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 sum of the version numbers is 1012
The output of the encoded input is 2223947372407 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/nine"
"unsupervised.ca/aoc2021/one" "unsupervised.ca/aoc2021/one"
"unsupervised.ca/aoc2021/seven" "unsupervised.ca/aoc2021/seven"
"unsupervised.ca/aoc2021/seventeen"
"unsupervised.ca/aoc2021/six" "unsupervised.ca/aoc2021/six"
"unsupervised.ca/aoc2021/sixteen" "unsupervised.ca/aoc2021/sixteen"
"unsupervised.ca/aoc2021/ten" "unsupervised.ca/aoc2021/ten"
@@ -70,6 +71,8 @@ func main() {
day = fifteen.Init("fifteen/input.txt") day = fifteen.Init("fifteen/input.txt")
case "sixteen": case "sixteen":
day = sixteen.Init("sixteen/input.txt") day = sixteen.Init("sixteen/input.txt")
case "seventeen":
day = seventeen.Init("seventeen/input.txt")
default: default:
fmt.Printf("%q does not have a solution.\n", flagParts[1]) fmt.Printf("%q does not have a solution.\n", flagParts[1])
help() 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