18_lumber.py 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #!/usr/bin/env python3
  2. import sys
  3. OPEN, TREE, LUMB = range(3)
  4. trans = {'.': OPEN, '|': TREE, '#': LUMB}
  5. initial = []
  6. for line in sys.stdin:
  7. w = len(line) + 1
  8. initial += [OPEN, *(trans[c] for c in line.rstrip()), OPEN]
  9. pad = [OPEN] * w
  10. initial = pad + initial + pad
  11. h = len(initial) // w
  12. def simulate(minutes):
  13. prev = list(initial)
  14. grid = [0] * len(prev)
  15. for minute in range(minutes):
  16. for y in range(1, h - 1):
  17. for x in range(1, w - 1):
  18. i = y * w + x
  19. cell = prev[i]
  20. counts = [0, 0, 0]
  21. for d in (-w - 1, -w, -w + 1, -1, 1, w - 1, w, w + 1):
  22. counts[prev[i + d]] += 1
  23. if cell == OPEN and counts[TREE] >= 3:
  24. cell = TREE
  25. elif cell == TREE and counts[LUMB] >= 3:
  26. cell = LUMB
  27. elif cell == LUMB and (not counts[LUMB] or not counts[TREE]):
  28. cell = OPEN
  29. grid[i] = cell
  30. counts = [0, 0, 0]
  31. for x in grid:
  32. counts[x] += 1
  33. yield counts[TREE] * counts[LUMB], hash(tuple(grid))
  34. prev, grid = grid, prev
  35. # part 1
  36. for val, ident in simulate(10):
  37. last = val
  38. print(last)
  39. # part 2
  40. def find_pattern(n):
  41. seen = []
  42. for minute, result in enumerate(simulate(n)):
  43. for i in range(len(seen) - 1, -1, -1):
  44. if seen[i] == result:
  45. return minute, tuple(zip(*seen[i:]))[0]
  46. seen.append(result)
  47. n = 1000000000
  48. minute, pattern = find_pattern(n)
  49. print(pattern[(n - minute - 1) % len(pattern)])