#rock grid class Chamber(): def __init__(self): self.grid = [['#', '#', '#', '#', '#', '#', '#']] def addEmpty(self, x): for i in range(x): self.grid.append(['.', '.', '.', '.', '.', '.', '.']) def removeEmpty(self): self.grid = [i for i in self.grid if i != ['.']*7] def topEdge(self): return len(self.grid) def addRock(self, rock): for add in rock: y, x = add self.grid[y][x] = '#' def testPrint(self): for gridLine in reversed(self.grid): line = '' for point in gridLine: line += point print(line) #Defining Rock Shapes def line(): relativeX = 0 relativeY = 0 settled = False chamber.addEmpty(3) NY = chamber.topEdge() NX = 2 chamber.addEmpty(1) while not settled: if jetstream[jetPosition] == '<': if NX != 0 and chamber.grid[NY][NX - 1] == '.': NX -= 1 relativeX -= 1 else: if NX != 3 and chamber.grid[NY][NX + 4] == '.': NX += 1 relativeX += 1 jet() if chamber.grid[NY - 1][NX:NX+4] == ['.', '.', '.', '.',]: NY -= 1 relativeY -= 1 else: settled = True rock = [(NY, NX), (NY, NX + 1), (NY, NX + 2), (NY, NX + 3)] chamber.addRock(rock) chamber.removeEmpty() rockSequence.append(((relativeY, relativeX), 1, chamber.topEdge() - 1)) def cross(): relativeX = 0 relativeY = 0 settled = False chamber.addEmpty(3) NY = chamber.topEdge() NX = 3 chamber.addEmpty(3) while not settled: if jetstream[jetPosition] == '<': if NX != 1 and all(x == '.' for x in (chamber.grid[NY][NX - 1], chamber.grid[NY + 1][NX - 2], chamber.grid[NY + 2][NX - 1])): NX -= 1 relativeX -= 1 else: if NX != 5 and all(x == '.' for x in (chamber.grid[NY][NX + 1], chamber.grid[NY + 1][NX + 2], chamber.grid[NY + 2][NX + 1])): NX += 1 relativeX += 1 jet() if all(x == '.' for x in (chamber.grid[NY - 1][NX], chamber.grid[NY][NX - 1], chamber.grid[NY][NX + 1])): NY -= 1 relativeY -= 1 else: settled = True rock = [(NY, NX), (NY + 1, NX - 1), (NY + 1, NX), (NY + 1, NX + 1), (NY + 2, NX)] chamber.addRock(rock) chamber.removeEmpty() rockSequence.append(((relativeY, relativeX), 2, chamber.topEdge() - 1)) def l(): relativeX = 0 relativeY = 0 settled = False chamber.addEmpty(3) NY = chamber.topEdge() NX = 2 chamber.addEmpty(3) while not settled: if jetstream[jetPosition] == '<': if NX != 0 and all(x == '.' for x in (chamber.grid[NY][NX - 1], chamber.grid[NY + 1][NX + 1], chamber.grid[NY + 2][NX + 1])): NX -= 1 relativeX -= 1 else: if NX != 4 and all(x == '.' for x in (chamber.grid[NY][NX + 3], chamber.grid[NY + 1][NX + 3], chamber.grid[NY + 2][NX + 3])): NX += 1 relativeX += 1 jet() if chamber.grid[NY - 1][NX:NX+3] == ['.', '.', '.']: NY -= 1 relativeY -= 1 else: settled = True rock = [(NY, NX), (NY, NX + 1), (NY, NX + 2), (NY + 1, NX + 2), (NY + 2, NX + 2)] chamber.addRock(rock) chamber.removeEmpty() rockSequence.append(((relativeY, relativeX), 3, chamber.topEdge() - 1)) def staff(): relativeX = 0 relativeY = 0 settled = False chamber.addEmpty(3) NY = chamber.topEdge() NX = 2 chamber.addEmpty(4) while not settled: if jetstream[jetPosition] == '<': if NX != 0 and all(x == '.' for x in (chamber.grid[NY][NX - 1], chamber.grid[NY + 1][NX - 1], chamber.grid[NY + 2][NX - 1], chamber.grid[NY + 3][NX - 1])): NX -= 1 relativeX -= 1 else: if NX != 6 and all(x == '.' for x in (chamber.grid[NY][NX + 1], chamber.grid[NY + 1][NX + 1], chamber.grid[NY + 2][NX + 1], chamber.grid[NY + 3][NX + 1])): NX += 1 relativeX += 1 jet() if chamber.grid[NY -1][NX] == '.': NY -= 1 relativeY -= 1 else: settled = True rock = [(NY, NX), (NY + 1, NX), (NY + 2, NX), (NY + 3, NX)] chamber.addRock(rock) chamber.removeEmpty() rockSequence.append(((relativeY, relativeX), 4, chamber.topEdge() - 1)) def square(): relativeX = 0 relativeY = 0 settled = False chamber.addEmpty(3) NY = chamber.topEdge() NX = 2 chamber.addEmpty(2) while not settled: if jetstream[jetPosition] == '<': if NX != 0 and (chamber.grid[NY][NX -1] == '.' and chamber.grid[NY + 1][NX -1] == '.'): NX -= 1 relativeX -= 1 else: if NX != 5 and (chamber.grid[NY][NX + 2] == '.' and chamber.grid[NY + 1][NX + 2] == '.'): NX += 1 relativeX += 1 jet() if chamber.grid[NY - 1][NX] == '.' and chamber.grid[NY - 1][NX + 1] == '.': NY -= 1 relativeY -= 1 else: settled = True rock = [(NY, NX), (NY + 1, NX), (NY + 1, NX + 1), (NY, NX + 1)] chamber.addRock(rock) chamber.removeEmpty() rockSequence.append(((relativeY, relativeX), 5, chamber.topEdge() - 1)) #miscelanious def jet(): global jetPosition jetPosition += 1 if jetPosition == jetWrap: jetPosition = 0 def _counter(): global counter counter += 1 if counter == end: return True return False def cycleFinder(): global cycleFound global counter global skippedValue if cycleFound: return position1, _, _ = rockSequence[-1] position2, _, _ = rockSequence[-2] position3, _, _ = rockSequence[-3] position4, _, _ = rockSequence[-4] position5, _, _ = rockSequence[-5] position6, _, _ = rockSequence[-6] position7, _, _ = rockSequence[-7] cycle[(position1, position2, position3, position4, position5, position6, position7)] = cycle.get((position1, position2, position3, position4, position5, position6, position7), 0) + len(rockSequence) if cycle[(position1, position2, position3, position4, position5, position6, position7)] > len(rockSequence): endOfCycle = rockSequence[-5] index = cycle[(position1, position2, position3, position4, position5, position6, position7)] - len(rockSequence) startOfCycle = rockSequence[index - 5] cycleFound = True cycleLength = len(rockSequence) - index cycleValue = endOfCycle[2] - startOfCycle[2] print('found cycle') n, rest = divmod(end - len(rockSequence), cycleLength) counter = len(rockSequence) + cycleLength * n skippedValue = cycleValue * n #Building Input, defioning variables with open('input17.txt','r') as f: inp = f.read().splitlines(keepends=False) jetstream = list(inp[0]) jetWrap = len(jetstream) chamber = Chamber() jetPosition = 0 counter = 0 end = 1000000000000 rockSequence = [] cycle = {} cycleFound = False # Main function while True: line() if _counter(): break cross() if _counter(): break l() if _counter(): break staff() if _counter(): break square() if _counter(): break if counter == 5: pass else: cycleFinder() if counter % 10000 == 0: print(counter, 'of', end) print(chamber.topEdge() - 1 + skippedValue)