10_pipes.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #!/usr/bin/env python3
  2. import sys
  3. from itertools import chain, pairwise
  4. UP, DOWN, LEFT, RIGHT = DIRECTIONS = (0, -1), (0, 1), (-1, 0), (1, 0)
  5. CONNECTIONS = {
  6. '|': (UP, DOWN),
  7. '-': (LEFT, RIGHT),
  8. '7': (LEFT, DOWN),
  9. 'J': (LEFT, UP),
  10. 'L': (UP, RIGHT),
  11. 'F': (RIGHT, DOWN),
  12. '.': (),
  13. 'S': (),
  14. }
  15. def parse(inp):
  16. graph = {}
  17. for y, line in enumerate(inp):
  18. for x, char in enumerate(line.rstrip()):
  19. graph[(x, y)] = [(x + dx, y + dy) for dx, dy in CONNECTIONS[char]]
  20. if char == 'S':
  21. sx, sy = start = x, y
  22. graph[start] = [(sx + dx, sy + dy) for dx, dy in DIRECTIONS
  23. if start in graph.get((sx + dx, sy + dy), [])]
  24. return graph, start
  25. def loop(graph, start):
  26. path = [start]
  27. nex = graph[start][0]
  28. while nex != start:
  29. path.append(nex)
  30. nex = next(nb for nb in graph[nex] if nb != path[-2])
  31. return path
  32. def find_outside(border):
  33. maxx, maxy = map(max, zip(*border))
  34. outside = set(chain(((0, y) for y in range(maxy + 1)),
  35. ((maxx, y) for y in range(maxy + 1)),
  36. ((x, 0) for x in range(maxx + 1)),
  37. ((x, maxy) for x in range(maxx + 1)))) - border
  38. explore = list(outside)
  39. while explore:
  40. x, y = explore.pop()
  41. for dx, dy in DIRECTIONS:
  42. nx, ny = nb = x + dx, y + dy
  43. if 0 <= nx <= maxx and 0 <= ny <= maxy and \
  44. nb not in outside and nb not in border:
  45. outside.add(nb)
  46. explore.append(nb)
  47. return outside
  48. def area(border):
  49. scaled = {(2 * x, 2 * y) for x, y in border}
  50. scaled |= {(ax + bx, ay + by)
  51. for (ax, ay), (bx, by) in pairwise(chain(border, border[:1]))}
  52. outside = sum(x % 2 + y % 2 == 0 for x, y in find_outside(scaled))
  53. maxx, maxy = map(max, zip(*border))
  54. return (maxx + 1) * (maxy + 1) - outside - len(border)
  55. border = loop(*parse(sys.stdin))
  56. print(len(border) // 2)
  57. print(area(border))