bjorng

bjorng

Erlang Core Team

Advent of Code 2024 - Day 23

This was surprisingly easy.

After a quick attempt to use digraph, I implemented by own straightforward algorithm to find the groups. To my surprise, I didn’t need to do any optimizations to solve both parts. The combined runtime for solving both parts was 2.5 seconds.

I then added an optimization to keep track of the size of largest set seen so far and quickly discard any sets smaller than that number before checking for connectedness.

That reduced the runtime to 0.2 seconds.

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

Most Liked

liamcmitchell

liamcmitchell

Another one that took a long time to reason about and even longer to get working around xmas distractions.
My part 2 runs in 100ms on my 2013 MBP so I’ve prob done something different.

Part 1 example (5.2ms): 7
Part 1 input (22.8ms): 1352
Part 2 example (0.9ms): "co,de,ka,ta"
Part 2 input (106.6ms): "dm,do,fr,gf,gh,gy,iq,jb,kt,on,rg,xf,ze"

For each node I sort all linked nodes by the number of times they are linked to each other. Then reduce the sorted list into the largest set by adding each node if it links to all existing nodes in the set.
https://github.com/liamcmitchell/advent-of-code/blob/6227b6dd61e22568ad110332b85d8ec03561ebad/2024/23/1.exs#L45-L68

antoine-duchenet

antoine-duchenet

Pretty similar solution here (at least for part 2), even without further optimizations (I use simple lists and maps) it solves part 2 sub 500ms:

defmodule Y2024.D23 do
  use Day, input: "2024/23", part1: ~c"l", part2: ~c"l"

  defp part1(input) do
    sorted_edges =
      input
      |> parse_input()
      |> Enum.sort_by(&elem(&1, 1))
      |> Enum.sort_by(&elem(&1, 0))

    sorted_edges
    |> Enum.chunk_by(&elem(&1, 0))
    |> Enum.flat_map(fn set ->
      set
      |> pairs()
      |> Enum.filter(&match?({{a1, _}, {a1, _}}, &1))
      |> Enum.filter(fn {{_, a2}, {_, b2}} -> Enum.member?(sorted_edges, {a2, b2}) end)
      |> Enum.map(fn {{a1, a2}, {a1, b2}} -> {a1, a2, b2} end)
    end)
    |> Enum.filter(fn
      {"t" <> _, _, _} -> true
      {_, "t" <> _, _} -> true
      {_, _, "t" <> _} -> true
      _ -> false
    end)
    |> Enum.count()
  end

  defp part2(input) do
    links =
      input
      |> parse_input()
      |> Enum.flat_map(fn {a, b} -> [{a, b}, {b, a}] end)
      |> Enum.group_by(&elem(&1, 0), &elem(&1, 1))

    links
    |> Enum.reduce({[], 0}, fn {from, tos}, {_, size} = acc ->
      tos
      |> combinations()
      |> Enum.sort_by(&Enum.count/1, :desc)
      |> Enum.take_while(&(Enum.count(&1) >= size))
      |> Enum.find(&full_mesh?(&1, links))
      |> case do
        nil -> acc
        set -> {[from | set], Enum.count(set) + 1}
      end
    end)
    |> elem(0)
    |> Enum.sort()
    |> Enum.join(",")
  end

  defp full_mesh?([], _), do: true

  defp full_mesh?([h | tail], links) do
    connected = Map.get(links, h)

    tail
    |> Enum.all?(&Enum.member?(connected, &1))
    |> Kernel.and(full_mesh?(tail, links))
  end

  defp pairs([]), do: []
  defp pairs([h | tail]), do: for(t <- tail, do: {h, t}) ++ pairs(tail)

  defp combinations([]), do: [[]]

  defp combinations([h | tail]) do
    tails = combinations(tail)
    for(t <- tails, do: [h | t]) ++ tails
  end

  defp parse_input(input), do: Enum.map(input, &parse_line/1)

  defp parse_line(<<node1::bytes-size(2), "-", node2::bytes-size(2)>>) do
    [node1, node2]
    |> Enum.sort()
    |> List.to_tuple()
  end
end

@bjorng I see this in your code:

    |> Enum.group_by(&elem(&1, 0))
    |> Enum.map(fn {v, reachable} ->
      {v, Enum.map(reachable, &elem(&1, 1))}
    end)
    |> Map.new

Is there any reason you do not use the third argument of Enum.group_by/3 to transform the values ?

rvnash

rvnash

Another fairly easy day. Decided to do part1 and part2 by just getting all valid networks first, and filter them later. It was taking about 8 seconds. Then added a filter function to pick out only the valid combinations on the fly, and that helped.

https://github.com/rvnash/aoc2024/blob/main/lib/d23.ex#L63

Then, taking advantage of the knowledge I gained yesterday about Atom being the fastest type of key for a Map, converted the computer names to atoms and got 3X faster. Final results are ~110ms for both parts on my M1 Mac.

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
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
bismark
Took me a minute to remember my binary math :smile: :grimacing:.. import Bitwise __DIR__ |&gt; Path.join("puzzle.txt") |&gt; File.strea...
New
QuinnWilton
Note: This topic is to talk about Day 7 of the Advent of Code 2019 . There is a private leaderboard for elixirforum members. You can joi...
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
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
kwando
Phew, this one took a while to get right. My naive attempts was way to slow so I reached for Dijkstras shortest path algorithm.. and that...
New
bjorng
Here is my solution for day 1 of Advent of Code: defmodule Day01 do def part1(input) do all = parse(input) {first, second} = E...
New
shritesh
I mapped both the cards and every possible hand to numeric values and sorted them. In part 2 I could only think of replacing the jokers w...
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

Other popular topics Top

skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

We're in Beta

About us Mission Statement