Files
aocpy/2022/d17.py
2024-07-07 20:34:52 -04:00

120 lines
3.5 KiB
Python

from lib import *
EXAMPLE = """>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>"""
ROCKS = [
[(0, 0), (0, 1), (0, 2), (0, 3)],
[(0, 1), (-1, 0), (-1, 1), (-1, 2), (-2, 1)],
[(0, 0), (0, 1), (0, 2), (-1, 2), (-2, 2)],
[(0, 0), (-1, 0), (-2, 0), (-3, 0)],
[(0, 0), (0, 1), (-1, 0), (-1, 1)],
]
def printfall(coords):
row_coords = list(map(lambda c: c[0], coords))
col_coords = list(map(lambda c: c[1], coords))
min_row, max_row = min(row_coords), max(row_coords)
min_col, max_col = min(col_coords), max(col_coords)
s = ""
for r in range(min_row, max_row + 1):
for c in range(min_col, max_col + 1):
s += "."
s += "\n"
g = Input(s).grid2()
for c in coords:
c = (c[0] + -min_row, c[1])
g[tuple(c)] = "#"
g.print()
print()
def solve(input: Input, second=False):
BLOWS = list(input.text.strip())
width, blow_index = 7, 0
heighest = [0 for _ in range(width)]
rocks = set([(0, i) for i in range(width)])
if second:
target = 1000000000000
nhs = {}
else:
target = 2022
i = 0
while i < target:
rock = ROCKS[i % len(ROCKS)]
pos = (min(heighest) - 4, 2)
if second and i > 0 and all(abs(heighest[i] - heighest[i + 1]) <= 2 for i in range(len(heighest) - 1)):
# long winded code to find repeating sequence
nh = tuple([h - min(heighest) for h in heighest])
if nh in nhs:
nhs[nh].append((i, heighest[0]))
else:
nhs[nh] = [(i, heighest[0])]
xs = nhs[nh]
if len(xs) > 4 and all(xs[1][0] - xs[0][0] == xs[i + 1][0] - xs[i][0] for i in range(len(xs) - 1)):
# we found a repeating sequence and can skip forward
di = xs[-1][0] - xs[-2][0]
dh = xs[-1][1] - xs[-2][1]
repeat = (target - i) // di
i += repeat * di
heighest = [h + repeat * dh for h in heighest]
for c, r in enumerate(heighest):
rocks.add((r, c))
nhs = {}
continue
falling = True
while falling:
blow = BLOWS[blow_index % len(BLOWS)]
blow_index += 1
dc = None
if blow == ">":
dc = 1
elif blow == "<":
dc = -1
for (ro, co) in rock:
r = pos[0] + ro
c = pos[1] + co + dc
if c < 0 or c >= width or (r, c) in rocks:
break
else:
pos = (pos[0], pos[1] + dc)
for (ro, co) in rock:
r = pos[0] + ro + 1
c = pos[1] + co
if (r, c) in rocks:
falling = False
break
else:
pos = (pos[0] + 1, pos[1])
for (ro, co) in rock:
r = pos[0] + ro
c = pos[1] + co
rocks.add((r, c))
heighest[c] = min(heighest[c], r)
i += 1
return -min(heighest)
def main():
_, day = extract_year_and_date(__file__)
DAY_INPUT = f"i{day}.txt"
print("Example 1:", solve(Input(EXAMPLE)))
s1 = solve(Input(DAY_INPUT))
assert s1 == 3102
print("Solution 1:", s1)
print("Example 2:", solve(Input(EXAMPLE), True))
print("Solution 2:", solve(Input(DAY_INPUT), True))
assert solve(Input(DAY_INPUT), True) == 1539823008825
if __name__ == "__main__":
main()