15_repair.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/env python3
  2. import sys
  3. from time import sleep
  4. from intcode import read_program, run
  5. NORTH, SOUTH, EAST, WEST = range(1, 5)
  6. WALL, SPACE, OXYGEN, UNKOWN = range(4)
  7. DX = [0, 0, -1, 1]
  8. DY = [-1, 1, 0, 0]
  9. def draw(mapped, robot):
  10. if '-v' not in sys.argv:
  11. return
  12. def draw_pos(pos):
  13. return 'D' if pos == robot else '#.O '[mapped.get(pos, UNKOWN)]
  14. minx = min(x for x, y in mapped)
  15. maxx = max(x for x, y in mapped)
  16. miny = min(y for y, y in mapped)
  17. maxy = max(y for y, y in mapped)
  18. print('\033c', end='')
  19. for y in range(miny, maxy + 1):
  20. print(''.join(draw_pos((x, y)) for x in range(minx, maxx + 1)))
  21. sleep(.001)
  22. def map_area(program):
  23. reverse_dir = [SOUTH, NORTH, WEST, EAST]
  24. pos = 0, 0
  25. direction = NORTH
  26. control = run(program, lambda: direction, 0)
  27. mapped = {pos: SPACE}
  28. path = [(NORTH, pos)]
  29. oxygen_distance = None
  30. def pick_direction():
  31. x, y = pos
  32. for d in (NORTH, SOUTH, EAST, WEST):
  33. newpos = x + DX[d - 1], y + DY[d - 1]
  34. if newpos not in mapped:
  35. return False, (d, newpos)
  36. return True, path.pop()
  37. while len(path):
  38. backtrack, (direction, newpos) = pick_direction()
  39. status = next(control)
  40. mapped[newpos] = status
  41. if status != WALL:
  42. if not backtrack:
  43. path.append((reverse_dir[direction - 1], pos))
  44. pos = newpos
  45. if status == OXYGEN:
  46. oxygen_distance = len(path) - 1
  47. draw(mapped, pos)
  48. return oxygen_distance, mapped
  49. def spread_oxygen(mapped):
  50. frontier = set(pos for pos, status in mapped.items() if status == OXYGEN)
  51. minutes = -1
  52. while frontier:
  53. newfrontier = set()
  54. for x, y in frontier:
  55. mapped[(x, y)] = OXYGEN
  56. for d in range(4):
  57. nb = x + DX[d], y + DY[d]
  58. if mapped[nb] == SPACE:
  59. newfrontier.add(nb)
  60. minutes += 1
  61. frontier = newfrontier
  62. draw(mapped, None)
  63. return minutes
  64. program = read_program(sys.stdin)
  65. oxygen_distance, mapped = map_area(program)
  66. print(oxygen_distance)
  67. print(spread_oxygen(mapped))