Day 3: Gear Ratios
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Part 1
https://adventofcode.com/2023/day/3
data =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
results =
data
|> Enum.with_index()
|> Enum.map(fn {line, y} ->
numbers_symbols =
(line <> ".")
|> String.codepoints()
|> Enum.with_index()
|> Enum.reduce(
%{numbers: [], symbols: []},
fn {c, x}, acc ->
case Integer.parse(c) do
{number, _} ->
# number
acc
|> Map.update(
:number_temp,
{_number_acc = number, _number_start_x = x},
fn {number_acc, number_start_x} ->
{number_acc * 10 + number, number_start_x}
end
)
:error ->
# symbol or . (number is end)
acc =
case acc[:number_temp] do
{number_acc, number_start_x} ->
acc
|> Map.update!(
:numbers,
&[{number_acc, {(number_start_x - 1)..x, (y - 1)..(y + 1)}} | &1]
)
|> Map.delete(:number_temp)
_ ->
acc
end
case c do
# .
"." ->
acc
# symbol
symbol_str ->
acc |> Map.update!(:symbols, &[{symbol_str, {x, y}} | &1])
end
end
end
)
{y, numbers_symbols}
end)
|> Map.new()
results
|> Enum.map(fn {_y, %{numbers: numbers}} ->
numbers
|> Enum.filter(fn {_number, {x_range, y_range}} ->
y_range
|> Enum.any?(fn y ->
(get_in(results, [y, :symbols]) || [])
|> Enum.any?(fn {_symbol_str, {x, _y}} -> x in x_range end)
end)
end)
|> Enum.map(fn {number, _position} -> number end)
end)
|> List.flatten()
|> Enum.sum()
Part 2
https://adventofcode.com/2023/day/3#part2
results
|> Enum.map(fn {_y, %{symbols: symbols}} ->
symbols
|> Enum.filter(fn {symbol_str, _position} -> symbol_str == "*" end)
|> Enum.map(fn {_symbol_str, {x, y}} ->
(y - 1)..(y + 1)
|> Enum.flat_map(fn y ->
(get_in(results, [y, :numbers]) || [])
|> Enum.filter(fn {_number, {x_range, _y_range}} ->
x in x_range
end)
|> Enum.map(fn {number, _position} -> number end)
end)
|> List.flatten()
|> case do
[part1, part2] -> part1 * part2
_ -> 0
end
end)
end)
|> List.flatten()
|> Enum.sum()