Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code 2023 - Day 16

2023/16.livemd

Advent of Code 2023 - Day 16

Mix.install([
  {:kino, "~> 0.11.0"},
  {:kino_aoc, github: "ljgago/kino_aoc"}
])

Input

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "16", System.fetch_env!("LB_AOC_SESSION"))
input =
  for {row, r} <- puzzle_input |> String.split("\n", trim: true) |> Stream.with_index(),
      {col, c} <- row |> String.graphemes() |> Stream.with_index(),
      into: %{},
      do: {{r, c}, col}

Part 1

defmodule Part1 do
  def sum_energized(grid, start, dir) do
    do_energize([], grid, start, dir)
    |> Stream.uniq_by(fn {pos, _} -> pos end)
    |> Enum.count()
  end

  defp do_energize(acc, grid, {r, c} = pos, {dr, dc} = dir) do
    energized = {pos, dir}

    if Enum.member?(acc, energized) do
      acc
    else
      case grid[pos] do
        nil ->
          acc

        "/" ->
          [energized | acc]
          |> do_energize(grid, {r + dc * -1, c + dr * -1}, {dc * -1, dr * -1})

        "\\" ->
          [energized | acc]
          |> do_energize(grid, {r + dc, c + dr}, {dc, dr})

        "|" when dr == 0 ->
          [energized | acc]
          |> do_energize(grid, {r - 1, c}, {-1, 0})
          |> do_energize(grid, {r + 1, c}, {+1, 0})

        "-" when dc == 0 ->
          [energized | acc]
          |> do_energize(grid, {r, c - 1}, {0, -1})
          |> do_energize(grid, {r, c + 1}, {0, +1})

        _ ->
          [energized | acc]
          |> do_energize(grid, {r + dr, c + dc}, dir)
      end
    end
  end
end

Part1.sum_energized(input, {0, 0}, {0, 1})

Part 2

defmodule Part2 do
  def max_max(grid) do
    {len_r, len_c} = grid |> Map.keys() |> Enum.max()

    [
      async_max(0..len_c, &amp;Part1.sum_energized(grid, {0, &amp;1}, {1, 0})),
      async_max(0..len_r, &amp;Part1.sum_energized(grid, {&amp;1, 0}, {0, 1})),
      async_max(0..len_c, &amp;Part1.sum_energized(grid, {len_r, &amp;1}, {-1, 0})),
      async_max(0..len_r, &amp;Part1.sum_energized(grid, {&amp;1, len_c}, {0, -1}))
    ]
    |> Task.await_many(20_000)
    |> Enum.max()
  end

  defp async_max(range, callback) do
    Task.async(fn ->
      range
      |> Task.async_stream(callback, ordered: false)
      |> Enum.max()
      |> elem(1)
    end)
  end
end

Part2.max_max(input)

Run in Livebook