adventofcode

Maravedis 2024-12-09T13:24:51.055559Z

The completion drop rate fell significantly today , and the percent of people stuck on part1 rose sharply.

Aleks 2024-12-09T14:05:02.764289Z

compare with last year

Zach 2024-12-09T14:16:42.706129Z

Today's a struggle 🤣

exitsandman 2024-12-09T16:25:07.797459Z

is the leaderboard still full of LLMs?

roklenarcic 2024-12-09T17:07:35.040719Z

But this is not a particularly hard problem

roklenarcic 2024-12-09T17:07:56.501089Z

why would it fall to half? LLMs cannot handle it?

2024-12-09T17:15:46.352629Z

I'm quite stuck on part 2. Part 1 was easy, and my solution works for the test input on part 2. I have no idea why its wrong for part 2 on the real input

2024-12-09T17:18:29.920569Z

My part 2 is reasonable performance wise as well, if the damn thing was correct 😄

🤣 1
roklenarcic 2024-12-09T17:20:07.849169Z

I did part 1 in a super complicated way that was basically same as part 2 lol except in one way.

2024-12-09T17:21:40.716449Z

I think I have an issue with creating blocks bigger than the initial block if the numbers overlap e.g.

1..2.....2222
would becomes
1..22222.....
And then when I'm scanning back along I would hit 2222 and see I can't move it, instead of just seeing a 2 and moving that to 12..2222 . Balls

roklenarcic 2024-12-09T17:23:09.612799Z

What do you mean? Part2 you’re only moving whole block with a specific ID. There’s never two separate places with same IDs

Zach 2024-12-09T17:23:25.851799Z

Part 2 feels awkward with immutable data structures. I’m waiting to solve it before seeing everyone’s solution but I have a feeling I’ll learn a ton once I do haha

2024-12-09T17:23:35.403369Z

but the ids are each just 1 digit, right ?

roklenarcic 2024-12-09T17:23:40.838709Z

No

2024-12-09T17:23:42.620069Z

like its 0-9 repeat and reused ?

1
2024-12-09T17:23:44.653089Z

oh ffs!

2024-12-09T17:24:00.919539Z

My solution is nowhere close then 😄

roklenarcic 2024-12-09T17:24:03.160329Z

The digit in the input in the size of the block

roklenarcic 2024-12-09T17:24:12.195529Z

So input only has 0-9

roklenarcic 2024-12-09T17:24:27.601879Z

but IDs are sequential and go up to 10k

roklenarcic 2024-12-09T17:25:44.018659Z

In solutions thread you can see 2 solutions from me. A normal one and a solution with regexes because I am a wicked wicked man.

Maravedis 2024-12-09T17:30:40.747469Z

And your regex solution "only" takes 25 seconds on my input! I was truly expecting something akin to 5 minutes, I went and made myself coffee expecting it to be way longer.

2024-12-09T17:32:27.085619Z

So in the example

00...111...2...333.44.5555.6666.777.888899
Each block of numbers represent a file. 0 is 2 blocks long, 1 is 3 blocks long , 9 is 2 blocks long etc. What would an 11th file look it ?
00...111...2...333.44.5555.6666.777.888899.00
But the 00 at the end is a different file to the 00 at the start ?

Maravedis 2024-12-09T17:33:07.593149Z

So, it's not a really convenient way to represent it like this.

roklenarcic 2024-12-09T17:33:14.171339Z

No that’s just a representation

roklenarcic 2024-12-09T17:33:39.567679Z

He manufactured an example with 9 files so he could render it like this

roklenarcic 2024-12-09T17:33:49.230749Z

10 files rather

roklenarcic 2024-12-09T17:34:57.701419Z

so you might look at it like this:

[0 0 nil nil nil 1 1 1 ..... 9 9 nil 10 10]

roklenarcic 2024-12-09T17:35:14.331649Z

How did you solve part1 without sorting this out, might I ask?

Maravedis 2024-12-09T17:35:20.091009Z

With a parsing that puts things in a vector and use numbers, it would look like this: [0 0 nil nil nil 1 1 1 nil nil nil 2 nil nil nil 3 3 3 nil 4 4 nil 5 5 5 5 nil 6 6 6 6 nil 7 7 7 nil 8 8 8 8 9 9 nil 10 10]

Maravedis 2024-12-09T17:35:30.704779Z

Ah damn. @roklenarcic is too fast for me.

2024-12-09T17:36:10.534789Z

I have no idea, my part 1 just worked 😐 I'm thinking maybe by fluke...

🤣 1
roklenarcic 2024-12-09T17:36:15.937409Z

Yeah and for my regex solution I figured: hey, I can go up to 65k on each character with UTF-16, so I can fit each ID in one character.

😁 1
Maravedis 2024-12-09T17:36:34.496889Z

@qmstuart Can you post your code for part 1 ? This is fascinating.

Aleks 2024-12-09T20:18:04.157539Z

@roklenarcic I thought about it too, but it's a little crazy

Aleks 2024-12-09T20:18:58.390059Z

Basically you need about 10k different characters

roklenarcic 2024-12-09T20:56:51.948269Z

10, 50, 5k, 10k? what’s the difference? I just generated \u0xxx on the fly

😀 1
Aleks 2024-12-09T15:20:27.932529Z

@potetm are you going to stream today?

2024-12-09T15:25:34.230879Z

Yep! I'll start at 11:00 CST.

✔️ 1
2024-12-09T16:51:19.759629Z

Day 7 incoming!

2024-12-09T16:51:30.982189Z

https://www.twitch.tv/timpote

2024-12-09T17:56:02.016799Z

@erdos's day 7 is 🔥 tho

2024-12-09T22:23:21.244709Z

A Day 9 part 2 question in the thread to avoid spoliers.

2024-12-09T22:24:26.779179Z

Given memory

[0, 0, nil, 1, 1, 1, 1, nil, nil, 2, 2, 2, 2]
And you were moving 2, 2, 2, 2 Would you expect to be able to move it after the final 1, even though the gap is 2 (because the gap includes the block being moved). ?

2024-12-09T22:24:53.275689Z

So memory would be [0, 0, nil, 1, 1, 1, 1, 2, 2, 2, 2, nil, nil] In this case.

vncz 2024-12-09T22:27:49.597049Z

No, I think the puzzle is specifically asking for 4 empty blocks to put the memory into

👍 3
➕ 1
roklenarcic 2024-12-09T07:24:55.189459Z

Day 9 - Solutions

bhauman 2024-12-13T04:04:56.111219Z

I just can’t let this go. Here’s a tree solution that doesn’t use clojure.zip. It uses straightforward recursion with no micro optimizations and it runs in ~620ms on my old machine. https://github.com/bhauman/adv2024/blob/main/src/adv2024/day09/soltreesimple.clj

roklenarcic 2024-12-09T08:07:50.022689Z

I tried to solve part 1 by taking an id and length pair and then pasting it over 1..n empty space sections, with 0..1 leftover section from empty section. Really horrible stuff to do in Clojure, looping through things, holding an element, that is updated and mutating another vector. Easily added 25 minutes to my time there, when it wasn’t needed at all.

Aleks 2024-12-09T08:20:05.068139Z

I solved it but not happy with my code at all. Part 2 takes about 3.5-4 seconds

roklenarcic 2024-12-09T08:25:48.951939Z

Heh mine takes 11

Maravedis 2024-12-09T09:22:27.287689Z

Pfiou. My code is horrible. But it runs in 280 ms. I'll clean up a bit and post it. Not proud that it took me four hours x)

Maravedis 2024-12-09T09:31:29.079619Z

https://github.com/Maravedis/advent_code/blob/master/src/advent_of_code/2024/09.clj I used sorted maps, which are a huge boon performance wise for part 2.

roklenarcic 2024-12-09T09:51:52.413379Z

what did you use sorted maps for?

djanus 2024-12-09T09:52:20.316139Z

I’ve bruteforced part 2 (gotta get to work) but quite like my custom transducer that solves part 1 in ~0.2ms 🙂 https://codeberg.org/nathell/aoc2024/src/branch/main/src/aoc2024/day9.clj

Maravedis 2024-12-09T09:53:18.986939Z

@roklenarcic keeping the idxes nice and sorted to find the next empty block, and being able to compare the keys (that are indexes in the original memories) to not overshoot.

Maravedis 2024-12-09T09:53:26.789779Z

It works really well.

roklenarcic 2024-12-09T11:11:46.257199Z

I’ve rewritten part2 to use regexes and str/replace https://gist.github.com/RokLenarcic/54b0ed20885ce6739bd39e100adc9249

🤯 3
🔥 2
tildedave 2024-12-09T14:22:41.908889Z

blek, first one this year that required a "slog". I ended up keeping the expanded vector approach for part 2. https://github.com/tildedave/advent-of-code/blob/main/src/advent2024/day9.clj one of those problems where I think it would have been easier with a mutable linked list with a bunch of pointers keeping track of the "next block of size", AoC seems to have a few of these every year...

vncz 2024-12-09T14:24:38.029459Z

Did anybody encounter stack overflow exceptions when trying to "expand" the disk layout?

tildedave 2024-12-09T14:25:21.628769Z

yes, I got this from vec on a giant list, switched to reduce into [] l

vncz 2024-12-09T14:25:55.521329Z

(defn unpack-disk [layout]
  (let [[r]
        (reduce (fn [[res type file] digit]
                  (condp = type
                    1 [(concat res (repeat (parse-long (str digit)) file)) 0 (inc file)]
                    0 [(concat res (repeat (parse-long (str digit)) \.)) 1 file])) [[] 1 0] layout)]
    r))

vncz 2024-12-09T14:26:12.184099Z

I am using this function to unpack, but apparently I get a stackoverflow when using on the real input

vncz 2024-12-09T14:27:26.606879Z

Precisely at iteration 9999 😐

tildedave 2024-12-09T14:30:07.872249Z

looks like it could be this https://stackoverflow.com/questions/24958907/why-does-reduce-give-a-stackoverflowerror-in-clojure

vncz 2024-12-09T14:31:27.719139Z

Ah ok

vncz 2024-12-09T14:31:52.732599Z

So I might need to loop and recur instead

roklenarcic 2024-12-09T17:43:36.678299Z

Updated my regex solution to be simpler and faster.

rjray 2024-12-09T17:43:37.550619Z

Well, I'm still stuck on part 2. Part 1 was poorly implemented, so much so that I had to increase the JVM stack-size to get it to run at all. And the way it represented the data made part 2 essentially impossible. So I'm going to totally re-do how I represent the files and gaps, and see if I can get part 2 done. Then I'll see if I can back-port any of that to part 1 so as to remove the JVM hack.

rjray 2024-12-09T17:44:32.620869Z

(By "poorly implemented", I mean my part 1 solution. The puzzle itself is, of course, just fine.)

roklenarcic 2024-12-09T18:32:54.852229Z

Part 1 is fairly straightforward. You go forward from the front and backwards from the back, throwing anything you find into the holes in the front. Single pass, O(n/2)

Zach 2024-12-09T19:26:27.130149Z

Part 2 got me

Zach 2024-12-09T19:28:11.104549Z

I'm still somewhat of a beginner with clojure. That being said, clojure felt really akward for this. Did anyone else have a similar experience?

roklenarcic 2024-12-09T19:28:46.177399Z

Yes

roklenarcic 2024-12-09T19:32:57.493819Z

A lot of these can be most elegantly solved by sticking some sort of helper mutable datastructure into global scope and then nest a couple of loops and mutate and calculate things as you go. Especially when you have to modify 2 things at once, e.g. update some data and also update some sort of accumulator. Clojure is all about returning sequences and stuff. So you usually have to write reduce calls and have complex arguments so they can hold 2 values that you need to write to. And you have to return these always. Also most C-style languages have much neater syntax when you need to fiddle with indexes.

💯 1
roklenarcic 2024-12-09T19:34:11.532759Z

And all that destructuring and restructuring of pairs or 2-3 key hashmaps ain’t cheap, it’s runs slow.

tildedave 2024-12-09T19:35:00.878859Z

oh yeah i should try using a transient vector here

tildedave 2024-12-09T19:35:08.302349Z

(gotta go fast)

😎 1
rjray 2024-12-09T20:33:13.725899Z

Finally got part 2 done: https://github.com/rjray/advent-2024-clojure/blob/master/src/advent_of_code/day09.clj I borrowed the representation of the uncompressed data from @zelark, and cleaned a couple of things based on comparing my code to his. My part 1, however, is atrocious. Takes 65-70s to run and requires boosting the JVM's stack-size to keep from overflowing. I'll rewrite part 1 later, to use the lessons learned in part 2.

vncz 2024-12-09T20:36:14.814999Z

My solution is relatively bad, but at least I came with it by myself in limited time. I am unable to work on this during the weekends so I had to catch up on day 7 and 8 - and do day 9 then

vncz 2024-12-09T20:36:38.098669Z

It’s kinda embarrassing TBH

vncz 2024-12-09T20:44:35.095999Z

vncz 2024-12-09T20:55:48.315529Z

I do not know why I am unable to upload code snippets

tschady 2024-12-09T21:50:25.039189Z

unreadable. did not enjoy. refuse to refactor. https://github.com/tschady/advent-of-code/blob/main/src/aoc/2024/d09.clj

misha 2024-12-09T22:34:54.599749Z

well, it was annoying more than anything else. chose to wrangle with flattened vec of repeated ids over mapcatting or rrbv/subvec and fighting ints "Elapsed time: 4160.339875 msecs"

2024-12-09T23:07:24.413569Z

I did not enjoy todays puzzle. I managed to get it working, but it was not a great fit for Clojure. I used a vector of (id,file-size,free-size) which was convenient to work with, but kind of slow (3-4 secs) as operations on both ends are needed, though i am sure faster approaches exist. I also ran in to stackoverflows when using normal recursion, so i had to refactor to use loop..recur https://github.com/ChrisBlom/advent-of-code/blob/master/src/adventofcode/2024/day09.clj#L175

vncz 2024-12-09T23:16:54.830959Z

Is that really the case, or are we just bad at Clojure?

vncz 2024-12-09T23:17:04.940769Z

99.9% of the times I feel like this, it’s because I do not know the core library enough

2024-12-09T23:35:54.107819Z

i'm sure there are better ways to solve it, but my solution required changes to both the start and end of a collection + inserts, which are not fast when using lists or vectors. a immutable deque with fast inserts would help a lot

2024-12-09T23:44:58.432829Z

hmm, profiling shows me slowest bit in my solution is searching for which block to move, that could probably be sped up with something clever

rjray 2024-12-09T23:51:11.068429Z

You can also speed up the arbitrary-position updates in a vector with transient.

tildedave 2024-12-09T23:59:43.142939Z

transient didn't save any time for me, probably just not enough updates

genmeblog 2024-12-10T00:12:43.920819Z

I'm quite happy with my solution. 500ms for part 2 (no transient, assoc on vectors, boxed math). I used two separate vectors, one for files and second for gaps (both keeping position and size) which made things quite easy (4 cases for part 1, 2 cases for part 2). https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2024/day09.clj UPDATE: without boxed math part 2 is around 250ms

1
bhauman 2024-12-10T00:59:45.184489Z

Here’s todays: https://github.com/bhauman/adv2024/blob/main/src/adv2024/day09/sol.clj The solution is nothing special really. 25s for part 2. I’d love to revisit it.

bhauman 2024-12-10T01:07:02.168349Z

the way I’d like to do this is to have a simple tree structure that would represent fungible blocks

[[[1 1 1] [:E :E]] [[2 2 2 2] [:E :E]] [[3 3] [:e]]]

Felipe 2024-12-10T01:17:16.691489Z

meh, something wrong with my part 2. works for the example input, maybe doesn't move some files in the real input because checksum is too high compared to other solutions 😕

(def areas (str/trim (slurp "2024/09.sample.in")))
(defn char->num [c] (- (int c) (int \0)))

(def files+spaces
  (loop [areas areas
         types (cycle [:file :space])
         file-number 0
         idx 0
         output {:files [], :spaces []}]
    (if areas
      (let [[area] areas, [area-type] types]
        (recur (next areas)
               (next types)
               (if (= :file area-type) (inc file-number) file-number)
               (+ idx (char->num area))
               (if (= :file area-type)
                 (update output :files  conj [file-number idx (char->num area)])
                 (update output :spaces conj [idx (char->num area)]))))
      output)))

(defn checksum [files]
  (reduce + (map (fn [[number idx area]]
                   (* number (/ area 2) (+ (* idx 2)
                                           (dec area))))
                 files)))

(defn leftmost-that-fits [spaces f-area]
  (when f-area
    (some->> spaces
             (filter (fn [[_s-idx s-area]] (<= f-area s-area)))
             (seq)
             (apply min-key first))))

(let [files+spaces' (update files+spaces :spaces (partial into (sorted-map)))]
  (loop [files+spaces files+spaces', new-files []]
    (let [[f-number _f-idx f-area :as file] (peek (:files files+spaces))
          [s-idx s-area :as space] (leftmost-that-fits (:spaces files+spaces) f-area)]
      (if (seq (:files files+spaces))
        (cond
          (not space)
          (recur (update files+spaces :files pop)
                 (conj new-files file))

          (> s-area f-area)
          (recur (-> files+spaces
                     (update :files pop)
                     (update :spaces dissoc s-idx)
                     (assoc-in [:spaces (+ s-idx f-area)] (- s-area f-area)))
                 (conj new-files [f-number s-idx f-area]))

          (= s-area f-area)
          (recur (-> files+spaces
                     (update :files pop)
                     (update :spaces dissoc s-idx))
                 (conj new-files [f-number s-idx s-area])))
        (+ (checksum (:files files+spaces))
           (checksum new-files))))))

Felipe 2024-12-10T01:22:15.762509Z

wait, maybe I'm moving stuff to the right?

Felipe 2024-12-10T01:24:19.586129Z

that was it!

2
Felipe 2024-12-10T01:32:14.890949Z

Ingy döt Net 2024-12-10T01:42:57.637219Z

#yamlscript Part 1

roklenarcic 2024-12-09T07:26:31.780419Z

What I actually used: https://gist.github.com/RokLenarcic/6567a9a5fd7505268b98fee7d3ba9e6d Here’s after washing it, to make it less horrifying: https://gist.github.com/RokLenarcic/4e15a89d053928130c6ee2036b2e00ee

🙌🏻 1
2024-12-09T07:36:51.611199Z

I promised myself I wasn't going to stay up late on these longer ones.... But I kept thinking I had the right optimization "this time". An hour of optimizing later... https://gitlab.com/maximoburrito/advent2024/-/blob/main/src/day09/main.clj Looking back, linked lists would be the way to go I think...

roklenarcic 2024-12-09T07:59:43.667979Z

your input parsing is very complex for what it is

Ingy döt Net 2024-12-11T02:28:55.084729Z

#yamlscript Part 2

bhauman 2024-12-11T03:43:50.807309Z

OK I made a tree structure and used zippers for navigation and modification and got 1.3s for part2. https://github.com/bhauman/adv2024/blob/main/src/adv2024/day09/soltree.clj

👍 1
👍🏻 1
bhauman 2024-12-11T03:44:47.282579Z

👍 1
Ingy döt Net 2024-12-11T03:44:49.541159Z

Is that pushed?

bhauman 2024-12-11T03:56:49.891489Z

it’s pushed now

bhauman 2024-12-11T03:59:32.567659Z

I’ve not used clojure.zip before so don’t take this as idiomatic