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, &Part1.sum_energized(grid, {0, &1}, {1, 0})),
async_max(0..len_r, &Part1.sum_energized(grid, {&1, 0}, {0, 1})),
async_max(0..len_c, &Part1.sum_energized(grid, {len_r, &1}, {-1, 0})),
async_max(0..len_r, &Part1.sum_energized(grid, {&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)