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

Advent of code day day 06

2024/livebooks/day-06.livemd

Advent of code day day 06

Mix.install([
  {:kino, "~> 0.5.0"}
])

Setup input

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")

parse

parsed =
  example
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&(String.split(&1, "", trim: true) |> List.to_tuple()))
  |> List.to_tuple()

lines = tuple_size(parsed) - 1
cols = tuple_size(elem(parsed, 0)) - 1

grid =
  for l <- 0..lines, c <- 0..cols, into: %{} do
    {{l, c}, elem(elem(parsed, l), c)}
  end
defmodule Solver do
  @dirs %{
    "^" => {{-1, 0}, "^", ">"},
    ">" => {{0, 1}, ">", "v"},
    "v" => {{1, 0}, "v", "<"},
    "<" => {{0, -1}, "<", "^"}
  }

  def part02(grid, current_pos) do
    {_, visited} = traverse(grid, current_pos, MapSet.new())

    visited = Enum.reject(visited, fn k -> k == current_pos end)

    Enum.reduce(visited, 0, fn {obstacle_y, obstacle_x}, acc ->
      modified_matrix = Map.put(grid, {obstacle_y, obstacle_x}, "O")

      case traverse(modified_matrix, current_pos, MapSet.new()) do
        :loop -> acc + 1
        _ -> acc
      end
    end)
  end

  def traverse(matrix, {y, x}, visited) do
    {{d_y, d_x}, current, rotated} = @dirs[matrix[{y, x}]]

    if MapSet.member?(visited, {{y, x}, current}) do
      :loop
    else
      updated_visited = MapSet.put(visited, {{y, x}, current})

      case matrix[{y + d_y, x + d_x}] do
        char when char == "#" or char == "O" ->
          updated_matrix = Map.put(matrix, {y, x}, rotated)
          traverse(updated_matrix, {y, x}, updated_visited)

        char when char == "." or char == "X" ->
          updated_matrix =
            matrix |> Map.put({y, x}, "X") |> Map.put({y + d_y, x + d_x}, current)

          traverse(updated_matrix, {y + d_y, x + d_x}, updated_visited)

        nil ->
          {matrix, MapSet.new(updated_visited, &amp;elem(&amp;1, 0))}
      end
    end
  end
end
## helper module
defmodule GridPrinter do
  def print_grid(map) do
    # Extract all the coordinates
    coordinates = Map.keys(map)

    # Determine the grid bounds
    {min_x, max_x} = Enum.min_max(Enum.map(coordinates, fn {x, _y} -> x end))
    {min_y, max_y} = Enum.min_max(Enum.map(coordinates, fn {_x, y} -> y end))

    # Build the grid as a string
    for y <- min_y..max_y do
      for x <- min_x..max_x do
        Map.get(map, {x, y}, " ") # Get the value or a default space
      end
      |> Enum.join("")           # Join the row into a string
    end
    |> Enum.join("\n")           # Join all rows with a newline
    |> IO.puts                   # Print the grid
  end
end

Part01

{pos, _v} = Enum.find(grid, fn {_k, v} -> v == "^" end)

{matrix, updated} = Solver.traverse(grid, pos, MapSet.new())
updated |> Enum.count


GridPrinter.print_grid(matrix)

Part 02

 Solver.part02(grid, pos)