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

Advent of Code 2024 - Day 6

2024/day-06.livemd

Advent of Code 2024 - Day 6

Mix.install([
  {:kino_aoc, "~> 0.1.7"},
  {:libgraph, "~> 0.16.0"}
])

Preparation

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2024", "6", System.fetch_env!("LB_AOC_SESSION"))
input =
  puzzle_input
  |> String.split("\n")
  |> Enum.map(&String.to_charlist/1)
obstacles =
  for {row, i} <- Enum.with_index(input, 1),
      {?#, j} <- Enum.with_index(row, 1),
      into: MapSet.new(),
      do: {i, j}
guard_i = Enum.find_index(input, &amp; ?^ in &amp;1)
guard_j = input |> Enum.at(guard_i) |> Enum.find_index(&amp; &amp;1 == ?^)
guard = {guard_i + 1, guard_j + 1}
imax = length(input)
jmax = length(hd(input))

Part 1

watched =
  {guard, {-1, 0}}
  |> Stream.iterate(fn {{i, j}, {di, dj}} ->
    if {i + di, j + dj} in obstacles do
      {{i, j}, {dj, -di}}
    else
      {{i + di, j + dj}, {di, dj}}
    end
  end)
  |> Enum.reduce_while(MapSet.new(), fn {{i, j}, _dir} = state, seen ->
    cond do
      i == 0 -> {:halt, seen}
      i > imax -> {:halt, seen}
      j == 0 -> {:halt, seen}
      j > jmax -> {:halt, seen}
      state in seen -> {:halt, seen}
      true -> {:cont, MapSet.put(seen, state)}
    end
  end)
  |> Enum.map(&amp;elem(&amp;1, 0))
  |> Enum.uniq()
length(watched)

Part 2

watched
|> List.delete(guard)
|> Task.async_stream(fn new_obstacle ->
  obstacles = MapSet.put(obstacles, new_obstacle)
  
  {guard, {-1, 0}}
  |> Stream.iterate(fn {{i, j}, {di, dj}} ->
    if {i + di, j + dj} in obstacles do
      {{i, j}, {dj, -di}}
    else
      {{i + di, j + dj}, {di, dj}}
    end
  end)
  |> Enum.reduce_while(MapSet.new(), fn {{i, j}, _dir} = state, seen ->
    cond do
      i == 0 -> {:halt, 0}
      i > imax -> {:halt, 0}
      j == 0 -> {:halt, 0}
      j > jmax -> {:halt, 0}
      state in seen -> {:halt, 1}
      true -> {:cont, MapSet.put(seen, state)}
    end
  end)
end, ordered: false)
|> Stream.map(&amp;elem(&amp;1, 1))
|> Enum.sum()