Skip to content

Commit 606f727

Browse files
committed
Day 14: Look for combination of max per-axis safety
1 parent ce65b37 commit 606f727

File tree

1 file changed

+29
-25
lines changed

1 file changed

+29
-25
lines changed

py/aoc2024/day14.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
from collections import namedtuple
66
from functools import partial
7-
from itertools import zip_longest
87
from math import lcm
9-
from typing import Generator
8+
from typing import Generator, Iterable
109

1110
SAMPLE_INPUT = """
1211
p=0,4 v=3,-3
@@ -26,23 +25,21 @@
2625
WIDTH, HEIGHT = 101, 103
2726

2827

29-
class _Robot(namedtuple("Robot", ("x0", "y0", "vx", "vy"))):
30-
def __getitem__(
31-
self, t: int, width: int = WIDTH, height: int = HEIGHT
32-
) -> tuple[int, int]:
33-
return (self.x0 + t * self.vx) % width, (self.y0 + t * self.vy) % height
28+
class _Robot(namedtuple("Robot1", ("p0", "v", "m"))):
29+
def __getitem__(self, t: int) -> int:
30+
return (self.p0 + t * self.v) % self.m
3431

3532

36-
def _parse(data: str) -> Generator[_Robot]:
33+
def _parse(
34+
data: str, width: int = WIDTH, height: int = HEIGHT
35+
) -> Generator[tuple[_Robot, _Robot]]:
3736
for line in filter(None, data.splitlines()):
3837
p, v = line.split(maxsplit=1)
3938
p = p[p.index("=") + 1 :]
4039
v = v[v.index("=") + 1 :]
41-
yield _Robot(
42-
int(p[: p.index(",")]),
43-
int(p[p.index(",") + 1 :]),
44-
int(v[: v.index(",")]),
45-
int(v[v.index(",") + 1 :]),
40+
yield (
41+
_Robot(int(p[: p.index(",")]), int(v[: v.index(",")]), width),
42+
_Robot(int(p[p.index(",") + 1 :]), int(v[v.index(",") + 1 :]), height),
4643
)
4744

4845

@@ -53,8 +50,8 @@ def part1(data: str, width: int = WIDTH, height: int = HEIGHT) -> int:
5350
"""
5451
midpoint_x, midpoint_y = width // 2, height // 2
5552
q1, q2, q3, q4 = 0, 0, 0, 0
56-
for robot in _parse(data):
57-
x, y = robot.__getitem__(100, width=width, height=height)
53+
for xrobot, yrobot in _parse(data, width, height):
54+
x, y = xrobot[100], yrobot[100]
5855
if x > midpoint_x and y > midpoint_y:
5956
q1 += 1
6057
if x < midpoint_x and y > midpoint_y:
@@ -66,19 +63,26 @@ def part1(data: str, width: int = WIDTH, height: int = HEIGHT) -> int:
6663
return q1 * q2 * q3 * q4
6764

6865

69-
def _part2_key(robots: tuple[_Robot], t: int) -> int:
70-
positions = sorted((robot[t] for robot in robots))
71-
line, max_line = 1, 0
72-
for (x, y), next in zip_longest(positions, positions[1:]):
73-
if (x, y + 1) == next:
74-
line += 1
75-
else:
76-
line, max_line = 1, max(line, max_line)
77-
return -max_line, t
66+
def _part2_key(robots: Iterable[_Robot], t: int) -> int:
67+
h1, h2 = 0, 0
68+
for robot in robots:
69+
p = robot[t]
70+
if p < robot.m // 2:
71+
h1 += 1
72+
elif p > robot.m // 2:
73+
h2 += 1
74+
return max(h1, h2)
7875

7976

8077
def part2(data: str) -> int:
81-
return min(range(lcm(WIDTH * HEIGHT)), key=partial(_part2_key, tuple(_parse(data))))
78+
xrobots = []
79+
yrobots = []
80+
for xrobot, yrobot in _parse(data):
81+
xrobots.append(xrobot)
82+
yrobots.append(yrobot)
83+
x = max(range(WIDTH), key=partial(_part2_key, xrobots))
84+
y = max(range(HEIGHT), key=partial(_part2_key, yrobots))
85+
return (x + (y - x) * pow(WIDTH, -1, HEIGHT) * WIDTH) % lcm(WIDTH, HEIGHT)
8286

8387

8488
parts = (part1, part2)

0 commit comments

Comments
 (0)