Skip to content

Commit

Permalink
2024 day 9 - simplify with a map approach
Browse files Browse the repository at this point in the history
It works better on the evil inputs listed here - https://www.reddit.com/r/adventofcode/comments/1haauty/2024_day_9_part_2_bonus_test_case_that_might_make/

The first input goes from 3.2 to 1.1 seconds

The second *really* evil input goes from 32 to 20 seconds

The slowness is probably from sorting the gap lists, now
  • Loading branch information
sevenseacat committed Dec 11, 2024
1 parent 9b9c1f6 commit d39987c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 34 deletions.
4 changes: 2 additions & 2 deletions lib/y2024/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ day 07, part 1 102.28 9.78 ms ±2.20% 9.77 ms 10.
day 07, part 2 14.56 68.66 ms ±0.66% 68.75 ms 69.78 ms
day 08, part 1 1060.88 0.94 ms ±6.65% 0.92 ms 1.08 ms
day 08, part 2 827.26 1.21 ms ±7.61% 1.18 ms 1.39 ms
day 09, part 1 8.72 114.69 ms ±1.28% 114.98 ms 117.37 ms
day 09, part 2 7.25 137.96 ms ±0.69% 137.79 ms 141.44 ms
day 09, part 1 9.33 107.22 ms ±0.49% 107.06 ms 108.74 ms
day 09, part 2 7.68 130.17 ms ±0.93% 130.17 ms 132.76 ms
day 10, part 1 3.87 258.13 ms ±0.90% 258.51 ms 263.14 ms
day 10, part 2 4.19 238.57 ms ±0.55% 238.51 ms 241.13 ms
day 11, part 1 179.79 5.56 ms ±6.00% 5.62 ms 6.21 ms
Expand Down
88 changes: 56 additions & 32 deletions lib/y2024/day09.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,13 @@ defmodule Y2024.Day09 do

{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)
gap_map =
gaps
|> Enum.reverse()
|> Enum.group_by(& &1.size)

defrag(to_move, gap_map, disk)
|> Map.values()
|> Enum.sort_by(& &1.start_at)
|> Enum.reduce(0, fn file, acc ->
Expand All @@ -73,43 +77,63 @@ defmodule Y2024.Day09 do
end)
end

defp defrag([], _, _, disk), do: disk
defp defrag([], _, disk), do: disk

defp defrag([_head | tail], [], gaps, disk), do: defrag(tail, Enum.reverse(gaps), [], disk)
defp defrag([head | tail], gap_map, disk) do
if gap = find_valid_gap(gap_map, head) do
# IO.puts("moving #{head.file_id} to #{gap.start_at}")
leftover_gap_size = gap.size - head.size

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)

Enum.reverse(start_gaps) ++ [new_gap | tail_gaps]
else
Enum.reverse(start_gaps) ++ tail_gaps
end

disk =
Map.update!(disk, head.file_id, fn head ->
%{head | start_at: head_gap.start_at}
gap_map =
if leftover_gap_size > 0 do
# IO.puts("adding new gap of size #{leftover_gap_size} at #{gap.start_at + head.size}")

new_gap =
gap
|> Map.put(:size, leftover_gap_size)
|> Map.put(:start_at, gap.start_at + head.size)

gap_map
|> Map.update(new_gap.size, [new_gap], fn list ->
[new_gap | list]
|> Enum.sort_by(& &1.start_at)
end)
else
gap_map
end
|> Map.update!(gap.size, fn list -> tl(list) end)

defrag(tail, gaps, [], disk)
else
defrag([head | tail], tail_gaps, [head_gap | start_gaps], disk)
end
disk =
Map.update!(disk, head.file_id, fn head ->
%{head | start_at: gap.start_at}
end)

defrag(tail, gap_map, disk)
else
# IO.puts("can't move #{head.file_id}")
defrag(tail, gap_map, disk)
end
end

defp find_valid_gap(gap_map, %{size: min_size, start_at: max_start_at}) do
# IO.puts("looking for gap of size #{min_size}")

Enum.reduce(gap_map, nil, fn
{_gap_size, []}, acc ->
acc

{gap_size, gaps}, acc ->
gap = hd(gaps)

if gap_size >= min_size && gap.start_at < max_start_at &&
(!acc || acc.start_at > gap.start_at) do
gap
else
acc
end
end)
end

def parse_input(input) do
input
|> String.trim()
Expand Down

0 comments on commit d39987c

Please sign in to comment.