/ Python / 2022 / 17.py
17.py
  1  from lib import *
  2  
  3  input = read_input(2022, 17).strip()
  4  
  5  SHAPES = [
  6      [[1, 1, 1, 1]],
  7      [[0, 1, 0], [1, 1, 1], [0, 1, 0]],
  8      [[0, 0, 1], [0, 0, 1], [1, 1, 1]],
  9      [[1], [1], [1], [1]],
 10      [[1, 1], [1, 1]],
 11  ]
 12  
 13  WIDTH = 7
 14  START_X = 2
 15  START_Y = 3
 16  
 17  
 18  def part1():
 19      grid = set()
 20      height = 0
 21      sh = 0
 22      st = 0
 23  
 24      def test(s, x, y):
 25          return (
 26              y - len(s) >= -1
 27              and x >= 0
 28              and x + len(s[0]) <= WIDTH
 29              and all((y - i, x + j) not in grid for i, r in enumerate(s) for j, k in enumerate(r) if k)
 30          )
 31  
 32      def add(s, x, y):
 33          grid.update((y - i, x + j) for i, r in enumerate(s) for j, k in enumerate(r) if k)
 34  
 35      for _ in range(2022):
 36          s = SHAPES[sh]
 37          sh = (sh + 1) % len(SHAPES)
 38          x = START_X
 39          y = height + START_Y + len(s) - 1
 40          while True:
 41              d = {"<": -1, ">": 1}[input[st]]
 42              st = (st + 1) % len(input)
 43              if test(s, x + d, y):
 44                  x += d
 45              if test(s, x, y - 1):
 46                  y -= 1
 47              else:
 48                  add(s, x, y)
 49                  height = max(y + 1, height)
 50                  break
 51      return height
 52  
 53  
 54  def part2():
 55      grid = set()
 56      height = 0
 57      st = 0
 58      sh = 0
 59  
 60      def test(s, x, y):
 61          return (
 62              y - len(s) >= -1
 63              and x >= 0
 64              and x + len(s[0]) <= WIDTH
 65              and all((y - i, x + j) not in grid for i, r in enumerate(s) for j, k in enumerate(r) if k)
 66          )
 67  
 68      def add(s, x, y):
 69          grid.update((y - i, x + j) for i, r in enumerate(s) for j, k in enumerate(r) if k)
 70  
 71      seen = []
 72      idx = {}
 73      heights = []
 74  
 75      round = 0
 76      while True:
 77          k = sh, st
 78          seen.append(k)
 79          heights.append(height)
 80          if k in idx:
 81              l = len(seen) - idx[k] - 1
 82              if seen[-l:] == seen[-2 * l : -l]:
 83                  break
 84          idx[k] = round
 85          s = SHAPES[sh]
 86          sh = (sh + 1) % len(SHAPES)
 87          x = START_X
 88          y = height + START_Y + len(s) - 1
 89          while True:
 90              d = {"<": -1, ">": 1}[input[st]]
 91              st = (st + 1) % len(input)
 92              if test(s, x + d, y):
 93                  x += d
 94              if test(s, x, y - 1):
 95                  y -= 1
 96              else:
 97                  add(s, x, y)
 98                  height = max(y + 1, height)
 99                  break
100          round += 1
101  
102      left = 1000000000000 - round
103      height += left // l * (heights[-1] - heights[-l - 1])
104      height += heights[-l - 1 + left % l] - heights[-l - 1]
105      return height
106  
107  
108  print(part1())
109  print(part2())