|
| 1 | +# Advent of Code 2024 - Day 06 |
| 2 | + |
| 3 | +```elixir |
| 4 | +Mix.install([ |
| 5 | + {:req, "~> 0.5"}, |
| 6 | + {:benchee, "~> 1.3"} |
| 7 | +]) |
| 8 | +``` |
| 9 | + |
| 10 | +## Input |
| 11 | + |
| 12 | +```elixir |
| 13 | +opts = [headers: [{"cookie", "session=#{System.fetch_env!("LB_AOC_SESSION")}"}]] |
| 14 | +puzzle_input = Req.get!("https://adventofcode.com/2024/day/6/input", opts).body |
| 15 | +``` |
| 16 | + |
| 17 | +```elixir |
| 18 | +grid = |
| 19 | + String.split(puzzle_input, "\n", trim: true) |
| 20 | + |> Enum.map(fn row -> |
| 21 | + String.codepoints(row) |
| 22 | + |> Enum.with_index() |
| 23 | + |> Enum.map(fn {char, index} -> {index, char} end) |
| 24 | + |> Map.new() |
| 25 | + end) |
| 26 | + |> Enum.with_index() |
| 27 | + |> Enum.map(fn {char, index} -> {index, char} end) |
| 28 | + |> Map.new() |
| 29 | +``` |
| 30 | + |
| 31 | +## Grid |
| 32 | + |
| 33 | +```elixir |
| 34 | +defmodule Grid do |
| 35 | + def rotate_dir_90({0, -1}), do: {1, 0} |
| 36 | + def rotate_dir_90({1, 0}), do: {0, 1} |
| 37 | + def rotate_dir_90({0, 1}), do: {-1, 0} |
| 38 | + def rotate_dir_90({-1, 0}), do: {0, -1} |
| 39 | + |
| 40 | + def move_dir({col_modifier, row_modifier} = _dir, {col, row} = _pos) do |
| 41 | + {col + col_modifier, row + row_modifier} |
| 42 | + end |
| 43 | + |
| 44 | + def find(grid, char) do |
| 45 | + Enum.reduce_while(grid, nil, fn {row_i, row_value}, _acc -> |
| 46 | + case Enum.find(row_value, fn {_k, v} -> v == char end) do |
| 47 | + {col_i, _col_value} -> {:halt, {col_i, row_i}} |
| 48 | + nil -> {:cont, nil} |
| 49 | + end |
| 50 | + end) |
| 51 | + end |
| 52 | + |
| 53 | + def update(grid, {col, row} = _pos, value) do |
| 54 | + Map.update!(grid, row, fn r -> |
| 55 | + Map.put(r, col, value) |
| 56 | + end) |
| 57 | + end |
| 58 | + |
| 59 | + def at(grid, {col, row} = _pos) do |
| 60 | + get_in(grid, [row, col]) || "" |
| 61 | + end |
| 62 | +end |
| 63 | +``` |
| 64 | + |
| 65 | +## Puzzle 1 |
| 66 | + |
| 67 | +```elixir |
| 68 | +defmodule Puzzle1 do |
| 69 | + def count_visited(grid, current_pos, dir, visited) do |
| 70 | + facing_pos = Grid.move_dir(dir, current_pos) |
| 71 | + facing_obstacle = Grid.at(grid, facing_pos) |
| 72 | + |
| 73 | + case facing_obstacle do |
| 74 | + "" -> visited |> Enum.uniq() |> Enum.count() |
| 75 | + "." -> count_visited(grid, facing_pos, dir, [facing_pos | visited]) |
| 76 | + "#" -> count_visited(grid, current_pos, Grid.rotate_dir_90(dir), visited) |
| 77 | + end |
| 78 | + end |
| 79 | +end |
| 80 | + |
| 81 | +puzzle_1 = fn -> |
| 82 | + start_pos = Grid.find(grid, "^") |
| 83 | + grid = Grid.update(grid, start_pos, ".") |
| 84 | + |
| 85 | + Puzzle1.count_visited(grid, start_pos, {0, -1}, [start_pos]) |
| 86 | +end |
| 87 | + |
| 88 | +puzzle_1.() |
| 89 | +``` |
| 90 | + |
| 91 | +## Puzzle 2 |
| 92 | + |
| 93 | +```elixir |
| 94 | +defmodule Puzzle2 do |
| 95 | + def loop?(grid, current_pos, dir, visited \\ []) do |
| 96 | + facing_pos = Grid.move_dir(dir, current_pos) |
| 97 | + facing_obstacle = Grid.at(grid, facing_pos) |
| 98 | + |
| 99 | + cond do |
| 100 | + {current_pos, dir} in visited -> |
| 101 | + 1 |
| 102 | + |
| 103 | + facing_obstacle == "#" -> |
| 104 | + loop?(grid, current_pos, Grid.rotate_dir_90(dir), [{current_pos, dir} | visited]) |
| 105 | + |
| 106 | + facing_obstacle == "." -> |
| 107 | + loop?(grid, facing_pos, dir, [{current_pos, dir} | visited]) |
| 108 | + |
| 109 | + true -> |
| 110 | + 0 |
| 111 | + end |
| 112 | + end |
| 113 | +end |
| 114 | + |
| 115 | +puzzle_2 = fn -> |
| 116 | + start_pos = Grid.find(grid, "^") |
| 117 | + grid = Grid.update(grid, start_pos, ".") |
| 118 | + |
| 119 | + row_range = Map.keys(grid) |> length() |
| 120 | + col_range = Map.get(grid, 0) |> Map.keys() |> length() |
| 121 | + |
| 122 | + positions_to_check = |
| 123 | + for row <- 0..(row_range - 1), col <- 0..(col_range - 1) do |
| 124 | + {col, row} |
| 125 | + end |
| 126 | + |> Enum.filter(fn pos -> |
| 127 | + Grid.at(grid, pos) != "#" and pos != start_pos |
| 128 | + end) |
| 129 | + |
| 130 | + positions_to_check |
| 131 | + |> Task.async_stream(fn pos -> |
| 132 | + Grid.update(grid, pos, "#") |
| 133 | + |> Puzzle2.loop?(start_pos, {0, -1}) |
| 134 | + end) |
| 135 | + |> Enum.reduce(0, fn {:ok, result}, acc -> acc + result end) |
| 136 | +end |
| 137 | + |
| 138 | +puzzle_2.() |
| 139 | +``` |
| 140 | + |
| 141 | +<!-- livebook:{"offset":3190,"stamp":{"token":"XCP.ZIz-v6sUQcM1Lm_PpVOn6JmIUrVushSMizvoGpA0ASgugGV3iX9504iqHEPT6lx7CVjDB33joZgNM--Z_4f-u3PVhnailJyoaVn_WO5E9GRgdskIDzY","version":2}} --> |
0 commit comments