06_guard.py 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. #!/usr/bin/env python3
  2. import sys
  3. grid = [line.rstrip() for line in sys.stdin]
  4. h = len(grid)
  5. w = len(grid[0])
  6. guard = next((x, y) for y in range(h) for x in range(w) if grid[y][x] == '^')
  7. obstacles = {(x, y) for y in range(h) for x in range(w) if grid[y][x] == '#'}
  8. def walk(x, y, dx, dy, obstacles):
  9. while 0 <= x < w and 0 <= y < h:
  10. if (x, y) in obstacles:
  11. x -= dx
  12. y -= dy
  13. dx, dy = -dy, dx
  14. else:
  15. yield (x, y), (dx, dy)
  16. x += dx
  17. y += dy
  18. def loops(path, visited):
  19. vis = {(x, y, dx, dy) for (x, y), d in visited.items() for dx, dy in d}
  20. for pos in path:
  21. if pos in vis:
  22. return True
  23. vis.add(pos)
  24. return False
  25. def add_obstacle(gx, gy, obstacles):
  26. positions = set()
  27. visited = {}
  28. for xy, d in walk(gx, gy, 0, -1, obstacles):
  29. if xy not in visited and xy not in positions and \
  30. loops(walk(*xy, *d, obstacles | {xy}), visited):
  31. positions.add(xy)
  32. visited.setdefault(xy, set()).add(d)
  33. return positions
  34. print(len(set(xy for xy, _ in walk(*guard, 0, -1, obstacles))))
  35. print(len(add_obstacle(*guard, obstacles)))