72 lines
1.8 KiB
Elixir
72 lines
1.8 KiB
Elixir
|
defmodule AOC.Day15 do
|
||
|
use AOC.Day, day: 15
|
||
|
|
||
|
def parse_input(lines) do
|
||
|
lines
|
||
|
|> hd()
|
||
|
|> String.split(",")
|
||
|
end
|
||
|
|
||
|
def part1(init_seq) do
|
||
|
init_seq
|
||
|
|> Enum.map(&String.to_charlist/1)
|
||
|
|> Enum.map(&hash/1)
|
||
|
|> Enum.sum()
|
||
|
end
|
||
|
|
||
|
def part2(init_seq) do
|
||
|
init_seq
|
||
|
|> Enum.map(fn step ->
|
||
|
if String.contains?(step, "=") do
|
||
|
[label, focal_length] = String.split(step, "=")
|
||
|
{:add, String.to_charlist(label), String.to_integer(focal_length)}
|
||
|
else
|
||
|
label = step |> String.trim_trailing("-") |> String.to_charlist()
|
||
|
{:remove, label}
|
||
|
end
|
||
|
end)
|
||
|
|> Enum.reduce(%{}, fn
|
||
|
{:remove, label}, acc ->
|
||
|
box_number = hash(label)
|
||
|
|
||
|
case Map.fetch(acc, box_number) do
|
||
|
{:ok, lenses} ->
|
||
|
%{acc | box_number => Enum.reject(lenses, &(elem(&1, 0) == label))}
|
||
|
|
||
|
:error ->
|
||
|
acc
|
||
|
end
|
||
|
|
||
|
{:add, label, focal_length}, acc ->
|
||
|
box_number = hash(label)
|
||
|
|
||
|
case Map.fetch(acc, box_number) do
|
||
|
{:ok, lenses} ->
|
||
|
case Enum.find_index(lenses, &(elem(&1, 0) == label)) do
|
||
|
nil ->
|
||
|
%{acc | box_number => [{label, focal_length} | lenses]}
|
||
|
|
||
|
index ->
|
||
|
%{acc | box_number => List.replace_at(lenses, index, {label, focal_length})}
|
||
|
end
|
||
|
|
||
|
:error ->
|
||
|
Map.put(acc, box_number, [{label, focal_length}])
|
||
|
end
|
||
|
end)
|
||
|
|> Enum.flat_map(fn {box_number, lenses} ->
|
||
|
lenses
|
||
|
|> Enum.reverse()
|
||
|
|> Enum.with_index()
|
||
|
|> Enum.map(fn {{_label, focal_length}, index} ->
|
||
|
(box_number + 1) * (index + 1) * focal_length
|
||
|
end)
|
||
|
end)
|
||
|
|> Enum.sum()
|
||
|
end
|
||
|
|
||
|
def hash(step), do: hash(step, 0)
|
||
|
def hash([], acc), do: acc
|
||
|
def hash([hd | tl], acc), do: hash(tl, rem(17 * (hd + acc), 256))
|
||
|
end
|