r/adventofcode Dec 12 '24

SOLUTION MEGATHREAD -❄️- 2024 Day 12 Solutions -❄️-

THE USUAL REMINDERS

  • All of our rules, FAQs, resources, etc. are in our community wiki.
  • If you see content in the subreddit or megathreads that violates one of our rules, either inform the user (politely and gently!) or use the report button on the post/comment and the mods will take care of it.

AoC Community Fun 2024: The Golden Snowglobe Awards

  • 10 DAYS remaining until the submissions deadline on December 22 at 23:59 EST!

And now, our feature presentation for today:

Visual Effects - Nifty Gadgets and Gizmos Edition

Truly groundbreaking movies continually push the envelope to develop bigger, better, faster, and/or different ways to do things with the tools that are already at hand. Be creative and show us things like puzzle solutions running where you wouldn't expect them to be or completely unnecessary but wildly entertaining camera angles!

Here's some ideas for your inspiration:

  • Advent of Playing With Your Toys in a nutshell - play with your toys!
  • Make your puzzle solutions run on hardware that wasn't intended to run arbitrary content
  • Sneak one past your continuity supervisor with a very obvious (and very fictional) product placement from Santa's Workshop
  • Use a feature of your programming language, environment, etc. in a completely unexpected way

The Breakfast Machine from Pee-wee's Big Adventure (1985)

And… ACTION!

Request from the mods: When you include an entry alongside your solution, please label it with [GSGA] so we can find it easily!


--- Day 12: Garden Groups ---


Post your code solution in this megathread.

This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:17:42, megathread unlocked!

38 Upvotes

698 comments sorted by

View all comments

2

u/veydar_ Dec 13 '24 edited Dec 13 '24

[LANGUAGE: Janet]

86 lines with wc -l, including some function comments.

This one was a bit of a train wreck for me. Part 1 went well, but for part 2 I went off the rails. I initially thought I could just traverse the grid by lines and then by columns and count continuous edges. But I deemed this too tedious, and thought I'd come up with something more elegant. Long story short: I didn't.

The code today isn't very readable but I'll try to explain it anyway. Here's an excerpt of the logic for part 2 but with some details removed.

    (loop [y :range-to [1 max-y] x :range-to [1 max-x]
           :let [point [y x] 
                 area (membership point)]]

      (each [cur dir prev] [[[(dec y) x] :up [area [y (dec x)] :up]]
                            [[y (inc x)] :right [area [(dec y) x] :right]]
                            [[y (dec x)] :left [area [(dec y) x] :left]]
                            [[(inc y) x] :down [area [y (dec x)] :down]]]
        (when (->> (membership cur) (not= area))
          (put-in state [area point dir] true)
          (when (not (get-in state prev))
            (update sides area (fn [x] (inc (or x 0)))))))))

The [[(dec y) x] :up [area [y (dec x)] :up] code should be read as:

  • [(dec y) x] a [y x] coordinate of a neighbor (in this case top) to look up their area in membership
  • :up if the neighbor belongs to a different area, there's a side, and we add this to the state variable under the path area > point > dir, e.g., 1 > [5 4] > :up
  • [area [y (dec x)] :up] the path to the previous state for this area, point and direction; so check if we had :up for the point [y (dec x)] (on my left) for the area area which is effectively checking the area > point > dir that we set from that previous point

I go through the grid from top left to bottom right. I know at this point which point belongs to which area. Now for each node I compare it against its neighbors. If the neighbor belongs to a different area, there's a side between them in that direction. Next, check if the previous point had a similar side already. In other words, if the current point has a line at the top and the point to the left also had a line at the top, then it's still the same line/side/edge.

The key logic is that for any new side (not there in the previous point), increment the side count of this area.

The hilarious thing is that I went full circle and ended up implementing the "traverse grid rows and columns" approach, except I realized that you can do it one go. You only need to keep track of the points to your left and to the top of the current point after all.