2021 Day 17 Part 1
This commit is contained in:
parent
372255b82b
commit
4f0bd01e62
1 changed files with 107 additions and 0 deletions
107
2021/day17/main.go
Normal file
107
2021/day17/main.go
Normal 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
|
||||
}
|
||||
Loading…
Reference in a new issue