18_lumber.py 1.6 KB

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