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