solution.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/python3
  2. import sys
  3. right, down, left, up = (1, 0), (0, 1), (-1, 0), (0, -1)
  4. cube_regions = {
  5. 1: [(50, 0), (99, 49)],
  6. 2: [(100, 0), (149, 49)],
  7. 3: [(50, 50), (99, 99)],
  8. 4: [(0, 100), (49, 149)],
  9. 5: [(50, 100), (99, 149)],
  10. 6: [(0, 150), (49, 199)],
  11. }
  12. cube_transitions = {
  13. 1: {
  14. right: (2, right, lambda x, y: (100, y)),
  15. down: (3, down, lambda x, y: (x, 50)),
  16. left: (4, right, lambda x, y: (0, 149 - y)),
  17. up: (6, right, lambda x, y: (0, 100 + x))
  18. },
  19. 2: {
  20. right: (5, left, lambda x, y: (99, 149 - y)),
  21. down: (3, left, lambda x, y: (99, x - 50)),
  22. left: (1, left, lambda x, y: (99, y)),
  23. up: (6, up, lambda x, y: (x - 100, 199))
  24. },
  25. 3: {
  26. right: (2, up, lambda x, y: (50 + y, 49)),
  27. down: (5, down, lambda x, y: (x, 100)),
  28. left: (4, down, lambda x, y: (y - 50, 100)),
  29. up: (1, up, lambda x, y: (x, 49))
  30. },
  31. 4: {
  32. right: (5, right, lambda x, y: (50, y)),
  33. down: (6, down, lambda x, y: (x, 150)),
  34. left: (1, right, lambda x, y: (50, 149 - y)),
  35. up: (3, right, lambda x, y: (50, 50 + x))
  36. },
  37. 5: {
  38. right: (2, left, lambda x, y: (149, 149 - y)),
  39. down: (6, left, lambda x, y: (49, 100 + x)),
  40. left: (4, left, lambda x, y: (49, y)),
  41. up: (3, up, lambda x, y: (x, 99))
  42. },
  43. 6: {
  44. right: (5, up, lambda x, y: (y - 100, 149)),
  45. down: (2, down, lambda x, y: (100 + x, 0)),
  46. left: (1, down, lambda x, y: (y - 100, 0)),
  47. up: (4, up, lambda x, y: (x, 149))
  48. },
  49. }
  50. def wrap_around_position(grid, xlimits, ylimits, position, move):
  51. x, y = position
  52. mx, my = move
  53. #print(x, y, mx, my, '-> ', end='')
  54. # horizontal movement
  55. if mx > 0 and x + mx > xlimits[y][1]:
  56. x = xlimits[y][0]
  57. mx = 0
  58. elif mx < 0 and x + mx < xlimits[y][0]:
  59. x = xlimits[y][1]
  60. mx = 0
  61. # vertical movement
  62. if my > 0 and y + my > ylimits[x][1]:
  63. y = ylimits[x][0]
  64. my = 0
  65. elif my < 0 and y + my < ylimits[x][0]:
  66. y = ylimits[x][1]
  67. my = 0
  68. #print(x, y, mx, my)
  69. return (x + mx, y + my)
  70. def wrap_around_position_cubic(grid, position, xlimits, move, side):
  71. x, y = position
  72. mx, my = move
  73. nx, ny = x + mx, y + my
  74. ul, lr = cube_regions[side]
  75. sx1, sy1 = ul
  76. sx2, sy2 = lr
  77. #print(x, y, mx, my, sx1, sy1, sx2, sy2)
  78. # horizontal cubic wrap around
  79. if abs(mx) > 0 and (nx < sx1 or nx > sx2):
  80. print('case 1 true')
  81. side, new_move, new_xy = cube_transitions[side][move]
  82. print(x, y, new_xy(nx, ny))
  83. x, y = new_xy(nx, ny)
  84. mx, my = new_move
  85. elif abs(my) > 0 and (ny < sy1 or ny > sy2):
  86. print('case 2 true')
  87. side, new_move, new_xy = cube_transitions[side][move]
  88. print(x, y, new_xy(nx, ny))
  89. x, y = new_xy(nx, ny)
  90. mx, my = new_move
  91. else:
  92. x = nx
  93. y = ny
  94. return (x, y), (mx, my), side
  95. def collision(grid, xlimits, ylimits, position, cubic=False):
  96. x, y = position
  97. #print(x, y, xlimits[y][0], x - xlimits[y][0], len(grid), len(grid[y]))
  98. return grid[y][x - xlimits[y][0]] == '#'
  99. def solution(cubic=False):
  100. path = None
  101. grid = []
  102. xlimits = []
  103. ylimits = []
  104. print(cube_regions)
  105. print(cube_transitions)
  106. side = 1
  107. for line in sys.stdin:
  108. stripped = line.strip()
  109. if stripped == '':
  110. path = next(sys.stdin).strip()
  111. else:
  112. offset = line.rstrip().count(' ')
  113. grid.append(stripped)
  114. xlimits.append((offset, offset + len(stripped) - 1))
  115. maxxl = 0
  116. for xl in xlimits:
  117. maxxl = max(maxxl, xl[1])
  118. for x in range(maxxl + 1):
  119. offset = 0
  120. count = 0
  121. count_offset = True
  122. for xl in xlimits:
  123. if count_offset:
  124. if x >= xl[0] and x <= xl[1]:
  125. count_offset = False
  126. else:
  127. offset += 1
  128. else:
  129. if x >= xl[0] and x <= xl[1]:
  130. count += 1
  131. ylimits.append((offset, offset + count))
  132. print(grid)
  133. print(xlimits)
  134. print(ylimits)
  135. print(path)
  136. position = (xlimits[0][0], 0)
  137. facing = (1, 0)
  138. path = [[int(num) for num in p.split('L')] for p in path.split('R')]
  139. for i, rmove in enumerate(path):
  140. for j, lmove in enumerate(rmove):
  141. print(f'moving {lmove} (now at position {position} facing {facing} on side {side})')
  142. for k in range(int(lmove)):
  143. if not cubic:
  144. next_position = wrap_around_position(grid, xlimits, ylimits, position, facing)
  145. if not collision(grid, xlimits, ylimits, next_position):
  146. position = next_position
  147. else:
  148. break
  149. else:
  150. next_position, next_face, next_side = wrap_around_position_cubic(grid, position, xlimits, facing, side)
  151. if not collision(grid, xlimits, ylimits, next_position):
  152. position = next_position
  153. facing = next_face
  154. side = next_side
  155. else:
  156. break
  157. print(position)
  158. if j != len(rmove) - 1:
  159. facing = (facing[1], -facing[0])
  160. print(f'turning left (now facing {facing})')
  161. if i != len(path) - 1:
  162. facing = (-facing[1], facing[0])
  163. print(f'turning right (now facing {facing})')
  164. facing_number = {(1, 0): 0, (0, 1): 1, (-1, 0): 2, (0, -1): 3}
  165. password = 1000 * (position[1] + 1) + 4 * (position[0] + 1) + facing_number[facing]
  166. print(f'the password is {password}')
  167. if sys.argv[1] in '1':
  168. solution()
  169. else:
  170. solution(cubic=True)