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()