Solution for Day 17

This commit is contained in:
2021-12-18 19:50:49 +00:00
parent 5c0b7a3b09
commit 56b9b82e60
7 changed files with 280 additions and 0 deletions

View File

@@ -173,3 +173,12 @@ The solution for "sixteen" is:
The sum of the version numbers is 1012
The output of the encoded input is 2223947372407
```
### Day seventeen
```sh
$ ./aoc2021 --seventeen
The solution for "seventeen" is:
The max height is 35511
There are 3282 initial velocities that will hit the target
```

View File

@@ -14,6 +14,7 @@ import (
"unsupervised.ca/aoc2021/nine"
"unsupervised.ca/aoc2021/one"
"unsupervised.ca/aoc2021/seven"
"unsupervised.ca/aoc2021/seventeen"
"unsupervised.ca/aoc2021/six"
"unsupervised.ca/aoc2021/sixteen"
"unsupervised.ca/aoc2021/ten"
@@ -70,6 +71,8 @@ func main() {
day = fifteen.Init("fifteen/input.txt")
case "sixteen":
day = sixteen.Init("sixteen/input.txt")
case "seventeen":
day = seventeen.Init("seventeen/input.txt")
default:
fmt.Printf("%q does not have a solution.\n", flagParts[1])
help()

1
seventeen/input.txt Normal file
View File

@@ -0,0 +1 @@
target area: x=14..50, y=-267..-225

28
seventeen/main.go Normal file
View File

@@ -0,0 +1,28 @@
package seventeen
import "fmt"
type Seventeen struct {
probe probe
}
func Init(filepath string) *Seventeen {
seventeen := &Seventeen{
probe: probe{},
}
seventeen.probe.load(filepath)
return seventeen
}
func (d *Seventeen) Answer() string {
ivs := d.probe.intialVelocities()
return fmt.Sprintf("The max height is %d", maxHeight(d.probe, ivs))
}
func (d *Seventeen) FollowUp() string {
ivs := d.probe.intialVelocities()
return fmt.Sprintf("There are %d initial velocities that will hit the target", len(ivs))
}

180
seventeen/probe.go Normal file
View File

@@ -0,0 +1,180 @@
package seventeen
import (
"bufio"
"os"
"strconv"
"strings"
)
type target struct {
xMin int
xMax int
yMin int
yMax int
}
type velocity struct {
x int
y int
}
func (v *velocity) step() velocity {
newVelocity := velocity{}
if v.x > 0 {
newVelocity.x = v.x - 1
} else if v.x < 0 {
newVelocity.x = v.x + 1
}
newVelocity.y = v.y - 1
return newVelocity
}
type position struct {
x int
y int
}
func (p *position) step(v velocity) position {
newPosition := position{
x: p.x + v.x,
y: p.y + v.y,
}
return newPosition
}
type probe struct {
target target
v velocity
p position
}
func (p *probe) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
p.target = target{}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
parts := strings.Split(scanner.Text(), "=")
xParts := strings.Split(strings.Split(parts[1], ",")[0], "..")
xMin, err := strconv.Atoi(xParts[0])
if err != nil {
return err
}
xMax, err := strconv.Atoi(xParts[1])
if err != nil {
return err
}
yParts := strings.Split(parts[2], "..")
yMin, err := strconv.Atoi(yParts[0])
if err != nil {
return err
}
yMax, err := strconv.Atoi(yParts[1])
if err != nil {
return err
}
p.target.xMin = xMin
p.target.xMax = xMax
p.target.yMin = yMin
p.target.yMax = yMax
}
return nil
}
func (p *probe) intialVelocities() []velocity {
velocitiesToTarget := []velocity{}
for x := 0; x <= p.target.xMax; x++ {
if maxDist(x) <= p.target.xMin {
continue
}
for y := 0; y <= (p.target.yMin * -1); y++ {
// Test +y
v := velocity{x: x, y: y}
if p.hitTarget(v) {
velocitiesToTarget = append(velocitiesToTarget, v)
}
// Test -y
if y == 0 {
continue
}
v = velocity{x: x, y: (-1 * y)}
if p.hitTarget(v) {
velocitiesToTarget = append(velocitiesToTarget, v)
}
}
}
return velocitiesToTarget
}
func (p *probe) pathToTarget(iv velocity) []position {
v := velocity{x: iv.x, y: iv.y}
pos := position{x: 0, y: 0}
path := []position{pos}
for pos.x < p.target.xMax && pos.y > p.target.yMin {
pos = pos.step(v)
path = append(path, pos)
v = v.step()
// In x range!
if pos.x >= p.target.xMin && pos.x <= p.target.xMax {
// In y range!
if pos.y <= p.target.yMax && pos.y >= p.target.yMin {
break
}
}
}
return path
}
func (p *probe) hitTarget(iv velocity) bool {
v := velocity{x: iv.x, y: iv.y}
position := position{x: 0, y: 0}
for position.x < p.target.xMax && position.y > p.target.yMin {
position = position.step(v)
v = v.step()
// In x range!
if position.x >= p.target.xMin && position.x <= p.target.xMax {
// In y range!
if position.y <= p.target.yMax && position.y >= p.target.yMin {
return true
}
}
}
return false
}
func maxDist(x int) int {
return x * (x + 1) / 2
}
func maxHeight(p probe, ivs []velocity) int {
max := 0
for _, v := range ivs {
path := p.pathToTarget(v)
for _, pos := range path {
if pos.y > max {
max = pos.y
}
}
}
return max
}

58
seventeen/probe_test.go Normal file
View File

@@ -0,0 +1,58 @@
package seventeen
import (
"testing"
)
func Test_read(t *testing.T) {
p := probe{}
if err := p.load("test_input.txt"); err != nil {
t.Log(err)
t.FailNow()
}
if p.target.xMin != 20 {
t.Logf("Expected 20, found %d", p.target.xMin)
t.Fail()
}
if p.target.xMax != 30 {
t.Logf("Expected 30, found %d", p.target.xMax)
t.Fail()
}
if p.target.yMax != -5 {
t.Logf("Expected 20, found %d", p.target.xMin)
t.Fail()
}
if p.target.yMin != -10 {
t.Logf("Expected 30, found %d", p.target.xMax)
t.Fail()
}
}
func Test_initialVelocities(t *testing.T) {
p := probe{}
p.load("test_input.txt")
ivs := p.intialVelocities()
if len(ivs) != 112 {
t.Logf("Expected 112 initial velocities to target, found %d", len(ivs))
t.Fail()
}
}
func Test_maxHeight(t *testing.T) {
p := probe{}
p.load("test_input.txt")
ivs := p.intialVelocities()
max := maxHeight(p, ivs)
if max != 45 {
t.Logf("Expected max height of 45, found %d", max)
t.Fail()
}
}

1
seventeen/test_input.txt Normal file
View File

@@ -0,0 +1 @@
target area: x=20..30, y=-10..-5