11_paintrobot.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/env python3
  2. import sys
  3. from operator import add, mul, lt, eq
  4. def run(p, inputs, memsize=0):
  5. opmap = {1: add, 2: mul, 7: lt, 8: eq}
  6. p = p + [0] * memsize
  7. pc = relbase = 0
  8. while p[pc] != 99:
  9. modes, opcode = divmod(p[pc], 100)
  10. def decode_param(offset):
  11. return p[pc + offset], modes // (10 ** (offset - 1)) % 10
  12. def pload(offset):
  13. param, mode = decode_param(offset)
  14. return param if mode == 1 else p[param + relbase * mode // 2]
  15. def pstore(offset, value):
  16. param, mode = decode_param(offset)
  17. p[param + relbase * mode // 2] = value
  18. if opcode in (1, 2, 7, 8):
  19. pstore(3, opmap[opcode](pload(1), pload(2)))
  20. pc += 4
  21. elif opcode == 3:
  22. pstore(1, inputs.pop())
  23. pc += 2
  24. elif opcode == 4:
  25. inputs = yield pload(1) or inputs
  26. pc += 2
  27. elif opcode == 5:
  28. pc = pload(2) if pload(1) else pc + 3
  29. elif opcode == 6:
  30. pc = pload(2) if not pload(1) else pc + 3
  31. elif opcode == 9:
  32. relbase += pload(1)
  33. pc += 2
  34. def paint(firmware, startcolor):
  35. robot = run(firmware, [startcolor], 1000)
  36. painted = set()
  37. white = set()
  38. inputs = None
  39. x = y = 0
  40. dx, dy = 0, -1
  41. try:
  42. while True:
  43. make_white = robot.send(inputs)
  44. painted.add((x, y))
  45. (white.add if make_white else white.discard)((x, y))
  46. right = next(robot)
  47. if right:
  48. dx, dy = -dy, dx
  49. else:
  50. dx, dy = dy, -dx
  51. x += dx
  52. y += dy
  53. inputs = [int((x, y) in white)]
  54. except StopIteration:
  55. return white, len(painted)
  56. def draw(coords):
  57. xmin = min(x for x, y in coords)
  58. xmax = max(x for x, y in coords)
  59. ymin = min(y for x, y in coords)
  60. ymax = max(y for x, y in coords)
  61. grid = [[0] * (xmax - xmin + 1) for y in range(ymin, ymax + 1)]
  62. for x, y in coords:
  63. grid[y - ymin][x - xmin] = 1
  64. for row in grid:
  65. print(''.join(' @'[c] for c in row))
  66. firmware = list(map(int, sys.stdin.read().split(',')))
  67. white, npainted = paint(firmware, 0)
  68. print(npainted)
  69. white, npainted = paint(firmware, 1)
  70. draw(white)