adventofcode2022/day17/sol.py

123 lines
2.6 KiB
Python
Raw Normal View History

2022-12-17 05:45:25 +00:00
import itertools
rocks = [
0b00011110,
0b00001000_00011100_00001000,
0b00000100_00000100_00011100,
0b00010000_00010000_00010000_00010000,
0b00011000_00011000,
]
2022-12-17 06:43:00 +00:00
wall = 0b10000000_10000000_10000000_10000000_10000000
2022-12-17 06:42:43 +00:00
jets = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>"
jets = open("input").read().strip()
2022-12-17 05:45:25 +00:00
2022-12-17 06:43:00 +00:00
def ceil(n):
if n%8 != 0:
n += 8 - n%8
return n
2022-12-17 05:45:42 +00:00
def drop(a, r, jets):
2022-12-17 06:43:00 +00:00
h = ceil(a.bit_length()) + 8*3
2022-12-17 06:42:43 +00:00
numjets = 0
2022-12-17 05:45:42 +00:00
while True:
2022-12-17 21:17:35 +00:00
# push left or right
2022-12-17 05:45:42 +00:00
j = next(jets)
if j == '<':
x = (r<<1)
if x & wall == 0:
if x & (a>>h) == 0:
r = x
elif j == '>':
x = (r<<7)
if x & wall == 0:
x >>= 8
if x & (a>>h) == 0:
r = x
2022-12-17 06:42:43 +00:00
numjets += 1
2022-12-17 05:45:42 +00:00
2022-12-17 05:45:25 +00:00
# continue falling?
if r & (a>>(h-8)) == 0:
h -= 8
2022-12-17 05:45:42 +00:00
assert h > 0
2022-12-17 05:45:25 +00:00
else:
# stop
a |= (r<<h)
2022-12-17 06:42:43 +00:00
return a, numjets
2022-12-17 05:45:42 +00:00
2022-12-17 06:43:00 +00:00
def head(a):
2022-12-17 21:17:35 +00:00
# technically this isn't sufficient.
# you could imagine a stack of overhangs like
#
# |# #|
# |#### #|
# |# #|
# |# #|
# |# ###|
# |# #|
#
# that a rock might be able to navigate through indefinitely,
# but our stacks are much messier than that, so no need to worry.
#
# we could probably just take the top 10 or so rows and call it good.
2022-12-17 06:43:00 +00:00
h = ceil(a.bit_length())
2022-12-17 21:17:35 +00:00
x = 0x80
while h >= 8:
2022-12-17 06:43:00 +00:00
h -= 8
x |= (a>>h)&0xff
2022-12-17 21:17:35 +00:00
if x == 0xff:
return a>>h
return a
2022-12-17 06:43:00 +00:00
def height(a):
return ceil(a.bit_length())//8
2022-12-17 05:45:42 +00:00
2022-12-17 06:43:00 +00:00
# Part 1
a = 0b11111111
jeti = itertools.cycle(jets)
rocki = itertools.cycle(rocks)
for _ in range(2022):
r = next(rocki)
a, _ = drop(a,r,jeti)
print(height(a>>8))
# Part 2
2022-12-17 05:45:42 +00:00
a = 0b11111111
stopped = 0
2022-12-17 06:42:43 +00:00
jeti = itertools.cycle(jets)
2022-12-17 06:43:00 +00:00
rocki = itertools.cycle(rocks)
2022-12-17 06:42:43 +00:00
i = 0
j = 0
seen = dict()
2022-12-17 06:43:00 +00:00
2022-12-17 06:42:43 +00:00
try:
while True:
r = next(rocki)
a, n = drop(a,r,jeti)
stopped += 1
i = (i+1) % len(rocks)
j = (j+n) % len(jets)
if (i,j,head(a)) in seen:
break
seen[(i,j,head(a))] = (a,stopped)
#for i in reversed(range(0,a.bit_length(),8)):
# print("{:08b}".format((a>>i)&0xff))
#print()
2022-12-17 21:17:35 +00:00
except:
print(i, j, stopped)
raise
2022-12-17 06:43:00 +00:00
b, old = seen[(i,j,head(a))]
sdiff = stopped - old
hdiff = height(a) - height(b)
2022-12-17 06:42:43 +00:00
2022-12-17 21:17:35 +00:00
goal = 10**12
2022-12-17 06:43:00 +00:00
rounds, extra = divmod(goal - stopped, sdiff)
for _ in range(extra):
r = next(rocki)
a, n = drop(a,r,jeti)
print(rounds*hdiff + height(a)-1)