solution.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/python3
  2. import sys
  3. from dataclasses import dataclass
  4. @dataclass
  5. class Pos:
  6. y: int
  7. x: int
  8. names = ('up', 'right', 'down', 'left')
  9. emittance = {
  10. '.': ([], [], [], []),
  11. '|': ([], [0, 2], [], [0, 2]),
  12. '-': ([1, 3], [], [1, 3], []),
  13. '\\': ([3], [2], [1], [0]),
  14. '/': ([1], [0], [3], [2]),
  15. }
  16. def step(pos, direction):
  17. return (Pos(pos.y - 1, pos.x), Pos(pos.y, pos.x + 1), Pos(pos.y + 1, pos.x), Pos(pos.y, pos.x - 1))[direction]
  18. def bounded(pos, bounds):
  19. return pos.y >= 0 and pos.x >= 0 and pos.y < bounds.y and pos.x < bounds.x
  20. def collide(grid, energized, bounds, ray, direction):
  21. if (ray.y, ray.x, direction) in energized: return
  22. while bounded(ray, bounds):
  23. energized.add((ray.y, ray.x, direction))
  24. emit = emittance[grid[ray.y][ray.x]][direction]
  25. for r in emit:
  26. collide(grid, energized, bounds, step(ray, r), r)
  27. if len(emit) > 0:
  28. return
  29. ray = step(ray, direction)
  30. def energy_grid_str(energized, bounds):
  31. seen = set()
  32. for y, x, direction in energized:
  33. seen.add((y, x))
  34. return '\n'.join([''.join(row) for row in [['#' if (y, x) in seen else ' ' for x in range(bounds.x)] for y in range(bounds.y)]])
  35. def energy_grid_count(energized, bounds):
  36. seen = set()
  37. for y, x, direction in energized:
  38. seen.add((y, x))
  39. return len(seen)
  40. def part1():
  41. print('part 1')
  42. grid = [tuple(line) for line in map(str.strip, sys.stdin)]
  43. energized = set()
  44. bounds = Pos(len(grid), len(grid[0]))
  45. ray = Pos(0, 0)
  46. collide(grid, energized, bounds, ray, 1)
  47. print(energy_grid_str(energized, bounds))
  48. print(f'{energy_grid_count(energized, bounds)} tiles energized')
  49. def part2():
  50. print('part 2')
  51. grid = [tuple(line) for line in map(str.strip, sys.stdin)]
  52. bounds = Pos(len(grid), len(grid[0]))
  53. max_energized = 0
  54. for y in range(0, bounds.y):
  55. energized = set()
  56. collide(grid, energized, bounds, Pos(y, 0), 1)
  57. result = energy_grid_count(energized, bounds)
  58. max_energized = max(max_energized, result)
  59. print(f'{result} tiles energized')
  60. for x in range(0, bounds.x):
  61. energized = set()
  62. collide(grid, energized, bounds, Pos(0, x), 2)
  63. result = energy_grid_count(energized, bounds)
  64. max_energized = max(max_energized, result)
  65. print(f'{result} tiles energized')
  66. for y in range(0, bounds.y):
  67. energized = set()
  68. collide(grid, energized, bounds, Pos(y, bounds.x - 1), 3)
  69. result = energy_grid_count(energized, bounds)
  70. max_energized = max(max_energized, result)
  71. print(f'{result} tiles energized')
  72. for x in range(0, bounds.x):
  73. energized = set()
  74. collide(grid, energized, bounds, Pos(bounds.y - 1, x), 0)
  75. result = energy_grid_count(energized, bounds)
  76. max_energized = max(max_energized, result)
  77. print(f'{result} tiles energized')
  78. print(f'maximum is {max_energized}')
  79. if sys.argv[1] in '1':
  80. part1()
  81. else:
  82. part2()