antoine-duchenet

antoine-duchenet

Advent of Code 2024 - Day 11

Everything went smoothly today.
Nothing to change to solve part 2 because I already used memoization for part 1 (it looked like an AoC exercise where it would be useful :smile_cat: ).

Here are the main parts :

  defp blink([_], 0), do: 1

  defp blink([0], steps), do: blink([1], steps - 1)

  defp blink([h], steps) do
    Performance.memoize({h, steps}, fn ->
      case should_split?(h) do
        {true, split_params} -> split_params |> split() |> blink(steps - 1)
        _ -> blink([h * 2024], steps - 1)
      end
    end)
  end

  defp blink([h | tail], steps) do
    blink([h], steps) + blink(tail, steps)
  end

Part 2 takes ~100ms ~70ms to run.
A virtual part 3 with 1000 blinks instead of 75 takes “only” ~5475ms to run.

Most Liked

billylanchantin

billylanchantin

PSA: If you’re using Elixir 1.18, now there’s:

No more Enum.reduce(enum, 0, &(&1 + &2)) :slight_smile:

mexicat

mexicat

Once I had coffee and realized that order doesn’t matter I just used plain old Maps:

Part 1 runs in ~700μs, part 2 runs in ~40ms.

sevenseacat

sevenseacat

Author of Ash Framework

Oh yes, and even when stones are replaced, they always stay in the same order! Makes you think that order is important

Flo0807

Flo0807

My solution using ETS. It takes 56.94 ms for Part 2 with a clean cache.

defmodule PlutonianPebbles do
  def init_cache do
    if :ets.whereis(:stones_cache) != :undefined do
      :ets.delete(:stones_cache)
    end

    :ets.new(:stones_cache, [:set, :public, :named_table])
  end

  def blink_stone(0), do: 1

  def blink_stone(stone) do
    digits = Integer.digits(stone)
    len = length(digits)

    if rem(len, 2) == 0 do
      mid = div(len, 2)
      first = Enum.take(digits, mid) |> Integer.undigits()
      second = Enum.drop(digits, mid) |> Integer.undigits()
      {first, second}
    else
      2024 * stone
    end
  end

  def count_stones(stones, depth) when is_list(stones) do
    stones
    |> Enum.map(&count_stones(&1, depth))
    |> Enum.sum()
  end

  def count_stones(stone, depth) do
    cache_key = {stone, depth}

    case :ets.lookup(:stones_cache, {stone, depth}) do
      [{_key, result}] ->
        result

      [] ->
        calculate_stones(stone, depth)
        |> tap(fn result ->
          :ets.insert(:stones_cache, {cache_key, result})
        end)
    end
  end

  defp calculate_stones({_first, _second}, 0), do: 2
  defp calculate_stones(_stone, 0), do: 1

  defp calculate_stones(stone, depth) do
    case blink_stone(stone) do
      {first, second} ->
        count_stones(first, depth - 1) + count_stones(second, depth - 1)

      stone ->
        count_stones(stone, depth - 1)
    end
  end
end

nums = String.split(puzzle_input) |> Enum.map(&String.to_integer(&1))
PlutonianPebbles.init_cache()

# Part 1
PlutonianPebbles.count_stones(nums, 25)

# Part 2
PlutonianPebbles.count_stones(nums, 75)
Aetherus

Aetherus

I was stupid. I don’t need a graph.

blink = fn
  0 ->
    [1]

  n ->
    len = floor(:math.log10(n)) + 1

    if Bitwise.band(len, 1) == 1 do
      [n * 2024]
    else
      d = 10 ** Bitwise.bsr(len, 1)
      [div(n, d), rem(n, d)]
    end
end

############################

puzzle_input
|> String.split()
|> Enum.map(&String.to_integer/1)
|> Enum.frequencies()
|> Stream.iterate(fn freqs ->
  for {num, freq} <- freqs, num2 <- blink.(num), reduce: %{} do
    freqs2 -> Map.update(freqs2, num2, freq, & &1 + freq)
  end
end)
|> Enum.at(75)
|> Map.values()
|> Enum.sum()

Where Next?

Popular in Challenges Top

sasajuric
Note by the Moderators: This topic is to talk about Day 5 of the Advent of Code. For general discussion about the Advent of Code 2018 an...
New
JEG2
Note: This topic is to talk about Day 9 of the Advent of Code. For general discussion about the Advent of Code 2018 and links to topics ...
New
Aetherus
This topic is about Day 3 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/le...
New
christhekeele
Continuation of Advent of Code 2022​:christmas_tree:, Day 1: Day 2! Leaderboard:
New
bjorng
This topic is about Day 9 of the Advent of Code 2021 . We have a private leaderboard (shared with users of Erlang Forums): https://adve...
New
bjorng
Note: This topic is to talk about Day 18 of the Advent of Code 2019. There is a private leaderboard for elixirforum members. You can joi...
New
adamu
Probably not the most efficient implementation, because part 1 took &gt;1 ms and part 2 &gt;4ms, but the code was simple enough. def p...
New
cblavier
Hi, there :wave: Today, I felt it was way more challenging! I went through part2 thanks to Agent based memoization (without memoization ...
New
Aetherus
I spent 3 hours struggling in part 2, until I noticed a very basic mistake :joy: Here’s my code: By the way, the starting position in...
New
coen.bakker
Since I started using Elixir, I have benefited greatly from being able to study various open-source projects. The codebase of LiveBook, i...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement