Solution for Day 17
This commit is contained in:
@@ -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
|
||||||
|
```
|
||||||
|
3
main.go
3
main.go
@@ -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
1
seventeen/input.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
target area: x=14..50, y=-267..-225
|
28
seventeen/main.go
Normal file
28
seventeen/main.go
Normal 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
180
seventeen/probe.go
Normal 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
58
seventeen/probe_test.go
Normal 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
1
seventeen/test_input.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
target area: x=20..30, y=-10..-5
|
Reference in New Issue
Block a user