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, &elem(&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)