advent-of-code/2021/python/day17.py

86 lines
1.9 KiB
Python
Raw Permalink Normal View History

2022-12-09 16:43:00 +00:00
import shared
from scanf import scanf
from dataclasses import dataclass
@dataclass
class Probe:
x: int
y: int
x_vel: int
y_vel: int
@dataclass
class Box:
x1: int
x2: int
y1: int
y2: int
@property
def max_x(self):
return max(self.x1, self.x2)
@property
def min_y(self):
return min(self.y1, self.y2)
class TrickShot:
def __init__(self, target, x_vel, y_vel):
self.target = target
self.probe = Probe(0, 0, x_vel, y_vel)
self.y_max = -9999
def step(self):
self.probe.x += self.probe.x_vel
self.probe.y += self.probe.y_vel
if self.probe.y > self.y_max:
self.y_max = self.probe.y
self.probe.x_vel += towards_zero(self.probe.x_vel)
self.probe.y_vel -= 1
def check_in_target(self):
return (
self.target.x1 <= self.probe.x <= self.target.x2
and self.target.y1 <= self.probe.y <= self.target.y2
)
def check_out_of_bounds(self):
return self.probe.y < self.target.min_y or self.probe.x > self.target.max_x
def towards_zero(value):
if value > 0:
return -1
elif value == 0:
return 0
else:
return 1
def main():
with open(shared.get_fname(17), "r") as f:
target = Box(*scanf("target area: x=%d..%d, y=%d..%d", f.read()))
hits = []
for x in range(target.max_x + 1):
for y in range(target.min_y, -target.min_y):
t = TrickShot(target, x, y)
while True:
t.step()
if t.check_in_target():
hits.append((x, y, t.y_max))
break
elif t.check_out_of_bounds():
break
hits = sorted(hits, key=lambda x: x[-1])
highest = hits[-1][-1]
print("highest", highest)
print("hits", len(hits))
if __name__ == "__main__":
main()