Powered by AppSignal & Oban Pro

Day15

2021/day15.livemd

Day15

Untitled

Mix.install([:priority_queue])
grid =
  "input"
  |> IO.getn(1_000_000)
  |> String.trim()
  |> String.split(["\n", "\r\n"], trim: true)
  |> Enum.map(fn line ->
    line |> String.split("", trim: true) |> Enum.map(&String.to_integer/1)
  end)

grid =
  for {line, row} <- Enum.with_index(grid), {cell, col} <- Enum.with_index(line), into: %{} do
    {{row, col}, cell}
  end
defmodule D15 do
  @offsets [{-1, 0}, {1, 0}, {0, -1}, {0, 1}]

  def walk({row, col}, r, q, grid) do
    {q, grid} =
      @offsets
      |> Enum.map(fn {dr, dc} -> {row + dr, col + dc} end)
      |> Enum.map(&amp;{&amp;1, grid[&amp;1]})
      |> Enum.reject(&amp;is_nil(elem(&amp;1, 1)))
      |> Enum.reduce({q, grid}, fn {pos, risk}, {q, grid} ->
        {PriorityQueue.put(q, risk + r, pos), Map.delete(grid, pos)}
      end)

    {{risk, next}, q} = PriorityQueue.pop(q)
    {next, risk, q, grid}
  end

  def solve1(grid) do
    max = grid |> Map.keys() |> Enum.max()

    Stream.iterate(
      {{0, 0}, 0, PriorityQueue.new(), Map.delete(grid, {0, 0})},
      fn {next, risk, q, grid} ->
        D15.walk(next, risk, q, grid)
      end
    )
    |> Stream.drop_while(fn
      {^max, _, _, _} -> false
      _ -> true
    end)
    |> Enum.at(0)
    |> elem(1)
    |> IO.inspect()
  end

  def solve2(grid) do
    offset = grid |> Enum.filter(&amp;match?({{0, _}, _}, &amp;1)) |> length

    grid
    |> Enum.map(fn {{row, col}, v} ->
      0..4
      |> Enum.map(
        &amp;{{row + offset * &amp;1, col},
         if (v = v + &amp;1) > 9 do
           v - 9
         else
           v
         end}
      )
    end)
    |> List.flatten()
    |> Enum.map(fn {{row, col}, v} ->
      0..4
      |> Enum.map(
        &amp;{{row, col + offset * &amp;1},
         if (v = v + &amp;1) > 9 do
           v - 9
         else
           v
         end}
      )
    end)
    |> List.flatten()
    |> Map.new()
    |> solve1()
  end
end

P1

D15.solve1(grid)

P2

D15.solve2(grid)