adventofcode

2024-12-07T14:55:02.247699Z

wonderful numbers that are too big for longs...

roklenarcic 2024-12-07T17:42:41.142119Z

Hasn’t been the case for me. You can try using autopromoting operators

Guy Geva 2024-12-07T17:31:54.761999Z

I'm approaching day6's question today, and I had inspiration to visualize my solution (both to learn it for debugging and as an additional challenge.) Does anyone have recommendations for what to use for stuff like that?

roklenarcic 2024-12-07T17:41:24.887649Z

https://github.com/mabe02/lanterna

roklenarcic 2024-12-07T17:41:33.666989Z

if you want text gui πŸ™‚

roklenarcic 2024-12-07T17:41:48.789329Z

The first is a low level terminal interface which gives you the most basic control of the terminal text area. You can move around the cursor and enable special modifiers for characters put to the screen. You will find these classes in package com.googlecode.lanterna.terminal.

Guy Geva 2024-12-07T17:41:51.571039Z

Yeah I know that one, it's really neat

Guy Geva 2024-12-07T17:42:15.412399Z

I picked up quil for now, although lanterna probably fits my needs a bit more

Maravedis 2024-12-07T17:49:12.409589Z

Didn't know Lanterna. Imma try it out. Thanks for the link !

bhauman 2024-12-07T18:39:18.770149Z

well now I’m curious

Guy Geva 2024-12-07T19:21:43.623689Z

Progress: Should have probably forced everything to be squares. but I might change that later I fed it the initial state, now to implement moving the guard and then feeding that into the visualization

πŸ‘ 1
Guy Geva 2024-12-07T19:48:53.171899Z

πŸ™‚

πŸ”₯ 2
Guy Geva 2024-12-07T20:23:58.381219Z

It seems like for the real input redrawing everything every turn is really slow - but I don't have (or want to create and test) the abstraction layer needed to only redraw the changed squares; So I changed it to only draw the player and not visualize the :visited data, and now it's fast It's still useful drawing everything in the example case

Guy Geva 2024-12-07T20:24:44.536839Z

(Actually I could just store an array of which squares I already visited before last turn, diff it with this turn's list, and only draw these; This might be simple enough)

bhauman 2024-12-07T17:40:36.993199Z

for stuff like this I like text visualizations I know it’s boring but its quick

Guy Geva 2024-12-07T17:41:34.316829Z

What do you use for it? I use clojure-lanterna in my console game, but I'd love to hear about more stuff

bhauman 2024-12-07T17:42:36.340579Z

no libraries just printing text to the screen πŸ˜‰ I’m guessing you want animations

Guy Geva 2024-12-07T17:43:07.794129Z

Makes sense I guess I want animations, I haven't fully decided; I'm just trying cool stuff for now

bhauman 2024-12-07T17:43:33.531679Z

when I do that I just print the individiual steps one after the other

Guy Geva 2024-12-07T17:44:15.466659Z

I saw someone with a rust animation (in bevy_tiled_ecs) and it inspired me to do it myself, since gui/creative is usually my weak suit, and I don't have any idea how to visualize a reduce for example, so it will be a nice challenge

bhauman 2024-12-07T17:44:54.475449Z

it certainly sounds fun πŸ‘

Guy Geva 2024-12-07T17:45:06.484099Z

Well doesn't this sound nice

Guy Geva 2024-12-07T17:45:29.407879Z

Now only the visualization left πŸ™‚

Maravedis 2024-12-07T05:25:06.914809Z

Day 7 - Solutions

Stefan 2024-12-11T10:54:05.132379Z

@benjamin.schwerdtner Very nice solution, thanks for sharing. Soo much nicer than my noob-core-logic solution πŸ˜…

πŸ˜„ 1
Aleks 2024-12-07T08:19:40.788979Z

I always struggle with numbers and math, so my initial solution was pretty naive β€” but at least I liked it! Anyway, inspired by @erdos's solution (the math trick), I decided to rewrite mine as an exercise. Now it runs in 4.9 ms and 6.1 ms for parts 1 and 2, respectively. https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2024/day_07_fast.clj

πŸ‘ 1
Jungwoo Kim 2024-12-07T09:01:29.172389Z

https://github.com/jungwookim/aoc-exercise/blob/master/src/aoc/2024/day7.clj I'm back again and today is a bit of trivial for me compared to past few days.

djanus 2024-12-07T09:53:29.102659Z

Another day of Advent of Bruteforce πŸ˜„ https://codeberg.org/nathell/aoc2024/src/branch/main/src/aoc2024/day7.clj

😁 2
misha 2024-12-07T09:57:28.656979Z

misha 2024-12-07T09:58:29.416269Z

combinatorics/selections was ~12x slower

Maravedis 2024-12-07T10:12:07.364099Z

I mean, is there any other way for today? Isn't today's problem some kind of NP-complete problem that is unsolvable unless you literally try everything?

misha 2024-12-07T10:16:54.087469Z

Maravedis 2024-12-07T10:22:44.051749Z

Stole @misha’s idea, now code runs in 500ms. Damn.

🀝 1
misha 2024-12-07T11:19:07.089979Z

rearranging ops inside juxt seems to give another 5-10% speed up: grow numbers faster and remove sooner

2024-12-07T11:30:28.310539Z

A simple solution using recursion, run in about 300ms on my machine: https://github.com/ChrisBlom/advent-of-code/blob/master/src/adventofcode/2024/day07.clj#L60-L82 I found a small optimization (200ms) by pruning branches were the intermediate result is greater than the target

Zach 2024-12-07T12:57:06.483529Z

Is anyone able to ELI5 the math trick? Why is it giving such a fast solution?

erdos 2024-12-07T13:18:13.685729Z

Removing the string operations, I could get it down to 4ms+7ms with clj, 4ms+14ms with babashka: https://github.com/erdos/advent-of-code/blob/master/2024/day07_numeric.clj

πŸ™Œ 1
πŸ™ŒπŸ» 1
Sam Ferrell 2024-12-07T13:24:04.163489Z

I think it's because going backwards, from target to the last value, means that most recursion is conditional and thereby avoided entirely

πŸ‘ 2
tschady 2024-12-07T13:30:43.650939Z

First pass unoptimized:

(ns aoc.2024.d07
  (:require
   [aoc.file-util :as f]))

(def input (f/read-int-vectors "2024/d07.txt"))

(defn || [a b] (parse-long (str a b)))

(defn valid? [ops [result & operands]]
  (some #{result}
        (reduce (fn [poss n] (mapcat #(map (fn [op] (op % n)) ops) poss))
                (list (first operands))
                (rest operands))))

(defn solve [ops input]
  (reduce + (map first (filter (partial valid? ops) input))))

(defn part-1 [input] (solve [+ *] input))

(defn part-2 [input] (solve [+ * ||] input))

erdos 2024-12-07T13:41:35.712889Z

@dingelsz3 > Is anyone able to ELI5 the math trick? Why is it giving such a fast solution? Exactly what @mail191 said, but elaborating a bit: Since all operations are reversible, we can move backwards. For example, if we have an equation like 7 OP₁ 11 = 77 (where we want to find operator OP₁), then it is the same as solving 77 OP₁⁻¹ 11 = 7 for OP₁⁻¹ . Similarly, 7 OP₁ 11 OPβ‚‚ 1 = 78 becomes 78 OP₂⁻¹ 1 OP₁⁻¹ 11 = 7. And here comes the optimisation: we only have easily invertible operations: for (*) we have (/) , for (+) we have (-) , and for (concat) we can implement (remove-prefix) . But we want to operate only on positive integers. So if the result of the inverse operation would not be such (eg. a fraction or a negative number), then we can stop the search on that branch.

vncz 2024-12-07T14:21:14.689879Z

Done! Not that bad

Maravedis 2024-12-07T14:54:26.254959Z

Parallelization + math trick (thanks @erdos!) + juxt instead of combinatorics, total run time ends up being 12ms with input parsing for each part included. Not bad, very cool to see every thing people come up with.

2024-12-07T15:29:04.663819Z

My part 2 right now is SLOOOOW. It takes many minutes.

(ns stuartstein777.2024.day7 
  (:require
    [clojure.string :as str]
    [clojure.math.combinatorics :as combo]))

(defn parse-line [line]
  (let [[total values] (str/split line #":")]
    {:total (parse-long total)
     :values (-> (str/trim values)
                 (str/split #" ")
                 (->> (mapv parse-long)))}))

(defn parse []
  (->> "puzzle-inputs/2024/day7"
       (slurp)
       (str/trim)
       (str/split-lines)
       (mapv parse-line)))

(defn comb [m n]
  (parse-long (str m n)))

(defn solve 
    "Takes an equestion of the form [1 \+ 2 \* 3 \+ 4] and returns 13"
    [eq]
  (:total (reduce (fn [{:keys [total op] :as acc} i]
                    (if (or (= i \*) (= i \+) (= i \c))
                      (assoc acc :op i)
                      (condp = op
                        \* (assoc acc :total (* total i))
                        \+ (assoc acc :total (+ total i))
                        \c (assoc acc :total (comb total i))
                        nil (assoc acc :total i))))
                  {:total 0.0 :op nil}
                  eq)))

(defn merge-lists [main-list interleaved-items]
  (let [pairs (interleave main-list interleaved-items)
        remaining (drop (count interleaved-items) main-list)]
    (concat pairs remaining)))

(defn equation-can-be-solved [operators equation]
  (let [perm-count (dec (count (:values equation)))
        operator-permutations (combo/selections operators perm-count)
        equations (map (partial merge-lists (:values equation)) operator-permutations)]
    (reduce (fn [_ eq]
              (if (= (solve eq) (:total equation))
                (reduced (:total equation))
                0)) 0 equations)))




(defn part-one []
  (let [input (parse)]
    (->> (map (partial equation-can-be-solved [\+ \*]) input)
         (reduce +))))

(defn part-two []
  (let [input (parse)]
    (->> (map (partial equation-can-be-solved [\+ \* \c]) input)
         (reduce +))))

(part-one) ; 6083020304036
(part-two) ; 59002246504791

Maravedis 2024-12-07T15:31:28.096149Z

I think your generate-permutations is equivalent to combo/selections

2024-12-07T15:32:36.804599Z

πŸ‘ Thanks, you are right, it is. I never noticed that function πŸ™‚

Felipe 2024-12-07T15:40:44.081849Z

part 2 takes 15 seconds 😒

tschady 2024-12-07T15:44:49.466699Z

every year I re-learn reversing the input is usually much faster, thinking about how he might create the problems/inputs it makes sense.

πŸ‘ 2
πŸ’― 1
Felipe 2024-12-07T15:45:56.144059Z

hah, very cool math trick to get the optimized version today. thanks for the explainer, @erdos

bhauman 2024-12-07T15:51:24.794219Z

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

bhauman 2024-12-07T15:55:32.529129Z

(defn ev [[res init & args] ops]
  (= res
     (reduce (fn [acc [op n]] (op acc n)) init (map vector ops args))))

(defn solvable? [possible-ops calib]
  (->> (combo/selections possible-ops (- (count calib) 2))
       (filter #(ev calib %))
       first))

;; part 1
#_(->> (filter (partial solvable? [+ *]) input)
       (map first)
       (reduce +))

Ingy dΓΆt Net 2024-12-07T21:07:21.742229Z

#yamlscript Part 2:

2024-12-08T00:00:01.792669Z

OK. I'm pretty drunk. But I do NOT understand this reversing math trick:confounded:

Ingy dΓΆt Net 2024-12-08T00:01:02.399569Z

More drinks!

Apple 2024-12-08T03:50:23.472759Z

less than 2s. not bad. (def input #(slurp (format "resources/2024/%02d" %))) (defn func1 [s] (->> (re-seq #"\d+" s) (mapv parse-long))) (time(doall(let [data (->> (input 7) (re-seq #".+") (map func1)) f (fn [a b] (parse-long (str a b)))] (for [ops [[+ *] [+ * f]]] (->> (for [[sum & nums] data :when (some #{sum} (reduce (fn [accu n] (for [a accu o ops] (o a n))) [(first nums)] (rest nums)))] sum) (reduce +))))))

Apple 2024-12-08T03:53:00.711339Z

erdos's great solution of course. only 8ms. whopping increase in terms of %. (time(let [data (->> (input 7) (re-seq #".+") (map func1)) round-up-to-nearest-power-of-10 #(let [x (long (Math/pow 10 (Math/ceil (Math/log10 %))))] (if (= x %) (* x 10) x)) f (fn f [g [n & n*]] (if (seq n*) (or (if (= 0 (rem g n)) (f (/ g n) n*)) (if (>= g n) (f (- g n) n*)) (let [x (round-up-to-nearest-power-of-10 n)] (if (= n (mod g x)) (f (quot g x) n*)))) (= g n)))] (->> (for [[goal & nums] data :when (f goal (reverse nums))] goal) (reduce +))))

Maravedis 2024-12-07T05:26:44.981159Z

Nothing transcendent today, just a pure bruteforce on the possible operations. Thanks clojure.math.combinatorics . This is incredibly slow but πŸ€·β€β™‚οΈ EDIT: added some parallelization. Runs in about 5s on my 10 yo laptop. Good enough for me.

πŸ™Œ 1
πŸ™ŒπŸ» 1
2024-12-07T05:30:36.188799Z

https://gitlab.com/maximoburrito/advent2024/-/blob/main/src/day07/main.clj I wrote part1 evaluation backwards and had to reverse the input. But that didn't work for part 2 so I had to rewrite it for that. It's slow, but it gets the job done

πŸ’― 1
Sam Ferrell 2024-12-07T05:35:23.765219Z

Quick and dirty recursion, takes about 1.8s in bb and 400ms in clj

πŸ‘Œ 4
Maravedis 2024-12-07T05:36:33.421539Z

Oh man, this is way faster than what I did x)

Sam Ferrell 2024-12-07T05:46:01.335519Z

Ermm maybe I miscounted, its about 50s -_- I think I can get it down significantly though Edit: Down to 2.6s, no memoization

Sam Ferrell 2024-12-07T05:46:30.714789Z

I don't really need all these sets...

erdos 2024-12-07T05:47:02.811609Z

with memoize a small trick i could bring it down to 11ms and 30ms https://github.com/erdos/advent-of-code/blob/master/2024/day07.clj (could be faster with fewer string operations)

3
6
⚑ 1
Maravedis 2024-12-07T05:50:30.883419Z

That reversal of operations is diabolically clever, damn.

Zach 2024-12-07T05:51:16.432729Z

Saw the extra operator coming from a mile away so it only took a minute for the second solution 😎 On another note, I've been solving the problems this year on pen and paper before running any code. Anyone doing the same?

rjray 2024-12-07T05:51:29.023819Z

https://github.com/rjray/advent-2024-clojure/blob/master/src/advent_of_code/day07.clj I imagine my solution looks a lot like most of them. Ran fast enough, for now. Tomorrow I'll clean it up so that there is less duplication of code. I might also run the lines in parallel for speed.

rjray 2024-12-07T06:25:16.254879Z

Couldn't resist shortening the code, removing the duplicate parts: https://github.com/rjray/advent-2024-clojure/blob/master/src/advent_of_code/day07bis.clj Runs about the same speed as before, since none of the changes are optimizations. I'll look at some other solutions tomorrow and see if I can squeeze out some performance.

Andrew Byala 2024-12-07T07:10:16.369759Z

I like my solution because I finally got to use my depth-first search function in my utilities namespace. Give it a starting search space, a predicate to check if you've found the answer, and a function to create new values for the search space, and let it do its thing. Ended up with a pretty small solution that executes in just over a second for part 2. β€’ Blog: https://github.com/abyala/advent-2024-clojure/blob/main/docs/day07.md β€’ Source: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day07.clj

πŸ‘ 1
πŸ‘πŸ» 1
ghaskins 2024-12-24T16:52:41.801779Z

https://github.com/ghaskins/adventofcode/blob/main/src/aoc/2024/day7.clj

(time (part1))
"Elapsed time: 60.083042 msecs"
=> 20281182715321
(time (part2))
"Elapsed time: 3547.072666 msecs"
=> 159490400628354

ghaskins 2024-12-24T17:40:51.543139Z

Enjoying the thread on the optimizations. I get the pruning approach. Still trying to grok the reverse inputs concept

carnundotcom 2024-12-08T11:20:04.884579Z

Was real fun reading this thread after my own efforts. I was kicking myself! (But, then, I knew what I was doing. I chose flame graphs over back to the drawing board...) πŸ˜„ https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2024/d7.clj

genmeblog 2024-12-08T20:21:05.364949Z

My first approach yesterday was so slow (fully combinatorics approach). So after some thinking about early cut search branches I come with much faster one. Still 1sec on part-2. However I'm happy with really low number of LOC: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2024/day07.clj

🀩 1
Benjamin 2024-12-10T13:30:49.082329Z

https://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2024/day7_core_logic.clj probably just the same as using recursion.

ghaskins 2024-12-29T16:18:01.397699Z

@erdos https://github.com/ghaskins/adventofcode/commit/e95e7391a55ab35d00140922b4329ee122aabd0f My mind was blown by your solution there. I had never thought about using recursion in this way to conditionally cache partial solutions. Brilliant.

πŸ‘ 1