adventofcode

Aleks 2024-12-11T10:44:38.222589Z

I guess it's 10, as AoC meets its first anniversary

🔟 5
2024-12-11T13:29:21.349909Z

I misspoke during yesterday's stream. I will not be able to stream today. I've already committed to volunteering at the Salvation Army this morning. I'll be back tomorrow at 11:00am CST!

👍 4
2024-12-11T14:13:43.439739Z

So, day 11 part 2. My naive solution for part 1, with 25 turned up to 75... How unlikely is this to finish in a reasonable time ?

Maravedis 2024-12-11T14:21:14.389479Z

The sun will eat the Earth before you finish 😄

🫠 1
exitsandman 2024-12-11T17:45:15.938189Z

Someone estimated that their implementation would've taken the age of the observable Universe. Human beings don't handle exponential growth very well.

2024-12-11T14:15:45.015219Z

It gets to about 40 iterations and its very very slow at this point.

Arno Jacobs 2024-12-11T14:18:06.951689Z

Hint: memoization

jurjanpaul 2024-12-11T15:21:12.340939Z

Hint: how relevant is the position of the stones?

2024-12-11T15:23:09.901329Z

dont really care about the positions, do I ? e.g. 0 -> 1 -> 2024 -> 20, 24, that's going to go from 1 stone to 2 stones, regardless of its position.

👌 1
bhauman 2024-12-11T19:58:32.147249Z

Here’s the answer to day 11 I found on reddit:

🔣 2
bhauman 2024-12-11T20:00:26.028049Z

I’d never heard of this lang, I’m guessing its APL like.

thomas 2024-12-12T08:58:25.888849Z

certainly looks like it

thomas 2024-12-12T08:58:38.565619Z

but now at least it all makes sense

thomas 2024-12-12T08:58:40.696159Z

😉

Alvydas Vitkauskas 2024-12-12T13:02:12.355809Z

UIUA is really cool language (if you are into the APL-like world at all) and is actively developed.

👍 1
2024-12-11T05:29:26.314029Z

Day 11 - Solutions

exitsandman 2024-12-11T08:23:03.151059Z

Maravedis 2024-12-11T09:16:24.404359Z

Finally did it. My god. This is terrible code. I missed something obvious and I'm anxious to discover what.

👏 2
👏🏻 1
Maravedis 2024-12-11T09:21:42.163099Z

I just couldn't figure out how to have a clean history. The fact that I need to store the number of steps remaining was fucking with me. Ended up storing the tree. I don't think it's the way to go. Posting the code to shame myself into cleaning it up ><

Maravedis 2024-12-11T09:35:05.648029Z

OH so my whole code can be replaced by a one-liner because I didn't think of just counting at each step instead of storing the result. Cool cool cool cool. Godammit.

tschady 2024-12-11T13:01:19.751669Z

memoized recursion https://github.com/tschady/advent-of-code/blob/main/src/aoc/2024/d11.clj

tschady 2024-12-11T13:47:06.119489Z

hah, ya memoize isn’t saving me much since it only operates at that level. frequencies is better (and faster). it was a reflex from looking at the problem. memoize only useful if you run the problem multiple times.

tildedave 2024-12-11T14:25:48.826169Z

memoizing the recursion relation seems ideologically better, I went with frequences as others have pointed out. https://github.com/tildedave/advent-of-code/blob/main/src/advent2024/day11.clj#L45-L56

bhauman 2024-12-11T14:36:17.010659Z

Here’s todays: https://github.com/bhauman/adv2024/blob/main/src/adv2024/day11/sol.clj

bhauman 2024-12-11T14:37:13.869759Z

bhauman 2024-12-11T14:38:19.360859Z

~340ms for part 2

bhauman 2024-12-11T14:38:30.180049Z

used recursion and memoize

vollcheck 2024-12-11T14:47:49.977279Z

managed to get ~448 µs (on 10yo machine) for part 2 with quite clean Clojure: https://github.com/vollcheck/aoc/blob/master/src/y24/day11.clj#L49

vollcheck 2024-12-11T14:49:49.625489Z

btw I examinated splitting number as string vs use of Math/pow, quot and rem and the latter is 2x faster on average

Zach 2024-12-11T15:43:02.265719Z

I know what I have to do, but my brain doesn't wanna.@malaingreclement try taking notes of your thought process so you can go back after and see what was leading you down the wrong path! Sometimes the thing that throws you off is a couple of steps before it actually happens and it's almost impossible to see that after it happens

Zach 2024-12-11T15:47:27.471379Z

I got pretty tripped up on checking the number of digits. Kept getting weird edge cases (log 1, log 10)... I even tried to find a closed form solution but this isn't project euler 🤣

Maravedis 2024-12-11T15:49:12.862339Z

My solution was able to rebuild the whole tree... Which is stupid, but yeah, I simply didn't keep in mind the goal of the exercise.

rjray 2024-12-11T17:14:03.107139Z

https://github.com/rjray/advent-2024-clojure/blob/master/src/advent_of_code/day11.clj I'm just sick over part 2. Like many, I brute-forced part 1 but realized almost immediately that it wouldn't work for part 2. So I got the idea to just keep a count of how many stones of each number there were in a given state and produce the next state from that. I didn't have to preserve any past state this way, and a (reduce + (vals <final>)) would give me my answer. But it didn't work; I kept getting answers wildly too high (I was only running part 2 for 25 blinks and comparing it to the brute-force part 1 answer). After about 2 hours and 40 minutes (11:40PM local time) I gave up and went to bed. This morning, I tried some other things with identical results. I believed in the algorithm, so I just yanked out the code and re-implemented it. Now, I was getting answers too low, but only slightly. Stepping each implementation through progressively more iterations, I finally found the last bug: when accounting for a split stone, if the two splits were the same number I was only counting one stone, not two. Problem solved, but still annoyed with myself.

👏 1
👏🏻 1
Maravedis 2024-12-11T17:16:44.559829Z

As a fellow "stuck on an idea", you have all my compassion. Congrats on solving it!

misha 2024-12-11T17:21:49.264849Z

@j3k.walczak (take (inc times)) last -> (drop times) first

misha 2024-12-11T17:25:50.853739Z

misha 2024-12-11T17:29:35.774289Z

split string + join - 250ms

Apple 2024-12-11T18:15:01.550859Z

This might err {L n R n} when L=R

👍 1
genmeblog 2024-12-11T18:48:54.455789Z

Custom memoization after half of the day of (over)thinking. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2024/day11.clj

Felipe 2024-12-11T19:04:02.790879Z

memoized recursion too here! shortest code this year so far

(def count-stones
  (memoize
   (fn [n x]
     (if (zero? n)
       1
       (let [stone-length (count (str x))]
         (cond
           (zero? x)
           (count-stones (dec n) 1)

           (even? stone-length)
           (+ (count-stones (dec n) (parse-long (subs (str x) 0 (/ stone-length 2))))
              (count-stones (dec n) (parse-long (subs (str x) (/ stone-length 2) stone-length))))

           :else
           (count-stones (dec n) (* 2024 x))))))))

(def initial-stones (read-string (format "[%s]" (slurp "2024/11.in"))))
(reduce + (map (partial count-stones 25) initial-stones))
(reduce + (map (partial count-stones 75) initial-stones))

Felipe 2024-12-11T19:08:37.295079Z

hah, practically identical to @roklenarcic

Felipe 2024-12-11T19:16:20.003589Z

@tws I think memoize does prune a lot of steps even on the first, cold run

tschady 2024-12-11T19:27:59.450749Z

edit: i should benchmark memoization vs. frequencies

Felipe 2024-12-11T19:37:53.136229Z

aha, yeah. thought about it harder and frequencies is definitely less computation. clever

roklenarcic 2024-12-11T19:39:12.645089Z

@tws That’s not true. I wrote both and memoization beats frequencies.

roklenarcic 2024-12-11T19:40:44.137239Z

I’ll retract these statements 🙂 Depends on how you define level

roklenarcic 2024-12-11T19:44:33.318819Z

Here’s with memoization: https://gist.github.com/RokLenarcic/6caca85b7be6ba642b20ef70ffdd51fe Here’s without: https://gist.github.com/RokLenarcic/d154a81f747da21cf0ce63352870050c You can try it yourself. It varies a lot based on how hot the hotspot code is.

roklenarcic 2024-12-11T19:51:07.166749Z

But I could optimize frequencies more. Remove merge with and use a transient and merge directly into it.

bhauman 2024-12-11T20:01:28.070749Z

I’m having a hard time intuiting why the frequencies approach works. I understand its implementation but I’m having a hard time seeing the equivalence in the two methods.

tildedave 2024-12-11T20:04:09.061839Z

you can think about it like a compaction of the list, e.g. if you have a 1024 in your list, it always becomes 10 24 in the next version of the list, and this happens whether there's 1 or 50.

tildedave 2024-12-11T20:04:26.169459Z

so instead of 1024 .... 1024 ... 1024 ... 1024 ... you store {1024 4} etc

exitsandman 2024-12-11T20:04:50.457389Z

The key to that approach is that ordering doesn't actually matter despite the text saying it does. E: Regardless of what approach is more efficient in terms of time, the freqs approach does have the advantage of using constant stack space.

👍 1
bhauman 2024-12-11T21:03:19.931569Z

OK I got it. I was picturing it the frequency execution incorrectly.

Aneesh Mulye 2024-12-11T21:48:50.093349Z

Man, this one is so hard to give hints for without giving everything away! I just saw frequencies and TBH that was enough for me to both get the basic idea, and try out a simple naive implementation of the idea, which worked immediately.

Aneesh Mulye 2024-12-11T22:02:52.642229Z

My solution (came out pretty clean, I personally think, though not the shortest):

(ns advent-24.day-11
  (:require [clojure.string :as str]))

(defn parse-d11-input [fname]
  (->> (str/split (first (str/split-lines (slurp fname))) #"\s+")
       (mapv #(parse-long %))))

(defn d11-1-blink [stones]
  (reduce
    (fn [v stone]
      (cond
        (= 0 stone) (conj v 1)

        (even? (count (str stone)))
        (let [len (/ (count (str stone)) 2)
              sstone (str stone)
              l (parse-long (subs sstone 0 len))
              r (parse-long (subs sstone len))]
          (conj v l r))

        :else (conj v (* 2024 stone))))
    []
    stones))

(defn d11-2-blink [stone-freqs]
  (reduce
    (fn [m [stone freq]]
      (cond
        (= 0 stone) (update m 1 (fnil #(+ % freq) 0))

        (even? (count (str stone)))
        (let [len (/ (count (str stone)) 2)
              sstone (str stone)
              l (parse-long (subs sstone 0 len))
              r (parse-long (subs sstone len))]
          (-> m
              (update l (fnil #(+ % freq) 0))
              (update r (fnil #(+ % freq) 0))))

        :else (update m (* 2024 stone) (fnil #(+ % freq) 0))))
    {}
    stone-freqs))

(comment
  ;; Parsing input
  (def i (parse-d11-input "resources/input_11"))
  ;; Part 1
  (->> i
       (iterate d11-1-blink)
       (take 26)
       (last)
       (count))
  ;; Part 2
  (->> (frequencies i)
       (iterate d11-2-blink)
       (take 76)
       (last)
       (vals)
       (reduce +))
  )

misha 2024-12-12T08:33:49.523999Z

@zengxh (= L R) is handled on prev line: (= L R) {L (* 2 n)}

Apple 2024-12-12T14:06:35.681849Z

Of course I missed that. You are right. @misha

roklenarcic 2024-12-11T05:30:24.842189Z

These are getting into oneliner territory. Yesterday too

roklenarcic 2024-12-11T05:32:05.655509Z

how fast does it calculate (on empty cache)?

2024-12-11T05:33:50.543269Z

"Elapsed time: 213.921853 msecs"

roklenarcic 2024-12-11T05:36:16.830829Z

(time (p2 input)) “Elapsed time: 114.840958 msecs”

roklenarcic 2024-12-11T05:36:42.342289Z

I think that subs is faster than splitting string into a sequence and then reassembling it

Aleks 2024-12-11T05:39:29.849589Z

Guys, any clues for part 2?

roklenarcic 2024-12-11T05:41:44.894909Z

the usual crap

roklenarcic 2024-12-11T05:42:03.932809Z

I cannot be more specific without telling everything, it’s so simple

roklenarcic 2024-12-11T05:42:35.053899Z

Think about what’s the usual thing we do in AoC in those situations

2024-12-11T05:46:46.637429Z

@zelark Since this is the solution thread already, consider the example of [125 17] Then consider what you would have gotten for just [125] and just for [17]

erdos 2024-12-11T05:53:46.970279Z

frequencies! https://github.com/erdos/advent-of-code/blob/master/2024/day11.clj

❤️ 2
Apple 2024-12-11T06:09:58.165359Z

Best case: "Elapsed time: 0.343692 msecs"

roklenarcic 2024-12-11T06:19:15.572769Z

@erdos that’s even better

Andrew Byala 2024-12-11T06:33:23.842789Z

I did two implementations, with an explanation about memoizing results manually vs using Clojure's built-in support. • Blog: https://github.com/abyala/advent-2024-clojure/blob/main/docs/day11.md • Code: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day11.clj • Code with built-in memoization: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day11_memo.clj

Aleks 2024-12-11T06:39:27.843859Z

thanks @erdos, when you said frequencies I got it

Aleks 2024-12-11T06:40:24.721319Z

The old good frequencies, how could I miss it

Maravedis 2024-12-11T06:53:51.600989Z

I'm stumped. I know what I have to do, but my brain doesn't wanna. I know I have to account for the states repeating, and memoize that, but for some reason, I'm stuck on how to store the cache in a way that makes sense.

Maravedis 2024-12-11T06:53:58.440209Z

This is intensely frustrating.

Aleks 2024-12-11T07:07:01.360079Z

@malaingreclement I see, I felt almost the same until freqs shed some light. Also I took a small break to restart my brain.

Maravedis 2024-12-11T07:08:16.830989Z

I don't see how frequencies applies to caching 😕 Like, yeah, I can count things that repeat and simplify the tree, but the naive implem doesn't work with a starting root of 0 on depth 75, so I'm struggling. I might just need to take a small break.

Aleks 2024-12-11T07:10:16.056809Z

frequencies applies not to caching, but to reducing repeating stones, take a brake and mull it over

Maravedis 2024-12-11T07:10:42.822449Z

I think I pigeon-holed myself in a mapcat hell and it's not helping ^^. Imma come back to this later.