Day 16: The Floor Will Be Lava

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • @hades@lemm.ee
    link
    fedilink
    4
    edit-2
    3 months ago

    Python

    53.059 line-seconds (ranks third hardest after days 8 and 12 so far).

    from .solver import Solver
    
    
    def _trace_beam(data, initial_beam_head):
      wx = len(data[0])
      wy = len(data)
      beam_heads = [initial_beam_head]
      seen_beam_heads = set()
      while beam_heads:
        next_beam_heads = []
        for x, y, dx, dy in beam_heads:
          seen_beam_heads.add((x, y, dx, dy))
          nx, ny = (x + dx), (y + dy)
          if nx < 0 or nx >= wx or ny < 0 or ny >= wy:
            continue
          obj = data[ny][nx]
          if obj == '|' and dx != 0:
            next_beam_heads.append((nx, ny, 0, 1))
            next_beam_heads.append((nx, ny, 0, -1))
          elif obj == '-' and dy != 0:
            next_beam_heads.append((nx, ny, 1, 0))
            next_beam_heads.append((nx, ny, -1, 0))
          elif obj == '/':
            next_beam_heads.append((nx, ny, -dy, -dx))
          elif obj == '\\':
            next_beam_heads.append((nx, ny, dy, dx))
          else:
            next_beam_heads.append((nx, ny, dx, dy))
        beam_heads = [x for x in next_beam_heads if x not in seen_beam_heads]
      energized = {(x, y) for x, y, _, _ in seen_beam_heads}
      return len(energized) - 1
    
    
    class Day16(Solver):
    
      def __init__(self):
        super().__init__(16)
    
      def presolve(self, input: str):
        data = input.splitlines()
        self.possible_energized_cells = (
          [_trace_beam(data, (-1, y, 1, 0)) for y in range(len(data))] +
          [_trace_beam(data, (x, -1, 0, 1)) for x in range(len(data[0]))] +
          [_trace_beam(data, (len(data[0]), y, -1, 0)) for y in range(len(data))] +
          [_trace_beam(data, (x, len(data), 0, -1)) for x in range(len(data[0]))])
    
    
      def solve_first_star(self) -> int:
        return self.possible_energized_cells[0]
    
      def solve_second_star(self) -> int:
        return max(self.possible_energized_cells)