17_tetris.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. #!/usr/bin/env python3
  2. import sys
  3. from itertools import cycle
  4. from operator import sub
  5. ROCKS = (
  6. (1, ((0, 0), (1, 0), (2, 0), (3, 0))),
  7. (3, ((1, 0), (0, 1), (1, 1), (2, 1), (1, 2))),
  8. (3, ((0, 0), (1, 0), (2, 0), (2, 1), (2, 2))),
  9. (4, ((0, 0), (0, 1), (0, 2), (0, 3))),
  10. (2, ((0, 0), (1, 0), (0, 1), (1, 1))),
  11. )
  12. def drop_rocks(shifts, n):
  13. shifts = cycle(enumerate(shifts))
  14. tower = set()
  15. def drop(rock, height):
  16. x = 2
  17. y = height + 3
  18. for shift_id, shift in shifts:
  19. if all(0 <= x + dx + shift < 7
  20. and (x + dx + shift, y + dy) not in tower
  21. for dx, dy in rock):
  22. x += shift
  23. if any((x + dx, y + dy - 1) in tower or y == 0
  24. for dx, dy in rock):
  25. return x, y, shift_id
  26. y -= 1
  27. def dropn(n, height):
  28. cache = {}
  29. loop_size = 0
  30. while not loop_size:
  31. key = ()
  32. for rock_height, rock in ROCKS:
  33. x, y, shift_id = drop(rock, height)
  34. tower.update({(x + dx, y + dy) for dx, dy in rock})
  35. height = max(height, y + rock_height)
  36. n -= 1
  37. if n == 0:
  38. return height
  39. key += shift_id,
  40. value = n, height
  41. loop_size, diff = map(sub, cache.setdefault(key, value), value)
  42. skip, n = divmod(n, loop_size)
  43. return dropn(n, height) - skip * diff
  44. return dropn(n, 0)
  45. shifts = ['< >'.index(x) - 1 for x in sys.stdin.readline().rstrip()]
  46. print(drop_rocks(shifts, 2022))
  47. print(drop_rocks(shifts, 1000000000000))