solution.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #!/usr/bin/python3
  2. import sys
  3. import re
  4. # part 1
  5. # (x, y)
  6. rocks = [(3, 0), (2, 2), (2, 2), (0, 3), (1, 1)]
  7. solid = [
  8. [(0, 0), (1, 0), (2, 0), (3, 0)],
  9. [(1, 0), (0, 1), (1, 1), (2, 1), (1, 2)],
  10. [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)],
  11. [(0, 0), (0, 1), (0, 2), (0, 3)],
  12. [(0, 0), (0, 1), (1, 0), (1, 1)],
  13. ]
  14. def jet_movement_possible(grid, rock, lx, ly, rx, ry):
  15. return not collision(grid, rock, lx, ly) and lx >= 0 and rx < 7
  16. def collision(grid, rock, lx, ly):
  17. for sx, sy in solid[rock]:
  18. if (sx + lx, sy + ly) in grid:
  19. return True
  20. return False
  21. def print_grid(grid):
  22. for y in range(max([y for x, y in grid]) + 1)[::-1]:
  23. for x in range(7):
  24. print('#' if (x, y) in grid else '.', end='')
  25. print()
  26. def part1(rock_count, jet=None):
  27. if not jet:
  28. jet = next(sys.stdin).strip()
  29. jetlen = len(jet)
  30. jetx = [-1 if c == '<' else 1 for c in jet]
  31. jetindex = 0
  32. #print(jet, jetx, jetlen)
  33. rock = 0
  34. rocklen = len(rocks)
  35. grid = set([(x, 0) for x in range(0, 7)])
  36. hx, hy = 2, 4
  37. for fallen in range(rock_count):
  38. width, height = rocks[rock]
  39. lx, ly = hx, hy
  40. rx, ry = lx + width, ly + height
  41. #print('rock', rock, 'spawned', lx, ly, rx, ry)
  42. while not collision(grid, rock, lx, ly):
  43. # get moved by jet
  44. jx = jetx[jetindex]
  45. if jet_movement_possible(grid, rock, lx + jx, ly, rx + jx, ry):
  46. lx += jx
  47. rx += jx
  48. jj = jetindex
  49. jetindex = (jetindex + 1) % jetlen
  50. # fall down
  51. ly -= 1
  52. ry -= 1
  53. #print(f'{lx} {ly} {rx} {ry} {jx}@{jj}')
  54. # collision happened, handle collision
  55. #print('collision', lx, ly, rx, ry)
  56. for sx, sy in solid[rock]:
  57. # add but with one height higher to avoid collision
  58. grid.add((sx + lx, sy + ly + 1))
  59. hy = max(ry + 1, hy - 4) + 4
  60. #hy = ry + 5
  61. rock = (rock + 1) % rocklen
  62. print(sorted(grid))
  63. print_grid(grid)
  64. print(f'tower height is {hy - 4}')
  65. return hy - 4
  66. def find_cycle(diffs):
  67. for i, a in enumerate(diffs):
  68. for j, b in enumerate(diffs[i + 1:]):
  69. if a == b:
  70. return len(diffs) - 1 - i
  71. return -1
  72. def part2(rock_count):
  73. jet = next(sys.stdin).strip()
  74. jetlen = len(jet)
  75. jetx = [-1 if c == '<' else 1 for c in jet]
  76. jetindex = 0
  77. print(jet, jetx, jetlen)
  78. rock = 0
  79. rocklen = len(rocks)
  80. grid = set([(x, 0) for x in range(0, 7)])
  81. hx, hy = 2, 4
  82. # part 2 stuff
  83. cheight = 0
  84. dheight = 0
  85. ddheight = 0
  86. lheight = 0
  87. llheight = 0
  88. lrockc = 0
  89. drockc = 0
  90. hdiffs = []
  91. rdiffs = []
  92. hdiffs_left = None
  93. rdiffs_left = None
  94. hdiffs_right = None
  95. rdiffs_right = None
  96. # game loop
  97. for fallen in range(rock_count):
  98. width, height = rocks[rock]
  99. lx, ly = hx, hy
  100. rx, ry = lx + width, ly + height
  101. #print('rock', rock, 'spawned', lx, ly, rx, ry)
  102. while not collision(grid, rock, lx, ly):
  103. # get moved by jet
  104. jx = jetx[jetindex]
  105. if jet_movement_possible(grid, rock, lx + jx, ly, rx + jx, ry):
  106. lx += jx
  107. rx += jx
  108. jj = jetindex
  109. jetindex = (jetindex + 1) % jetlen
  110. # fall down
  111. ly -= 1
  112. ry -= 1
  113. #print(f'{lx} {ly} {rx} {ry} {jx}@{jj}')
  114. # collision happened, handle collision
  115. #print('collision', lx, ly, rx, ry)
  116. for sx, sy in solid[rock]:
  117. # add but with one height higher to avoid collision
  118. grid.add((sx + lx, sy + ly + 1))
  119. hy = max(ry + 1, hy - 4) + 4
  120. #hy = ry + 5
  121. rock = (rock + 1) % rocklen
  122. if rock == 0:
  123. row_full = True
  124. for x in range(2, 7 - 2):
  125. if (x, hy - 4) not in grid:
  126. row_full = False
  127. break
  128. if row_full:
  129. print(cheight, lheight, llheight, dheight, ddheight, fallen, lrockc, drockc)
  130. cheight = hy - 4
  131. dheight = cheight - lheight
  132. ddheight = lheight - llheight
  133. drockc = fallen - lrockc
  134. hdiffs.append(dheight)
  135. rdiffs.append(drockc)
  136. cycle = find_cycle(hdiffs)
  137. print('cycle is', cycle, hdiffs)
  138. if cycle >= 0:
  139. print('found cycle')
  140. hdiffs_left = hdiffs[:-cycle - 1]
  141. rdiffs_left = rdiffs[:-cycle - 1]
  142. hdiffs_right = hdiffs[-cycle:]
  143. rdiffs_right = rdiffs[-cycle:]
  144. break
  145. lheight = cheight
  146. llheight = lheight
  147. lrockc = fallen
  148. print(hdiffs_left, hdiffs_right)
  149. print(rdiffs_left, rdiffs_right)
  150. #print(sorted(grid))
  151. calculated_height = sum(hdiffs_left)
  152. remaining_rocks = rock_count - sum(rdiffs_left)
  153. hdr = sum(hdiffs_right)
  154. rdr = sum(rdiffs_right)
  155. calculated_height += remaining_rocks // rdr * hdr
  156. remaining_rocks %= remaining_rocks // rdr
  157. index = 0
  158. while remaining_rocks > rdiffs_right[index]:
  159. calculated_height += hdiffs_right[index]
  160. remaining_rocks -= hdiffs_right[index]
  161. index = (index + 1) % cycle
  162. print(remaining_rocks)
  163. calculated_height += part1(remaining_rocks, jet) - 1
  164. remaining_rocks -= remaining_rocks
  165. print(calculated_height, remaining_rocks)
  166. # this is too complicated
  167. if sys.argv[1] in '1':
  168. part1(2022)
  169. else:
  170. part2(1000000000000)