Advent of Code 2024/10
Mix.install([
{:kino, "~> 0.14.2"}
])
Section
input = Kino.Input.textarea("input")
defmodule AoC2024_10 do
def parse(input) do
Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(fn el -> String.split(el, "", trim: true) |> Enum.map(&(String.to_integer(&1))) end)
end
def get(matrix, row, col) do
matrix
|> Enum.at(row, [])
|> Enum.at(col)
end
def left(_row, 0, _matrix), do: nil
def left(row, col, matrix), do: { row, col - 1, get(matrix, row, col - 1) }
def top(0, _col, _matrix), do: nil
def top(row, col, matrix), do: { row - 1, col, get(matrix, row - 1, col) }
def right(_row, col, matrix) when length(hd(matrix)) == col, do: nil
def right(row, col, matrix), do: { row, col + 1, get(matrix, row, col + 1) }
def down(row, _col, matrix) when length(matrix) == row, do: nil
def down(row, col, matrix), do: { row + 1, col, get(matrix, row + 1, col) }
def starts(matrix) do
matrix
|> Enum.with_index
|> Enum.reduce([], fn {cols, row}, row_acc ->
row_acc ++ (cols
|> Enum.with_index
|> Enum.reduce([], fn {element, col}, acc ->
if element == 0, do: acc ++ [{row, col}], else: acc
end))
end)
end
def walk(matrix, {row, col}, height \\ 0, keep_path \\ false, path \\ []) do
cond do
height == 9 ->
if keep_path, do: [path ++ [{row, col}]], else: [{row, col}]
true ->
[
left(row, col, matrix),
right(row, col, matrix),
top(row, col, matrix),
down(row, col, matrix)
]
|> Enum.filter(fn path -> path != nil end)
|> Enum.filter(fn { _, _, value} -> value == height + 1 end)
|> Enum.flat_map(fn { new_row, new_col, value} -> walk(matrix, {new_row, new_col}, value, keep_path, path ++ [{row, col}]) end)
end
end
def part_1(input) do
matrix = input
|> parse
matrix
|> starts
|> Enum.map(fn start -> walk(matrix, start) |> Enum.uniq |> Enum.count end)
|> Enum.sum
end
def part_2(input) do
matrix = input
|> parse
matrix
|> starts
|> Enum.flat_map(fn start -> walk(matrix, start, 0, true) end)
|> Enum.uniq
|> Enum.count
end
end
AoC2024_10.part_1(input)
AoC2024_10.part_2(input)