Advent 2024 - Day 9
Mix.install([
{:kino, "~> 0.14.2"}
])
Setup
input = Kino.Input.textarea("Please paste your input file")
input = input
|> Kino.Input.read()
|> String.graphemes()
|> Enum.map(&(String.to_integer/1))
Part 1
disk_in_chunks = input
|> Enum.with_index()
|> Enum.map(fn {num, index} ->
value = if rem(index, 2) == 0 do
div((index), 2)
else
nil
end
List.duplicate(value, num)
end)
|> List.flatten()
defmodule GParted do
def defrag(disk) do
defrag(disk, 0, length(disk) - 1)
end
def defrag(disk, current_index, max_index) when current_index > max_index do
disk
end
def defrag(disk, current_index, max_index) do
if Enum.at(disk, current_index) == nil do
{val, disk} = List.pop_at(disk, max_index)
if val == nil do
defrag(disk, current_index, max_index - 1)
else
disk = disk |> List.replace_at(current_index, val)
defrag(disk, current_index + 1, max_index - 1)
end
else
defrag(disk, current_index + 1, max_index)
end
end
end
GParted.defrag(disk_in_chunks)
|> Enum.with_index()
|> Enum.map(fn {pos, index} -> pos * index end)
|> Enum.sum()
Part 2
disk_in_files = input
|> Enum.with_index()
|> Enum.map(fn {num, index} ->
id = div((index), 2)
if rem(index, 2) == 0 do
{:file, id, num}
else
{:empty, num}
end
end)
|> List.flatten()
defmodule FDisk do
def display(disk) do
for entity <- disk do
case entity do
{:file, id, size} -> String.duplicate(Integer.to_string(id), size)
{:empty, size} -> String.duplicate(".", size)
end
end
|> Enum.join()
end
def manipulate(disk) do
to_move = disk
|> Enum.reverse()
|> Enum.filter(fn
{:file, _, _} -> true
_ -> false
end)
manipulate(disk, to_move)
end
def manipulate(disk, to_move) when length(to_move) == 0 do
disk
end
def manipulate(disk, [{:file, id, size} = file | rest]) do
# IO.puts(disk |> display())
{_, file_index} = disk
|> Enum.with_index()
|> Enum.find(nil, fn
{{:file, file_id, _size}, _} when file_id == id -> true
_ -> false
end)
empty_space = disk
|> Enum.with_index()
|> Enum.find(nil, fn
{{:empty, gap}, index} when gap >= size and index < file_index -> true
_ -> false
end)
if empty_space == nil do
manipulate(disk, rest)
else
{{:empty, gap}, gap_index} = empty_space
disk = disk
|> List.replace_at(file_index, {:empty, size})
|> List.replace_at(gap_index, file)
disk = if gap == size do
disk
else
disk |> List.insert_at(gap_index + 1, {:empty, gap - size})
end
manipulate(disk, rest)
end
end
end
FDisk.manipulate(disk_in_files)
|> Enum.reduce({0, 0}, fn
{:file, id, size}, {total, index} ->
total = total + (for x <- index..(index + (size - 1)) do
IO.inspect({id, x})
id * x
end
|> Enum.sum())
{total, index + size}
{:empty, size}, {total, index} ->
{total, index + size}
end)
|> elem(0)