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