86 lines
1.9 KiB
Python
86 lines
1.9 KiB
Python
|
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()
|