🎄 Year 2024 🔔 Day 09
Mix.install([
{:arrays, "~> 2.1"}
])
Setup
elems =
File.read!("#{__DIR__}/../../../inputs/2024/day09.txt")
# "2333133121414131402"
|> String.trim()
|> String.graphemes()
|> Enum.with_index(fn e, i ->
asdf = if rem(i, 2) == 0, do: :file, else: :free
{String.to_integer(e), asdf}
end)
|> Enum.flat_map_reduce(0, fn
{count, :file}, acc ->
{List.duplicate(acc, count), acc + 1}
{count, :free}, acc ->
{List.duplicate(nil, count), acc}
end)
|> elem(0)
{file_indexes, max_i} =
File.read!("#{__DIR__}/../../../inputs/2024/day09.txt")
# "2333133121414131402"
|> String.trim()
|> String.graphemes()
|> Enum.with_index(fn e, i ->
file_n = if rem(i, 2) == 0, do: div(i, 2), else: nil
{String.to_integer(e), file_n}
end)
|> Enum.map_reduce(0, fn {count, file_n}, start_i ->
{{file_n, start_i, count}, start_i + count}
end)
|> then(fn {elems, max_i} -> {elems, max_i - 1} end)
Part 1
defmodule Helper do
def solve(elems) do
elems = Enum.with_index(elems)
reversed = elems |> Enum.reverse()
solve(elems, reversed, [])
end
defp solve([], _, result), do: Enum.reverse(result)
defp solve(alist = [{a, ai} | atail], blist = [{b, bi} | btail], result) do
cond do
b == nil -> solve(alist, btail, result)
bi < ai -> solve(atail, blist, [nil | result])
a != nil -> solve(atail, blist, [a | result])
a == nil -> solve(atail, btail, [b | result])
end
end
end
Helper.solve(elems)
|> Enum.filter(fn e -> e != nil end)
|> Enum.with_index(fn e, i -> e * i end)
|> Enum.sum()
Part 2
defmodule Helper2 do
def step(elem_array, nil_indexes, to_move)
def step(elem_array, [{_, _, _count = 0} | nil_indexes], to_move) do
step(elem_array, nil_indexes, to_move)
end
def step(elem_array, nil_indexes, {file_n, start_i, move_count}) do
case find_nil_index(nil_indexes, 0, move_count, start_i) do
{{nil, nil_start_i, nil_size}, nil_list_i} ->
new_nil_indexes =
List.update_at(
nil_indexes,
nil_list_i,
fn _ -> {nil, nil_start_i + move_count, nil_size - move_count} end
)
nil_end_i = nil_start_i + move_count - 1
nil_range = nil_start_i..nil_end_i
end_i = start_i + move_count - 1
move_range = start_i..end_i
new_elem_array =
elem_array
|> then(
&Enum.reduce(nil_range, &1, fn ui, elem_array ->
put_in(elem_array[ui], file_n)
end)
)
|> then(
&Enum.reduce(move_range, &1, fn ui, elem_array ->
put_in(elem_array[ui], nil)
end)
)
{new_elem_array, new_nil_indexes}
nil ->
{elem_array, nil_indexes}
end
end
defp find_nil_index(nil_indexes, i, min_size, max_i) do
[nil_index = {nil, start_i, size} | tail] = nil_indexes
cond do
start_i > max_i ->
nil
size >= min_size ->
{nil_index, i}
true ->
find_nil_index(tail, i + 1, min_size, max_i)
end
end
end
elem_array = elems |> Enum.into(Arrays.new())
nil_indexes = Enum.take_every(Enum.drop(file_indexes, 1), 2)
file_indexes = Enum.take_every(file_indexes, 2) |> Enum.reverse()
file_indexes
|> Enum.reduce(
{elem_array, nil_indexes},
fn file_loc, {elem_array, nil_indexes} ->
Helper2.step(elem_array, nil_indexes, file_loc)
end
)
|> elem(0)
|> Enum.with_index(fn file_n, i -> {file_n, i} end)
|> Enum.filter(fn {char, _} -> char != nil end)
|> Enum.map(fn {char, i} -> char * i end)
|> Enum.sum()