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

Day 06

2024/day06.livemd

Day 06

Mix.install([:kino_aoc, :arrays])

Section

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2024", "6", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
{:ok,
 "...#..................#...................#......................#..............................#.............................#...\n....#.......................#........#.#..............##...........#.....#..........#..........................#..................\n.............#........................................................................#.........#.#..#..#..........#..............\n..........#.......#..........#..................#........##...................#..............#....................................\n....................#..........................................................#..#.....................................#.........\n....#............................#..............................................#.....................#..........##....#..........\n.......#.............#......................................................................#.............#.........#.............\n....###......................#....#...........#.....#................................#..........................#.................\n..........#..#...........#..#........................................................#.....#...........#................#.........\n..#....#......#....#....#...................................................................#.....................................\n....................#............#............................................#......#....#...............................#.......\n..........#.......#.........#.......#.............................................................................................\n.......#...#.......................................#...................#..........................................................\n.......#........#............................#.....#.......#..............................................#..................#...#\n.....................#.................................#................#...#...............#.....#.#..........................#..\n.....#..........................................#......................#.............##..............................#........#...\n.....#......#.........................#..........................#..........................................................#..#..\n.#......#.............#......#.................................................#.....#...................##......#................\n.............................................................................##...................................................\n........................................#.......................................#........#.............................#.#.......#\n...........#.....................................#.............................#......#......#..#....................#..#.........\n.............................................#.......................#..................##....#.....#.............................\n........................#..............................................................#..........................................\n#..............#.........................#........#...#...............#..............#..................#....................##...\n...#...#.............................#.......#................................................#........................#....#.....\n.....#.........................#..#.......................#..........#.....................#..................#.#.....#...........\n..................#........#..#.......#...................................................................................#....#..\n..#...#...............................................#.#..#........................................................#....#......#.\n...............#...............#..........................#............................#..........#.............#.................\n............#.....#........#.........................................................#........#........#.....#........#......#....\n............................#.........#....#........#.....#...#.............#.................................#...................\n........#..................#....#.." <> ...}
map =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.with_index()
  |> Enum.flat_map(fn {row, y} ->
    row
    |> String.to_charlist()
    |> Enum.with_index()
    |> Enum.map(fn {v, x} -> {{y, x}, v} end)
  end)
  |> Map.new()
%{
  {18, 103} => 46,
  {76, 13} => 46,
  {61, 121} => 46,
  {37, 47} => 46,
  {65, 63} => 46,
  {77, 129} => 46,
  {120, 47} => 46,
  {38, 2} => 46,
  {1, 26} => 46,
  {116, 69} => 46,
  {124, 56} => 46,
  {83, 76} => 46,
  {117, 125} => 46,
  {32, 15} => 46,
  {103, 106} => 46,
  {30, 113} => 46,
  {123, 104} => 46,
  {124, 60} => 46,
  {89, 14} => 46,
  {35, 30} => 46,
  {37, 53} => 46,
  {4, 5} => 46,
  {8, 50} => 46,
  {78, 98} => 46,
  {101, 62} => 46,
  {95, 56} => 46,
  {74, 12} => 46,
  {102, 74} => 46,
  {11, 39} => 46,
  {65, 43} => 46,
  {22, 38} => 46,
  {14, 86} => 46,
  {49, 117} => 46,
  {20, 41} => 46,
  {29, 25} => 46,
  {86, 10} => 46,
  {83, 36} => 46,
  {29, 26} => 46,
  {47, 27} => 46,
  {4, 81} => 46,
  {31, 42} => 46,
  {9, 34} => 46,
  {13, 124} => 46,
  {90, 0} => 46,
  {14, 122} => 46,
  {120, 42} => 46,
  {121, 77} => 46,
  {103, 39} => 46,
  {102, ...} => 46,
  {...} => 46,
  ...
}
{start_pos, _} = start = Enum.find(map, fn {_pos, v} -> v in ~c'^>v<' end)

map = Map.replace(map, start_pos, ?.)

start
{{93, 71}, 94}
defmodule Guard do
  def walk(map, start),
    do: walk(map, start, MapSet.new())

  defp walk(map, {pos, dir} = curr, visited) do
    if curr in visited do
      :loop
    else
      visited = MapSet.put(visited, curr)

      case Map.fetch(map, next(pos, dir)) do
        {:ok, ?#} ->
          walk(map, {pos, turn(dir)}, visited)

        {:ok, ?.} ->
          walk(map, {next(pos, dir), dir}, visited)

        :error ->
          MapSet.new(visited, fn {pos, _} -> pos end)
      end
    end
  end

  defp next({y, x}, ?^), do: {y - 1, x}
  defp next({y, x}, ?>), do: {y, x + 1}
  defp next({y, x}, ?v), do: {y + 1, x}
  defp next({y, x}, ?<), do: {y, x - 1}

  defp turn(?^), do: ?>
  defp turn(?>), do: ?v
  defp turn(?v), do: ?<
  defp turn(?<), do: ?^
end
{:module, Guard, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:turn, 1}}

Part 1

orig_path = Guard.walk(map, start)
  
MapSet.size(orig_path)
4433

Part 2

orig_path
|> MapSet.delete(start_pos)
|> Task.async_stream(fn point ->
  map
  |> Map.put(point, ?#)
  |> Guard.walk(start)
  |> Kernel.==(:loop)
  end, ordered: false)
|> Enum.count(&amp; &amp;1)
4432