Fork me on GitHub
#adventofcode
<
2023-12-05
>
cdpjenkins05:12:49

Having just read day 5, I must be getting a lot dumber. And I feel bad because I persuaded a whole load of people to try it for the first time this year and I assured them that, even if it got difficult later on, the first week would be relatively doable.

dpsutton05:12:21

yikes. just read it. that's too close to business logic and just tedious. I don't feel bad skipping

jake09:12:54

Haha, same here! Day 1 was way harder than I was expecting after having told my friend "don't worry, it will be trivial".

cdpjenkins09:12:40

Well I’ve managed part 1 (in Kotlin…) and I think I know how to do part 2 now… but it’s still my view that it is still the first week and I want problems that are easy enough for me to do before work!

potetm13:12:21

Part 1 is actually went faster for me than Day 2 this year lol

potetm13:12:26

Part 2 is evil

Alvydas Vitkauskas15:12:52

What I like about this kind of puzzles, that they show you how much (in millions and billions) the right thinking and the right algorithm can be better/quicker than just “let’s do it” brute force approach. I always wonder how much we loose in our business code efficiency (and server costs) just because…

hlship00:12:08

I think up until part 5b it's been pretty easy, except for that one gotcha early one with the number names.

hlship00:12:41

But 5b seems to require processing billions of values.

hlship00:12:45

Unless I'm missing something.

hlship00:12:59

Oh, maybe don't treat the range as a range per-se, but break it down into sub-ranges that match the first formula's ranges.

hlship00:12:54

So transform the initial seed ranges into a new set of ranges for the first map :seed-to-soil. Each input seed range will convert into 1 or more output seed ranges. The perform the same xform using the :soil-to-fertilizer ranges, all the way down. So basically, you do a lot fewer comparisons.

👍 1
hlship00:12:15

I think I'm on to something.

norman07:12:52

Day 5 - Solutions

norman07:12:37

https://gitlab.com/maximoburrito/advent2023/-/blob/main/src/day05/main.clj I think the solution is pretty solid, but the poor and inconsistent naming and structure makes it a bit opaque. Write once ... read never....

wevrem07:12:03

I have some repeat logic preparing the input for puzzle 1 and puzzle 2, I usually refactor that sort of thing into a single function, but I’m too tired, I’ll do it tomorrow morning.

Jakob Durstberger11:12:54

I don't think my part-2 solution is performing too well..... it has been running for nearly an hour now and still hasn't given me the answer 😄

Arno Jacobs11:12:58

@UM8P1G72Q If it's running for an hour then it will probably run for many more hours. Need a hint?

Jakob Durstberger12:12:36

I have given up on my current solution. I'll have to think a bit more 😕 No hints yet 😄

Arno Jacobs12:12:17

@UM8P1G72Q 🙂 I'm learning Clojure and (or but) first building my code in Haskell or Swift. The compiled version of the not-so-intelligent brute force solution needed 8+ minutes. (Now working on the efficient version. 😉 )

Jakob Durstberger12:12:45

Maybe I did something horribly wrong 😅

1
Jakob Durstberger12:12:56

Just for my own sanity. With the input on part 2 you end up with billions of seeds, right?

1
tschady14:12:56

unless you go backwards

tschady14:12:16

my input has a 0 in the last part, can start there

1
norman14:12:39

I started with 2.2 billion seeds in 20 groups and ended with 2.2 billion in 92 groups.

Arno Jacobs14:12:15

@UM8P1G72Q @U1Z392WMQ And going backwards I didn't need any code.

lol 1
wevrem14:12:13

time puzzle 1: 4.7ms time puzzle 2: 16.9ms

karlis15:12:05

Took a while to write down my pen+paper solution for part 2: https://github.com/skazhy/advent/blob/master/src/advent/2023/day5.clj

cdpjenkins20:12:04

I won't post my solution here because it's not Clojure (I used - gasp - Kotlin to write it) but I did manage to implement the "clever" solution to part 2 in the end and it runs in 100ms or so. I'm sure it could be made to run faster as well.

Marcel Krcah21:12:32

new to clojure, I wanted to learn and explore loop-recur; so here's part1 only with some cumbersome but working loop logic https://github.com/mkrcah/advent-of-code/blob/main/src/day_05.clj

Jörgen Lundberg23:12:57

Part 2 seemed so simple... 😄 Does the algorithm to solve day 2 have a name?

tschady00:12:09

My code is shit, so no post for me, but this was fun to use meta data instead of keeping separate collections:

(defn chranges
  [[x y d :as r] [a b :as orig] ]
  (cond
    (:altered (meta orig)) (list orig)            ;; already altered
    (or (< b x) (> a y)) (list orig)              ;; totally outside
    (< a x) (conj (chranges r [x b]) [a (dec x)]) ;; outside L
    (> b y) (conj (chranges r [a y]) [(inc y) b]) ;; outside R
    :else ;; inside, map it and set altered flag
    (list (with-meta [(+ d (- a x)) (+ d (- b x))] {:altered true})))) 

Felipe01:12:29

solved mine through dataviz. decimated the input ranges, searched for the part that likely had the global minimum, zoomed in and limited the range checking to that region. it worked!

Felipe01:12:37

>

;; this is a bit opaque, but the basic idea is that for each input range,
>   ;; compute the all the ranges it could be after going through the each map
>   ;; the lowest starting point after the final map is the winner...
can't believe that's the way to do it. I thought about that but it just seemed to involved, especially for day 5

potetm13:12:17

But yeah, starting at the end and working with ranges until you get to a seed number is basically the approach.

potetm13:12:25

Only fun part of my solutions is that I successfully used tree-seq (maybe for the first time ever).

potetm13:12:50

And it still runs in .5ms after warmup

oyakushev13:12:42

To me, walking from the beginning was easier.

oyakushev13:12:54

Actually, I haven't understood yet how working in reverse works:)

potetm13:12:58

Isn't the only way to do that to get lucky?

potetm13:12:27

You can start from anywhere in the beginning and end up anywhere at the end. There's no uniform distribution so even binary searching is out.

potetm13:12:52

Or you just plan to exhaustively search the entire tree?

oyakushev13:12:14

Don't need any search if you recompute destination ranges step by step.

potetm13:12:32

If that's the case, backwards is the literal same as forwards except you've started in a better spot.

oyakushev13:12:43

You start with ranges of seed numbers, and given a mapping of seed->soil, you compute soil ranges, and so on

potetm13:12:13

Gotcha. Yeah then backwards is the same except you start with the most likely range (lowest range on the last step)

👍 1
genmeblog16:12:14

Eventually got it working (part-2). Tricky play with intersection of ranges. Probably can be done simpler, but... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day05.clj edit: refactored

Ivana18:12:45

(defn split-interval [[b e] m]
  (let [ps (->> m
                (mapcat (fn [[_ s l]] [s (+ s l)]))
                (filter #(and (< b %) (<= % e)))
                sort
                dedupe
                (mapcat (fn [i] [(- i 1) i])))]
    (partition-all 2 (concat (cons b ps) [e]))))

(defn m-get [m v]
  (if-let [[d s _] (->> m (filter (fn [[_ s l]] (<= s v (+ s l -1)))) first)]
    (+ d (- v s))
    v))

(defn process-intervals [intervals m]
  (let [splitted (reduce (fn [acc iv] (into acc (split-interval iv m))) [] intervals)]
    (map (fn [iv] (map #(m-get m %) iv)) splitted)))

(let [[seeds & path] (->> (str/split input #"\n\n")
                          (map str/split-lines))
      to-vec (fn [s] (read-string (str "[" s "]")))
      seeds (-> seeds first (str/split #"\:" 2) second to-vec)
      path (->> path (map #(->> % rest (mapv to-vec))))
      go (fn [intervals] (reduce process-intervals intervals path))]
  (->> seeds
       (partition-all 2)
       (map (fn [[b l]] [b (+ b l -1)]))
       go
       (map first)
       (apply min)))
5.2: 18 msec

Max20:12:06

I ended up with two different solutions: I successfully solved pt1 https://github.com/maxrothman/advent-of-code/blob/main/2023/clj2023/src/clj2023/day5.clj#L185 but it was too slow to actually run on the real data. I also did https://github.com/maxrothman/advent-of-code/blob/main/2023/clj2023/src/clj2023/day5.clj#L216 and 2 with interval sets/maps, and my solution for pt2 ended up being a https://github.com/maxrothman/advent-of-code/blob/main/2023/clj2023/src/clj2023/day5.clj#L335

alekszelark16:12:27

Rewrote the solution with my namespace to work with ranges. Now I’m satisfied with it completely https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_05.clj

elken07:12:05

FYI https://www.reddit.com/r/adventofcode/comments/18an94z/psa_dont_share_your_inputs_even_in_your_github/ Mitigation: git filter-branch --tree-filter 'rm -f resources/inputs/*/day*.txt' HEAD(adjust regex as needed) to remove all the files from all commits If you need them in a build process or automation • Create a private repo with them all in • Add it as a submodule back in the same place • Generate an SSH keypair ssh-keygen -t rsa -b 4096 -C "Fake Deployment Key" -f 'gha_deploy_key' -N '' • Put the contents of gha_deploy_key.pub as a deploy key on the private repo • Put the contents of gha_deploy_key as a secret called SSH_KEY on the aoc repo • Adjust the checkout actions like so https://github.com/elken/aoc/commit/385c29b99ed5a6e567abaf282427bd7e6165a23e

🤯 2
gratitude-thank-you 1
maleghast08:12:30

I had no idea, I always assumed that the input data is / was the same for all participants.

elken08:12:40

Nah there's a (generous) fixed amount, if it was the same for everyone you could just copy the answers 😄

maleghast08:12:24

Right, but I am (despite previously expressed frustrations) much more interested in solving the puzzles than having all 50 stars or makling the leaderboard, so honestly that never occurred to me until you said it just now...

maleghast08:12:53

Also, what incentive would anyone have in sharing the answers if there was only 1 canonical input?

elken08:12:13

Some people take gaming the leaderboard very seriously 😄 There's a good amount of people using chatgpt to get super high. > Also, what incentive would anyone have in sharing the answers if there was only 1 canonical input? Same reason anyone lets anyone else cheat or copy off them 😄

maleghast08:12:36

Yeah, I am sorry it defeats me - there is no up-side to wining by cheating; you always have to live with yoursel fand you know you cheated so it accomplishes nothing.

maleghast08:12:12

Also, I really hate the idea of people using ChatGPT / Bard to win this - makes a mockery of the effort the organiser puts into it.

CarnunMP09:12:16

Huh, I also had no idea!

thom11:12:19

This just appears to be them saying please, is there any legal force behind it? It’s a very silly thing to ask and I’m not going to go and expunge several years of data (which also makes the repos less useful to me and anyone that stumbles on them). Can I feel okay karmically I bought a mug one year? :P

elken11:12:52

Some legal, very little. It's more of a gentlemanly thing to do, because you could technically get the same input as someone else and steal the answers to cheat (yes, there are other ways to cheat)

pez11:12:47

It has never occurred to me to store my input data locally in a file.

pez11:12:34

I have this:

(ns pez.aoc-2023.util
  (:require [clj-http.client :as client]
            [clojure.edn :as edn]
            [clojure.string :as string]))

(defn- fetch-input' [day]
  (try
    (let [cookie (slurp ".aoc-session")]
      (:body (client/get
              (str "" day "/input")
              {:cookies {"session" {:value cookie}}})))
    (catch Exception e
      (println "Ho, ho, ho! Did you forget to populate `.aoc-session` with your AOC session cookie?")
      (throw e))))

(def fetch-input
  (memoize fetch-input'))

(comment
  (def day 6)
  (map edn/read-string (string/split-lines "1,2\n2")))

(defn lines [day]
  (-> (fetch-input day)
      (string/split-lines)))

(defn values [day]
  (map edn/read-string
       (lines day)))

pez11:12:56

The cookie lives for very long.

pez11:12:36

Ah, will add.

1
elken11:12:59

Not a major deal, but in the future he might add in some user-agent filtering to block automated requests 😄

thom11:12:41

I’ve always just written my final answers as tests so I can experiment with faster implementations, and I like the builds being reproducible. Going and doing all the auth rigmarole seems a faff and will break at some point. I dunno, I politely decline to stop storing the inputs. I will go buy a T-shirt to assuage my guilt.

pez11:12:19

Updated fetch function:

(defn- fetch-input' [day]
  (try
    (let [cookie (slurp ".aoc-session")]
      (:body (client/get
              (str "" day "/input")
              {:cookies {"session" {:value cookie}}
               :headers {"User-Agent" "PEZ's AOC dabblings, by  [email protected]"}})))
    (catch Exception e
      (println "Ho, ho, ho! Did you forget to populate `.aoc-session` with your AOC session cookie?")
      (throw e))))

💯 1
elken11:12:37

Yeah I write mine in clerk notebooks that get compiled to a static site so I had to add in the keys step, but honestly it's a 10 second job. No major deal, he's not gonna send the lawyers after us 😄

maleghast12:12:37

I just use a private Github Repo - I make my solutions public via Gist WITHOUT the inputs.

jkxyz13:12:49

The benefits of including the inputs in my repo seem to outweigh the benefits of protecting the maybe non-existent copyright of some randomly-generated numbers. Since it's not harmful to share them, I never assumed it would be a problem

pez13:12:27

The creator of AOC thinks that if enough inputs are sourced, someone else can put up a copy of AOC, and that worries him to no end. Enough reason for me to not contribute to input data being made available.

norman14:12:24

I'm sympathetic, but I don't think it's reasonable to ask participants to leave a critical piece of data out of their repositories. I no longer add the puzzle text to my repo, for reasons of copyright. I suppose at some point I might try one of the solutions here, but it seems like a lot of extra work for something that both actively makes my aoc experience worse and that I don't believe provides any actual benefit to aoc.

jkxyz14:12:57

It seems like Eric (the creator) tweeted a while ago that it's "probably fine": https://nitter.net/ericwastl/status/1465805354214830081 Doesn't seem like a strong condemnation. So I will probably just keep the inputs alongside my code. I also can't understand the reasoning that it makes it that much easier to clone the site or why anyone would want to do that. It would be nice to be able to clone the repo in 5 years and be able to run the code on something that explains why I went to all the effort to avoid those heap space errors

pez14:12:58

“Probably fine” was not about the inputs, but about answer.

jkxyz14:12:40

You're right, I misread the sentence

pez14:12:52

TIL about nitter. Very nice!

genmeblog14:12:55

I decided to keep inputs in encrypted h2 KV store (JVM). If anyone is interested getter and setter functions are https://github.com/genmeblog/advent-of-code/blob/master/src/common.clj#L8-L33.

Samuel Ludwig16:12:42

for those wondering if Hanukkah of Data will make a return this year, I have reason to believe it will, I see saulpw mentioning it in his Discord server

Chase03:12:17

Thanks for the heads up on this Hanukkah of Data challenge. This was my first time hearing about it and it did start today. It was quite fun and definitely has an AOC vibe https://hanukkah.bluebird.sh/5784/

Chase03:12:12

the animated ascii text art is quite nice too

Chase03:12:17

Thanks for the heads up on this Hanukkah of Data challenge. This was my first time hearing about it and it did start today. It was quite fun and definitely has an AOC vibe https://hanukkah.bluebird.sh/5784/