Advent of Code 2024 - Day 25

This wraps up Advent of Code 2024 for me. Looking back on the puzzles, here are the ones I found to be the hardest:

The most fun puzzles for me were:

It turns out that three of the puzzles are on both lists.

5 Likes

Yay, 50 stars. My first year trying my hand at AOC. 23 successes, and 2 times I relied on you guys to help me out. Thanks all, it was fun.

Any observations on doing this in Elixir vs. other languages? I noticed the most elegant solutions posted here were a tight sequence of transformers taking the input data through Lists, Maps, MapSets, recursive traversals or searches, and composing it all back to the required output. I know other languages have these parts, but often I found myself smiling in satisfaction at the solutions you all posted.

Happy Holidays

3 Likes

I did this in F# and if I had to do it in Elixir, it would have been almost identical in code, with some strong typing and point free pipes.

This is the first year where I have done more solution in a non-Elixir programming language and loved it. I will actually write a post about my experiences.

2 Likes

Wooooooo, bittersweet that there is no part 2 but really happy to have finished :smile:

After all the challenges involving bit operations, I realised the keys and locks can be encoded as a single integer and a bitwise AND will check if there are any overlaps.

1 Like

I got lazy for this one and just used the 2D grid module again :smiley:

defmodule AdventOfCode.Solutions.Y24.Day25 do alias AdventOfCode.Grid alias AoC.Input def parse(input, _part) do input |> Input.read!() |> String.trim() |> String.split("\n\n") |> Enum.map(&parse_block/1) |> Enum.group_by(&elem(&1, 0), &elem(&1, 1)) end defp parse_block("#####\n" <> _ = lock), do: {:locks, parse_lock(lock)} defp parse_block(".....\n" <> _ = key), do: {:keys, parse_key(key)} defp parse_lock(lines) do coords = to_coords(lines) Enum.map(0..4, fn x -> Enum.max(Map.fetch!(coords, x)) end) end defp parse_key(lines) do coords = to_coords(lines) Enum.map(0..4, fn x -> 6 - Enum.min(Map.fetch!(coords, x)) end) end defp to_coords(lines) do lines |> String.split("\n") |> Grid.parse_lines(fn ?# -> {:ok, true} ?. -> :ignore end) |> elem(0) |> Map.keys() |> Enum.group_by(&elem(&1, 0), &elem(&1, 1)) end def part_one(%{locks: locks, keys: keys}) do for lock <- locks, key <- keys, reduce: 0 do acc -> if opens?(lock, key), do: acc + 1, else: acc end end defp opens?([p | lock], [k | key]) when p + k < 6, do: opens?(lock, key) defp opens?([_ | _], [_ | _]), do: false defp opens?([], []), do: true end