rugyoga

rugyoga

First 10 of 30 Posts! Switch mode

Aetherus

Aetherus

Stuck in Part 2. My algo works for the sample input, but not the real input. Any help?

https://github.com/Aetherus/advent-of-code/blob/0bc39c89cdd8d327fac4aab63b74b828ea2b15f4/2024/day-09.livemd

bjorng

bjorng

Erlang Core Team

It took me a long time to find an off-by-one error in part 2. The combined runtime for both parts is 0.4 seconds.

https://github.com/bjorng/advent-of-code/blob/main/2024/day09/lib/day09.ex

Aetherus

Aetherus

Finally found the problem. I should not swap a file with a space behind that file.

https://github.com/Aetherus/advent-of-code/blob/178d10a0a3429953ed8fff3df1bca5b3d582e9cb/2024/day-09.livemd

lud

lud

My solution takes 11 seconds adventofcode/lib/solutions/2024/day09.ex at main · lud/adventofcode · GitHub

I have an entry in the disk (a map) for each block. I will see if I can keep all contiguous file parts as a single map entry.

sevenseacat

sevenseacat

Author of Ash Framework

I am not proud of the code I wrote today.

I totally misunderstood the part 2 problem, came up with some code that gave the right answer anyway somehow but it was too slow, so I rewrote it after actually understanding what I was supposed to do, but it was even slower, so I scratched my head a bit and then rewrote it again.

For such an innocuous-sounding puzzle, that did my head in.

https://github.com/sevenseacat/advent_of_code/blob/main/lib/y2024/day09.ex

Runtime:

Name                     ips        average  deviation         median         99th %
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
Flo0807

Flo0807

Very slow solution today. I might come back optimizing it:

https://github.com/Flo0807/adventofcode/blob/main/2024/09.livemd

jarlah

jarlah

again just scrolling ultra fast down to not see any spoilers .. is there a bug in day 9 description?

The first example above, 2333133121414131402, represents these individual blocks:

00...111...2...333.44.5555.6666.777.888899

but:

left: “00…111…2…333.44.5555.6666.777.8888..99”
right: “00…111…2…333.44.5555.6666.777.888899”

i just made the function by spec …

for extremely simple algo that fails see here https://github.com/jarlah/advent_of_code/blob/master/lib/2024/day_9/Part1.ex#L9

ill eat my hat if it isnt something do with the pattern matching for the parse function … i have even added more tests that prove the more simpler examples is parse correctly

sevenseacat

sevenseacat

Author of Ash Framework

No. The example ends with 402 so there’s 4 eights, 0 gap, and 2 nines.

What does your code here https://github.com/jarlah/advent_of_code/blob/master/lib/2024/day_9/Part1.ex#L28 do if n2 is zero?

Your 90909 example is also wrong - it should be 000000000111111111222222222. The description says:

A disk map like 90909 would represent three nine-block files in a row (with no free space between them).

jarlah

jarlah

ofc duh! thanks

sevenseacat

sevenseacat

Author of Ash Framework

There’s been an bug in the problem on only one day that I can remember, in ten years of AOC. And there was a mad uproar about that and it was fixed within an hour.

Last Post!

stevensonmt

stevensonmt

Just realized I had set my Github repo to private b/c the AoC dev does not want input files public and I never remember to put it in the gitignore. So almost all my previous day’s solutions are not visible. lol.

Anyway here’s day 9 for me. Not fast enough really but gets the right answer. Could probably get a speed up by updating what the max_ndx for searching for files would be in part 2 to avoid searching indices that have already been moved.

defmodule Day9 do
  @test "2333133121414131402"

  @real File.read!(__DIR__ <> "/input.txt") |> String.trim("\n")

  def run(mode) do
    data =
      mode
      |> input()
      |> parse()

    part_1(data) |> IO.inspect(label: :part_1)
    part_2(data) |> IO.inspect(label: :part_2)
  end

  defp input(:test), do: @test
  defp input(:real), do: @real
  defp input(_), do: raise("Please use :test or :real as possible modes to run.")

  defp parse(input) do
    Stream.iterate(0, &(&1 + 1))
    |> Stream.intersperse(".")
    |> Enum.zip(String.graphemes(input) |> Enum.map(&String.to_integer/1))
  end

  defp part_1(data) do
    data
    |> compact()
    |> checksum()
  end

  defp part_2(data) do
    data
    |> into_map()
    |> compact_wo_frag()
    |> checksum_2()
  end

  defp compact(blocks) do
    blocks
    |> Enum.reduce_while({[], Enum.reverse(blocks)}, fn
      {".", space}, {acc, rev_blks} ->
        {:cont, move_blocks(space, rev_blks, acc)}

      {ndx, _blks}, {acc, [{ndx, remaining} | _] = _rev_blks} ->
        {:halt, append_blocks(acc, remaining, ndx)}

      {ndx, blks}, {acc, rev_blks} ->
        {:cont, {append_blocks(acc, blks, ndx), rev_blks}}
    end)
  end

  defp into_map(blocks) do
    blocks
    |> Enum.reduce({0, %{}}, fn {ndx_or_space, blks}, {last_dskmp_ndx, diskmap} ->
      max_ndx = last_dskmp_ndx + blks

      dm =
        Map.put(diskmap, last_dskmp_ndx, {blks, ndx_or_space})

      {max_ndx, dm}
    end)
  end

  defp compact_wo_frag({max_ndx, map}) do
    do_compact_wo_frag(0, max_ndx, map, %{})
  end

  defp do_compact_wo_frag(curr, max_ndx, _, acc) when curr > max_ndx, do: acc

  defp do_compact_wo_frag(curr, max_ndx, map, acc) do
    case Map.get(map, curr) do
      nil ->
        do_compact_wo_frag(curr + 1, max_ndx, map, acc)

      {blks, "."} ->
        move_files(blks, curr, max_ndx, max_ndx, map, acc)

      {blks, n} ->
        acc =
          0..(blks - 1)
          |> Enum.reduce(acc, fn i, a -> Map.put(a, curr + i, n) end)

        do_compact_wo_frag(curr + blks, max_ndx, map, acc)
    end
  end

  defp move_files(space, curr, search_ndx, max_ndx, map, acc) when curr >= search_ndx,
    do: do_compact_wo_frag(curr + space, max_ndx, map, acc)

  defp move_files(space, curr, search_ndx, max_ndx, map, acc) do
    case Map.get(map, search_ndx) do
      nil ->
        move_files(space, curr, search_ndx - 1, max_ndx, map, acc)

      {_, "."} ->
        move_files(space, curr, search_ndx - 1, max_ndx, map, acc)

      {blks, n} when blks == space ->
        acc =
          0..(blks - 1)
          |> Enum.reduce(acc, fn i, a -> Map.put(a, curr + i, n) end)

        do_compact_wo_frag(curr + blks, max_ndx, Map.delete(map, search_ndx), acc)

      {blks, n} when blks > space ->
        move_files(space, curr, search_ndx - 1, max_ndx, map, acc)

      {blks, n} ->
        acc =
          0..(blks - 1)
          |> Enum.reduce(acc, fn i, a -> Map.put(a, curr + i, n) end)

        move_files(
          space - blks,
          curr + blks,
          search_ndx - 1,
          max_ndx,
          Map.delete(map, search_ndx),
          acc
        )
    end
  end

  defp move_blocks(0, rev_blks, acc), do: {acc, rev_blks}

  defp move_blocks(space, [{".", _} | rest], acc), do: move_blocks(space, rest, acc)

  defp move_blocks(space, [{ndx, blks} | rest], acc) when blks > space do
    {append_blocks(acc, space, ndx), [{ndx, blks - space} | rest]}
  end

  defp move_blocks(space, [{ndx, blks} | rest], acc),
    do:
      move_blocks(
        space - blks,
        rest,
        append_blocks(acc, blks, ndx)
      )

  defp append_blocks(diskmap, blocks, ndx) do
    diskmap ++ (Stream.cycle([ndx]) |> Enum.take(blocks))
  end

  defp checksum(diskmap) do
    diskmap
    |> Enum.with_index()
    |> Enum.reduce(0, fn {id, pos}, acc -> acc + id * pos end)
  end

  defp checksum_2(diskmap) do
    diskmap
    |> Enum.reduce(0, fn {ndx, val}, sum -> sum + ndx * val end)
  end
end

Day9.run(:real)

Where Next?

Trending in Challenges Top

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New

We're in Beta

About us Mission Statement