Watch
1
0
Fork
You've already forked advent-of-code
0

2021 Day 17 Part 1

This commit is contained in:
Jeremy Kaplan 2021-12-16 22:22:48 -08:00
commit 4f0bd01e62

107
2021/day17/main.go Normal file
View file

@ -0,0 +1,107 @@
package main
import (
"fmt"
"regexp"
"github.com/jdkaplan/advent-of-code/aoc"
)
func main() {
text := aoc.Input().ReadFile("day17.txt")
re := regexp.MustCompile(`^target area: x=(-?\d+)\.\.(-?\d+), y=(-?\d+)..(-?\d+)$`)
m := re.FindStringSubmatch(text)
var (
x1 = aoc.MustInt(m[1])
x2 = aoc.MustInt(m[2])
y1 = aoc.MustInt(m[3])
y2 = aoc.MustInt(m[4])
)
r := Region{x1, x2, y1, y2}
fmt.Println(part1(r))
}
type Region struct{ x1, x2, y1, y2 int }
type Position struct{ x, y int }
func (p Position) Move(v Velocity) Position {
return Position{p.x + v.x, p.y + v.y}
}
func (p Position) InRegion(r Region) bool {
return r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2
}
func (p Position) Overshot(r Region) bool {
return p.x > r.x2 || p.y < r.y1
}
type Velocity struct{ x, y int }
func (v Velocity) Drag() Velocity {
x := v.x
if x < 0 {
x++
} else if x > 0 {
x--
}
return Velocity{x, v.y - 1}
}
func part1(r Region) int {
vxmin, vxmax := vxrange(r.x1, r.x2)
vymin, vymax := vyrange(r.y1, r.y2)
hmax := 0
for vx := vxmin; vx <= vxmax; vx++ {
for vy := vymin; vy <= vymax; vy++ {
hit := simulate(Velocity{vx, vy}, r)
if !hit {
continue
}
if h := tri(vy); h > hmax {
hmax = h
}
}
}
return hmax
}
func simulate(v Velocity, r Region) bool {
p := Position{0, 0}
for !p.InRegion(r) && !p.Overshot(r) {
p = p.Move(v)
v = v.Drag()
}
return p.InRegion(r)
}
func vxrange(x1, x2 int) (int, int) {
// Zoom directly to the far edge.
vxmax := x2
// Find the first value that crosses the near edge.
vxmin := 0
for vx := 0; vx < vxmax; vx++ {
xterm := tri(vx)
if xterm >= x1 {
vxmin = vx
break
}
}
return vxmin, vxmax
}
func vyrange(y1, y2 int) (int, int) {
if y1 >= 0 {
panic("This only works for negative-y regions!")
}
// Zoom directly to the close edge.
vymin := -y2
// Zoom directly to the far edge.
vymax := -y1
return vymin, vymax
}
func tri(x int) int {
return (x * (x + 1)) / 2
}