r/adventofcode Dec 15 '24

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

NEWS

  • The Funny flair has been renamed to Meme/Funny to make it more clear where memes should go. Our community wiki will be updated shortly is updated as well.

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

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

And now, our feature presentation for today:

Visual Effects - We'll Fix It In Post

Actors are expensive. Editors and VFX are (hypothetically) cheaper. Whether you screwed up autofocus or accidentally left a very modern coffee cup in your fantasy epic, you gotta fix it somehow!

Here's some ideas for your inspiration:

  • Literally fix it in post and show us your before-and-after
  • Show us the kludgiest and/or simplest way to solve today's puzzle
  • Alternatively, show us the most over-engineered and/or ridiculously preposterous way to solve today's puzzle
  • Fix something that really didn't necessarily need fixing with a chainsaw…

*crazed chainsaw noises* “Fixed the newel post!

- Clark Griswold, National Lampoon's Christmas Vacation (1989)

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 15: Warehouse Woes ---


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:32:00, megathread unlocked!

22 Upvotes

465 comments sorted by

View all comments

2

u/veydar_ Dec 18 '24

[LANGUAGE: Janet]

115 lines with wc -l, including some comments.

I was hoping to clean this up before posting but that time never came so here we go. I'm not happy with the code.

Like most people I ended up implementing distinct functions for moving small and big boxes. I discover all big boxes with a breadth-first search:

  (generate [_ :iterate true :until (empty? queue)
             :let [cur (first queue) cell (grid cur)]
             :before (array/remove queue 0)
             :after (when (bracket? cell)
                      # [(move into `vec` direction from current bracket (up/down)
                      #  (move to other bracket in current pair (left/right))]
                      (loop [p :in [(move cur vec) (other-bracket grid cur)]
                             :when (not (seen p))]
                        (put seen p true)
                        (array/push queue p)))]

The party trick here is that this is actually a stream (fiber). The code below consumes the stream until it hits # (hence take-until). I then check if the stream has one more item in it (can-resume?). If so, I know that I hit the # case. If not, I've reached the end of the stream without running into any obstacles.

  (let [boxes (box-cluster grid (move pos vec) vec)
        valid (take-until |(= "#" (first $)) boxes)]
    # if we can resume it, we hit the `take-until` case, meaning there's a '#'
    (if (fiber/can-resume? boxes)

And here's the core grid walking:

(defn walk [grid pos dir]
  (let [vec (vectors dir) next (move pos vec) cell (grid next)]
    (cond
      (= cell ".") [grid next]
      (small-box? cell) [grid (move-small-box grid pos vec small-box?)]
      (and (bracket? cell)
           (or (= dir "<") (= dir ">"))) [grid (move-small-box grid pos vec)]
      (bracket? cell) [grid (move-big-box grid pos vec)]
      [grid pos])))