Skip to content

Commit

Permalink
2024 day 9, part 2 rewrite
Browse files Browse the repository at this point in the history
We'll pretend I didn't totally misunderstand what I was supposed to do.
I guess I was lucky it still worked for both the sample and real input?

What I thought:

* From left to right, find the right-most file to fit in every gap

What it actually is:

* From right to left, find the left-most gap for the file to move to
  • Loading branch information
sevenseacat committed Dec 9, 2024
1 parent 8e747d1 commit 5138af9
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 42 deletions.
4 changes: 2 additions & 2 deletions lib/y2024/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ day 07, part 1 103.05 9.70 ms ±2.34% 9.69 ms 10.
day 07, part 2 14.76 67.73 ms ±1.35% 67.51 ms 71.95 ms
day 08, part 1 1.07 K 0.93 ms ±6.91% 0.90 ms 1.07 ms
day 08, part 2 0.83 K 1.20 ms ±7.78% 1.17 ms 1.38 ms
day 09, part 1 9.27 107.87 ms ±0.84% 107.61 ms 111.83 ms
day 09, part 2 0.23 4.43 s ±0.12% 4.43 s 4.43 s
day 09, part 1 9.26 108.03 ms ±0.66% 107.88 ms 111.50 ms
day 09, part 2 7.28 137.37 ms ±0.68% 137.22 ms 139.75 ms
```
89 changes: 49 additions & 40 deletions lib/y2024/day09.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,57 +47,66 @@ defmodule Y2024.Day09 do
2858
"""
def part2(input) do
input
|> Enum.reduce({0, true, []}, fn num, {file_id, fill?, list} ->
type = if fill?, do: :fill, else: :gap
next_file_id = if fill?, do: file_id + 1, else: file_id
{next_file_id, !fill?, [%{type: type, file_id: file_id, num: num} | list]}
end)
|> elem(2)
|> Enum.reverse()
|> defrag([])
|> Enum.reduce({0, 0}, fn record, {index, acc} ->
if record.type == :gap do
{index + record.num, acc}
else
acc =
Enum.reduce(0..(record.num - 1), acc, fn sub_index, acc ->
acc + (index + sub_index) * record.file_id
end)
list =
input
|> Enum.reduce({0, 0, true, []}, fn size, {file_id, start_at, fill?, list} ->
type = if fill?, do: :fill, else: :gap

{index + record.num, acc}
end
{file_id + 0.5, start_at + size, !fill?,
[%{type: type, start_at: start_at, file_id: file_id, size: size} | list]}
end)
|> elem(3)
|> Enum.reject(&(&1.size == 0))
|> Enum.map(fn row -> Map.update!(row, :file_id, &trunc/1) end)

{to_move, gaps} = Enum.split_with(list, &(&1.type == :fill))
disk = Map.new(list, &{&1.file_id, &1})
gaps = Enum.reverse(gaps)

defrag(to_move, gaps, [], disk)
|> Map.values()
|> Enum.sort_by(& &1.start_at)
|> Enum.reduce(0, fn file, acc ->
Enum.reduce(file.start_at..(file.start_at + file.size - 1), acc, fn index, acc ->
acc + index * file.file_id
end)
end)
|> elem(1)
end

defp defrag([], list), do: Enum.reverse(list)
defp defrag([], _, _, disk), do: disk

defp defrag([%{type: :fill} = head | tail], list) do
defrag(tail, [head | list])
end
defp defrag([_head | tail], [], gaps, disk), do: defrag(tail, Enum.reverse(gaps), [], disk)

defp defrag([%{type: :gap, num: num} = head | tail], list) do
filler =
Enum.find(Enum.reverse(tail), fn %{num: check_num, type: type} ->
type == :fill && check_num <= num
end)
defp defrag([head | tail], [head_gap | tail_gaps], start_gaps, disk) do
if head.start_at < head_gap.start_at do
# IO.puts("can't move #{head.file_id}")
defrag(tail, Enum.reverse(start_gaps) ++ [head_gap | tail_gaps], [], disk)
else
if head_gap.size >= head.size do
# IO.puts("gonna move #{head.file_id} to #{head_gap.start_at}")
leftover_gap_size = head_gap.size - head.size

gaps =
if leftover_gap_size > 0 do
new_gap =
head_gap
|> Map.put(:size, leftover_gap_size)
|> Map.put(:start_at, head_gap.start_at + head.size)

if filler do
list = [filler | list]
Enum.reverse(start_gaps) ++ [new_gap | tail_gaps]
else
Enum.reverse(start_gaps) ++ tail_gaps
end

tail =
Enum.map(tail, fn record ->
if record == filler, do: %{type: :gap, num: filler.num}, else: record
end)
disk =
Map.update!(disk, head.file_id, fn head ->
%{head | start_at: head_gap.start_at}
end)

if num - filler.num == 0 do
defrag(tail, list)
defrag(tail, gaps, [], disk)
else
defrag([%{type: :gap, num: num - filler.num} | tail], list)
defrag([head | tail], tail_gaps, [head_gap | start_gaps], disk)
end
else
defrag(tail, [head | list])
end
end

Expand Down

0 comments on commit 5138af9

Please sign in to comment.