import itertools rocks = [ 0b00011110, 0b00001000_00011100_00001000, 0b00000100_00000100_00011100, 0b00010000_00010000_00010000_00010000, 0b00011000_00011000, ] wall = 0b10000000_10000000_10000000_10000000_10000000 jets = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>" jets = open("input").read().strip() def ceil(n): if n%8 != 0: n += 8 - n%8 return n def drop(a, r, jets): # start falling h = ceil(a.bit_length()) + 8*3 numjets = 0 while True: 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 numjets += 1 # continue falling? if r & (a>>(h-8)) == 0: h -= 8 assert h > 0 else: # stop a |= (r<= 8 and x < 0x7f: h -= 8 x |= (a>>h)&0xff if x >= 0x7f: return a>>h return 0 def height(a): return ceil(a.bit_length())//8 # 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 a = 0b11111111 stopped = 0 jeti = itertools.cycle(jets) rocki = itertools.cycle(rocks) i = 0 j = 0 seen = dict() 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() finally: pass #print(i, j, stopped) b, old = seen[(i,j,head(a))] sdiff = stopped - old hdiff = height(a) - height(b) goal = 1000000000000 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)