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

LostKobrakai
This topic is about Day 9 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/le...
New
bismark
Took me a minute to remember my binary math :smile: :grimacing:… import Bitwise __DIR__ |&gt; Path.join("puzzle.txt") |&gt; File.stream...
New
antoine-duchenet
Everything went smoothly today. Nothing to change to solve part 2 because I already used memoization for part 1 (it looked like an AoC e...
New
bjorng
This topic is about Day 16 of the Advent of Code 2021. We have a private leaderboard (shared with users of Erlang Forums): https://adve...
New
New
stevensonmt
Anyone else think the prompt for this challenge is contradictory? The rules for comparing packets include If both values are lists, c...
New
jkwchui
Monkeys fitted squarely as GenServers in my head. My initial problem was using cast instead of call; I imagine impolite monkeys slinging...
New
Aetherus
This topic is about Day 16 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/l...
New
bjorng
Note: This topic is to talk about Day 4 of the Advent of Code 2019. There is a private leaderboard for elixirforum members. You can join...
New
Aetherus
Don’t know why the regex ~r/[\W && [^\.]]/x does not work in Elixir. It works pretty well in Ruby. Anyway, here is my solution:
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
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
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement