adventofcode

Maravedis 2024-12-03T05:22:14.692819Z

Day 3 - Solutions

Maravedis 2024-12-03T05:22:22.151699Z

(defn part1 [path]
  (->> (u/read-file-list path #(re-seq #"mul\((\d{1,3}),(\d{1,3})\)" %))
       (apply concat)
       (reduce (fn [acc [_ x y]] (+ acc (* (parse-long x) (parse-long y)))) 0)))

(defn part2 [path]
  (loop [[[h1 h2 h3] & t] (->> (u/read-file-list path #(re-seq #"mul\((\d{1,3}),(\d{1,3})\)|do\(\)|don't\(\)" %))
                               (apply concat))
         enabled          true
         acc              0]
    (if (nil? h1)
      acc
      (cond (= h1 "do()") (recur t true acc)
            (= h1 "don't()") (recur t false acc)
            :else (recur t enabled (if enabled (+ acc (* (parse-long h2) (parse-long h3))) acc))))))
https://github.com/Maravedis/advent_code/blob/master/src/advent_of_code/2024/03.clj

2024-12-03T05:30:35.823349Z

https://gitlab.com/maximoburrito/advent2024/-/blob/main/src/day03/main.clj?ref_type=heads newlines ... regexp.... grrr...

2024-12-03T05:34:24.638919Z

Also, re-seq... It's amazing what you forget about some times πŸ™‚

Maravedis 2024-12-03T05:35:10.804309Z

re-seq is our lord and savior.

πŸ’― 2
πŸ™ 2
Noah Moss 2024-12-03T05:35:31.123339Z

(def parsed-ops (re-seq #"mul\((\d{1,3}),(\d{1,3})\)|do\(\)|don't\(\)" data))

(:sum
 (reduce
  (fn [{:keys [enabled sum] :as acc} [operation s1 s2]]
    (case operation
      "don't()" {:enabled false :sum sum}
      "do()"    {:enabled true :sum sum}
      ;; default must be mul
      (if enabled
        (assoc acc :sum (+ sum (* (parse-long s1) (parse-long s2))))
        acc)))
  {:enabled true
   :sum 0}
  parsed-ops))

Maravedis 2024-12-03T05:36:14.711359Z

@norman Also if you check out my utils file, re-pos is amazing for niche cases that are bound to pop up, usually by day 15.

Andrew Byala 2024-12-03T05:55:11.094759Z

I'm rather proud of my tiny little solution! β€’ Blog: https://github.com/abyala/advent-2024-clojure/blob/main/docs/day03.md β€’ Source: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day03.clj

πŸ™Œ 3
πŸ™ŒπŸ» 1
Maravedis 2024-12-03T05:58:36.125279Z

Very elegant, you should be proud!

Zach 2024-12-03T06:42:25.709759Z

It's not the most elegant but it works πŸ˜„

;; ## Day 3
(def program-text
  ( 3))

;; ### Part 1
(defn parse-mul [text]
  (->> text
       (re-seq #"mul\((\d{1,3})\,(\d{1,3})\)")
       (map rest)
       (map #(map parse-long %))))

(defn D3P1 [text]
  (transduce
   (mapply *)
   +
   (parse-mul text)))

(tests
 (parse-mul "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))") := '((2 4) (5 5) (11 8) (8 5))
 (D3P1 "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))") := 161)


;; ### Part 2
(def re-instr-mul
  #"mul\(\d{1,3}\,\d{1,3}\)")

(def re-instr-do
  #"do\(\)")

(def re-instr-dont
  #"don't\(\)")

(defn parse-token [token]
  (cond
    (re-matches re-instr-mul token)
    (vec (concat [:mul] (->> token (re-seq #"\d+") (map parse-long))))

    (re-matches re-instr-do token)
    [:do]

    (re-matches re-instr-dont token)
    [:dont]))

(defn tokenize [program]
  (->> program
       (re-seq (re-pattern (format "%s|%s|%s" re-instr-mul re-instr-do re-instr-dont)))
       (map parse-token)
       (vec)))

(defn D3P2 [program]
  (loop [tokens (tokenize program)
         acc 0
         active? true]
    (if (empty? tokens) acc
        (let [[op & args] (first tokens)]
          (case op
            :mul
            (if active?
              (recur (rest tokens) (+ acc (apply * args)) active?)
              (recur (rest tokens) acc active?))

            :do
            (recur (rest tokens) acc true)

            :dont
            (recur (rest tokens) acc false))))))

(tests
 (tokenize "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))") := [[:mul 2 4] [:dont] [:mul 5 5] [:mul 11 8] [:do] [:mul 8 5]]
 (D3P2 "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))") := 48)

Aleks 2024-12-03T06:48:07.848549Z

Hi all! https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2024/day_03.clj

πŸ‘Œ 3
πŸ™Œ 4
2024-12-03T07:13:23.012849Z

I thought part 2 should be simple: Remove everything from don't() to do() or string end, but my Regex foo fails me. And I’m not using an LLM, my go to regex adviser, so just trying to get along with search engine + stack overflow + regex101. Why doesn’t this work?

(-> input
    (str/replace #"don't\(\).*?do\(\)" "") ;; remove don'ts to first do's
    (str/replace #"don't\(\).*" ""))       ;; remove 'dangling' don't

Andrew Byala 2024-12-03T07:13:48.522379Z

Very clever move for part 2, @zelark. I need to figure out exactly how that regex is working, but I get what you're doing.

2024-12-03T07:13:52.547249Z

I could just steal @zelark regex, that looks more sophisticated πŸ˜„

Maravedis 2024-12-03T07:31:24.597129Z

@trost.mario regarding your regex, I think it works for each line, but are you sure you're keeping the state in-between each line? That's the only thing I can think of that would break this.

Aleks 2024-12-03T07:47:42.719009Z

@abyala (?s) enables dotall mode. In dotall mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators. \Z stands for the end of the input.

Ben Sless 2024-12-03T07:51:01.410169Z

(ns day3
  (:require
   [ :as io]))

(def sample
  "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")

(def pat #"mul\((\d{1,3}),(\d{1,3})\)")

(defn find-matches
  ([sample]
   (find-matches sample pat))
  ([sample pat]
   (let [m (re-matcher pat sample)]
     (loop [v []]
       (if (.find m)
         (recur (conj v (.group m)))
         v)))))

(def matches
  (find-matches sample))

(defn calculate1
  [matches]
  (reduce +
          (map (fn [s]
                 (let [[_ n m] (re-find pat s)]
                   (* (parse-long n) (parse-long m))))
               matches)))
(calculate1 (find-matches sample))
;; => 161

(def input
  (->> "input/3"
       io/resource
       slurp))

(calculate1 (find-matches input))
;; => 157621318

(def sample2 "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")
(def pat2 #"mul\((\d{1,3}),(\d{1,3})\)|do\(\)|don't\(\)")
(find-matches sample2 pat2)
(def tokens (find-matches input pat2))

(defn find-active-tokens
  [tokens]
  (loop [[head & tokens] tokens
         active true
         acc []]
    (if head
      (condp = head
        "don't()" (recur tokens false acc)
        "do()" (recur tokens true acc)
        (recur tokens active (if active (conj acc head) acc)))
      acc)))

(calculate1 (find-active-tokens (find-matches sample2 pat2)))
;; => 48

(calculate1 (find-active-tokens (find-matches input pat2)))
;; => 79845780

Ben Sless 2024-12-03T07:52:09.549639Z

@malaingreclement TIL re-seq πŸ™

2024-12-03T07:57:26.203939Z

@malaingreclement thanks, that was it πŸ™ Prefixing (?s) to each regex gave the right result

(ns aoc.2024.day03
  (:require
   [clojure.string :as str]))

(def test-input "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")

(def input (slurp "src/aoc/2024/day03"))

(defn parse-input [input]
  (re-seq #"mul\(\d+,\d+\)" input))

(count (parse-input input))

(defn mult [l]
  (apply * (map parse-long l)))

;; part 1
(transduce
 (comp (map #(re-seq #"\d+" %))
       (map mult))
 +
 (parse-input input))))

; part 2
(transduce
 (comp (map #(re-seq #"\d+" %))
       (map mult))
 +
 (parse-input (-> input
                  (str/replace #"(?s)don't\(\).*?do\(\)" "")
                  (str/replace #"(?s)don't\(\).*" ""))))

Ben Sless 2024-12-03T07:57:56.587999Z

Much nicer with re-seq

(ns day3
  (:require
   [ :as io]))

(def sample
  "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")

(def pat #"mul\((\d{1,3}),(\d{1,3})\)")

(defn calculate1
  [matches]
  (reduce +
          (map (fn [[_ n m]]
                 (* (parse-long n) (parse-long m)))
               matches)))

(calculate1 (re-seq pat sample))
;; => 161

(def input
  (->> "input/3"
       io/resource
       slurp))

(calculate1 (re-seq pat input))
;; => 157621318

(def sample2 "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")
(def pat2 #"mul\((\d{1,3}),(\d{1,3})\)|do\(\)|don't\(\)")

(defn sum-active
  [tokens]
  (loop [[[head n m] & tokens] tokens
         active true
         acc 0]
    (if head
      (condp = head
        "don't()" (recur tokens false acc)
        "do()" (recur tokens true acc)
        (recur tokens active (if active (+ acc (* (parse-long n) (parse-long m))) acc)))
      acc)))

(sum-active (re-seq pat2 sample2))

(sum-active (re-seq pat2 input))
;; => 79845780

Sam Ferrell 2024-12-03T08:39:41.512699Z

just a loop with a flag

Kathryn Isabelle Lawrence 2024-12-03T08:53:03.005689Z

easier than yesterday's, this should have been day 2! https://github.com/lawreka/aoc24/blob/master/src/aoc24/3.clj

2024-12-03T09:01:49.113049Z

(ns stuartstein777.2024.day3
  (:require [clojure.string :as str]))

;; part 1
(defn parse [mul]
  (->> (re-seq #"\d+", mul)
       (map parse-long)))

(->> "puzzle-inputs/2024/day3"
     (slurp)
     (re-seq #"mul\(\d+,\d+\)")
     (map parse)
     (map #(reduce * 1 %))
     (reduce +)) ;; 174960292

;; part 2
(defn reducer [{:keys [doing total] :as acc} {:keys [instr values] :as i}]
  (cond (= :mul instr) 
        (if doing
          (assoc acc :total (+ total (reduce * 1 values)))
          acc)
        (= :do instr)  (assoc acc :doing true)
        (= :dont instr) (assoc acc :doing false)))

(defn parse2 [instr]
  (cond
    (str/starts-with? instr "mul")    {:instr :mul :values (->> (re-seq #"\d+", instr)
                                                                (map parse-long))}
    (= instr "don't()")               {:instr :dont :values []}
    (= instr "do()")                  {:instr :do :values []}))

(->> "puzzle-inputs/2024/day3"
     (slurp)
     (re-seq #"mul\(\d+,\d+\)|don't\(\)|do\(\)")
     (map parse2)
     (reduce reducer {:doing true, :total 0})) ;; {:doing true, :total 56275602}

dazld 2024-12-03T10:41:30.539689Z

Not the most elegant, but felt like solution was quite expressive and easy to read. https://github.com/dazld/aoc2024/blob/main/src/aoc03.clj (congrats on the solutions above though, beautiful stuff!)

(defn part2 [input]
  (loop [remaining input
         multiply? true
         total 0]
    (if (empty? remaining)
      total
      (let [do-match   (re-find #"^do\(\)" remaining)
            dont-match (re-find #"^don\'t\(\)" remaining)
            ops-match  (re-find #"^mul\(\d+,\d+\)" remaining)]
        (cond
          do-match (recur (subs remaining (count do-match))
                          true
                          total)
          dont-match (recur (subs remaining (count dont-match))
                            false
                            total)
          (and ops-match multiply?)
          (let [[a b] (->> (re-seq #"\d+" ops-match)
                           (map parse-long))
                next-total (+ total (* a b))]
            (recur (subs remaining (count ops-match))
                   multiply?
                   next-total))
          :else
          (recur (subs remaining 1) multiply? total))))))
Are we in regex land now? I suck so badly with them πŸ˜„

Daniel Galvin 2024-12-03T10:48:02.727289Z

Tried to go for something simple, took me a moment to remember regex . doesnt match \n by default Also i think i can add groups to re-seq avoiding having to re-seq each command extracted. think_beret

(defn execute-mul [command]
  (->> command
       (re-seq #"\d+")
       (map parse-long)
       (reduce *)))

(def day3-input (slurp "resources/aoc2024/day3.txt"))

(defn task1 []
  (transduce (map execute-mul) + (re-seq #"mul\(\d+,\d+\)" day3-input)))

(defn task2 []
  (let [clean-input (str/replace day3-input #"(?s)don't\(\).*?do\(\)" "")]
    (transduce (map execute-mul) + (re-seq #"mul\(\d+,\d+\)" clean-input))))
REVISED
(defn execute-mul [[_ d1 d2]]
  (* (parse-long d1) (parse-long d2)))

(defn process [input]
  (->> (re-seq #"mul\((\d+),(\d+)\)" input)
       (transduce (map execute-mul) +)))

(def day3-input (slurp "resources/aoc2024/day3.txt"))

(defn task1 []
  (process day3-input))

(defn task2 []
  (process (str/replace day3-input #"(?s)don't\(\).*?do\(\)" "")))

πŸ™Œ 4
2024-12-03T10:52:36.228259Z

Straight forward loop for both parts:

(defn solve [input part]
  (let [ops (re-seq #"mul\(\d+,\d+\)|do\(\)|don't\(\)" input)
        mul #(apply * (map read-string (re-seq #"\d+" %)))]
    (loop [[op & xs] ops, enabled true, sum 0]
      (if (nil? op) sum
          (condp = op
            "do()"    (recur xs true sum)
            "don't()" (recur xs false sum)
                      (recur xs enabled (cond-> sum (or enabled (= part 1)) (+ (mul op)))))))))

Jungwoo Kim 2024-12-03T10:53:01.625629Z

https://github.com/jungwookim/aoc-exercise/blob/master/src/aoc/2024/day3.clj again regex.

Aneesh Mulye 2024-12-03T11:37:30.058619Z

(defn p2-1 [fname]
  (let [f (slurp fname)
        muls (re-seq #"mul\((\d+),(\d+)\)" f)]
    (reduce
      (fn [sum [_ s1 s2]]
        (+ sum (* (parse-long s1) (parse-long s2))))
      0
      muls)))

(defn p2-2 [fname]
  (let [f (slurp fname)
        muls (re-seq #"mul\((\d+),(\d+)\)|do\(\)|don't\(\)" f)]
    (reduce
      (fn [[do? sum] [p s1 s2]]
        (case p
          "do()" [true sum]
          "don't()" [false sum]
          [do? (+ sum
                  (if do? (* (parse-long s1) (parse-long s2)) 0))]))
      [true 0]
      muls)))
Pretty straightforward today; IDK if it's 'cheating' to use the in-built regex facilities, which far as I can tell almost trivialise this problem.

tschady 2024-12-03T12:01:00.593809Z

newline regex bit me too. I did it in multiple passes until I stole @zelark’s RE

(def input (f/read-file "2024/d03.txt"))

(defn clean [s] (str/replace s #"(?s)don't\(\).*?(:?do\(\)|\Z)" ""))

(defn execute [mem]
  (transduce (comp (map second) (map s/ints) (map #(apply * %)))
             +
             (re-seq #"mul\((\d+,\d+)\)" mem)))

(defn part-1 [input] (-> input execute))

(defn part-2 [input] (-> input clean execute))

tschady 2024-12-03T12:04:16.611349Z

next time I’ll build the TobogganLang interpreter

marc 2024-12-03T12:12:48.377809Z

I went with reduce + case, in #squint https://is.gd/vQxQT4

❀️ 1
tschady 2024-12-03T12:26:46.882359Z

I missed the 1-3 digit requirement, didn’t seem to affect anything (I used \d+)

2024-12-03T12:44:51.907629Z

@tws, How does your solution only handle muls between dos and donts ? Is that what the clean regex is doing ? ah okay,having a play on regex101. I get it now. It replaces such muls with an empty string so all your left with is the valid stuff. Neat πŸ™‚

πŸ‘ 1
vncz 2024-12-03T12:45:56.600289Z

(ns day3)

(def input (-> "input/3.txt" slurp))

(def sol1 (->> input
               (re-seq #"mul\((\d{1,3}),(\d{1,3})\)")
               (map (fn [[_ a b]] (* (Integer/parseInt a) (Integer/parseInt b))))
               (apply +)))

(def sol2 (->> input
               (re-seq #"mul\((\d{1,3}),(\d{1,3})\)|do\(\)|don't\(\)")
               (reduce (fn [[state sum] [elem a b]]
                         (cond
                           (= "do()" elem) [true sum]
                           (= "don't()" elem) [false sum]
                           (true? state) [state (+ sum (* (Integer/parseInt a) (Integer/parseInt b)))]
                           :else [state sum])) [true 0])))

vncz 2024-12-03T12:46:21.359369Z

This day seemed to be the easiest so far

2024-12-03T12:48:10.210119Z

I really need to get better at regex

Maravedis 2024-12-03T12:49:43.610999Z

https://regexcrossword.com is pretty fun.

vncz 2024-12-03T12:49:50.642449Z

I am relatively surprised to see a lot of solutions using loop

vncz 2024-12-03T12:49:58.589609Z

Everytime there is a loop, reduce can be used instead

Maravedis 2024-12-03T12:51:02.337549Z

Yeah, but when you begin to have more than one state to keep, it becomes a matter of preference. I find it less clean to maintain a map in the accumulator of a reduce.

☝️ 1
Sam Ferrell 2024-12-03T12:51:34.824499Z

https://aphyr.com/posts/360-loopr-a-loop-reduction-macro-for-clojure some reading on this topic

Maravedis 2024-12-03T12:51:47.520129Z

I still use reduce if it's a very large collection, but in that case I use clojure.core.reducer's reduce.

Maravedis 2024-12-03T12:55:20.917499Z

@mail191 Thank you, very cool. Definitely gonna use loopr in the future. Especially for nested reduces.

Sam Ferrell 2024-12-03T12:55:44.860099Z

also reduce cannot completely replace loop in all instances

Felipe 2024-12-03T12:57:28.004479Z

https://github.com/FelipeCortez/advent-of-code/blob/master/2024/03.clj transduce and reduce

Felipe 2024-12-03T12:57:50.536049Z

not sure why my github links aren't unfurling think_beret

Maravedis 2024-12-03T12:59:04.832769Z

You probably set the setting "no preview" in your slack settings

Felipe 2024-12-03T12:59:45.811609Z

nah, I checked.

1
Felipe 2024-12-03T13:03:40.221079Z

wow that don't...do regex replacement is clever!

tschady 2024-12-03T13:14:10.275029Z

string munging works on these early ones, but this problem will likely have extensions to the grammar over many days, a la 2019's intcode interprer

☝️ 1
Daniel Galvin 2024-12-03T13:14:10.458639Z

i wonder if the string replace i do, is slow. matching the do() and don't() in a group and checking the elements during reduction is prolly more efficient, just read a few other solutions here

Sam Ferrell 2024-12-03T13:17:35.209709Z

can't seem to get loopr to compile in bb 😞

Maravedis 2024-12-03T13:20:51.529359Z

I tried it and it works really well in vanilla clojure. Problem is that my IDE screams and bleeds from its eyes because the syntax is unconventional.

Maravedis 2024-12-03T13:21:22.141949Z

I dislike the squiggly red line and I do not have the courage to write a custom clj-kondo hook, so loopr is gonna stay in the closet for now x)

Felipe 2024-12-03T13:38:17.699279Z

@malaingreclement IIRC, if you config :clj-kondo to {:hooks {:macroexpand {my-ns/my-macro hooks.my-ns/my-macro}}}, you can just copy paste the defmacro as it's defined and it will lint correctly

πŸ™ 2
Maravedis 2024-12-03T13:39:49.632889Z

Oh, def keeping this for a rainy day. For now, I just disabled the linters inside loopr. Brutal, but it does the job.

vollcheck 2024-12-03T13:41:11.932859Z

https://github.com/vollcheck/aoc/blob/master/src/y24/day03.clj got exhausted by playing with regex that would be good enough for part-2 so I used dumb loop with split by muls, dos and donts

Zach 2024-12-03T14:04:47.758559Z

@vincenz.chianese what’s the argument for reduce over loop?

2024-12-03T14:07:42.887589Z

I think of it the other way. Every time I see a reduce, I think "there's some code that code be written more clearly using loop". Reduce is sometimes more idiomatic, and it does lend it'self better to using sub-functions that can be independently tested and re-used. But in AOC, loop is almost always the way to go

Maravedis 2024-12-03T14:09:17.260329Z

Well there is an argument for performance. With the deconstruction and the seq wrapping, loop is slower when you're just iterating over one collection. But yeah, I agree, loop is very readable and it's its main appeal imo.

2024-12-03T14:11:02.144679Z

Thankfully we've never had an AOC problem where that would be a factor

Sam Ferrell 2024-12-03T14:15:05.734869Z

if youre just enumerating a collection and accreting one value i think reduce is much more idiomatic. loop is just an ergonomic mechanism for recursion which is broadly applicable to lots of problems. reduce also endures allocation issues when youre accreting a persistent value. i will say it is really easy to mess up termination conditions with more complex loops

Sam Ferrell 2024-12-03T14:16:27.795709Z

theyre not really interchangeable, generally

vncz 2024-12-03T14:18:34.080159Z

@dingelsz3 My primary reason is that it's pure by definition - or at least in 99.9% of the cases. When I see a reduce, I know what the developer is trying to do: Iterate on a collection while accumulating some state and return a value. When I see a loop written by somebody else, it means "oh no, I need to sit down, and read this code to make sure that the developer did not do something shady"

πŸ‘ 2
πŸ‘πŸ» 1
☝️ 1
vncz 2024-12-03T14:19:02.006659Z

Whether that is a persuasive reason or not - up to the team

Maravedis 2024-12-03T14:19:31.021949Z

It's not in my book, but you do you ^^

πŸ‘ 1
Sam Ferrell 2024-12-03T14:19:35.573129Z

do you mean pure of side effects? side effects are possible in both

vncz 2024-12-03T14:20:11.788019Z

@mail191 I am more talking about intentions of the code. I have modified the message

vncz 2024-12-03T14:20:23.356079Z

Side effects are technically possible everywhere, that's true

Andrew Byala 2024-12-03T18:36:25.439089Z

Ok, I went crazy. If anyone wants to learn about making a custom transducer, I just spent entirely too much time talking about how one would make one, and how to make it reusable, and why. The transducer, in this case, is a "thing that pushes values through it unless it's disabled." Hopefully it's an interesting blog post and solution. β€’ Blog post: https://github.com/abyala/advent-2024-clojure/blob/main/docs/day03.md β€’ Second solution with a custom transducer: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day03_transducer.clj

1
πŸ”₯ 2
πŸ˜„ 1
Karl Xaver 2024-12-03T20:49:00.529699Z

Tried to learn Learned some #instaparse today but couldn't figure out how to write a grammar that gets rid of the "garbage" without blowing up the parser. I gave up and added an extra data-cleaning pass, which makes the whole approach feel kinda pointless. Does anyone know how to do it right? I didn't handle the newlines, #'.|\n' fixed it! Thanks to @jcada

(ns day3 
  (:require [instaparse.core :as insta]
            [instaparse.combinators :as c]))

(def example1 "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")
(def example2 "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")

(def part1
  (c/ebnf
   "start   = ops
       = (mul / )*
    corrupt = #'.|\n'
    mul     = <'mul('> number <','> number <')'>
    number  = #'[0-9]{1,3}'"))

(def part2 
  (merge
   part1
   (c/ebnf
    "start   = (do | )+
         = <'do()'>    ops
     dont    = 'don\\'t()' ops")))

(defn solve [grammar input]
  (insta/transform
   {:number parse-long
    :mul    *
    :start  +}
   (insta/parse (insta/parser grammar :start :start) input)))

(solve part1 example1) ;; => 161
(solve part2 (str "do()" example2)) ;; => 48

exitsandman 2024-12-03T21:07:24.254589Z

I got into PEGs for the heck of it and this works, but it's a lot more work than a couple regex!

(ns mini.advent.day3
  (:require
   [mini.advent.util :as util]
   [crustimoney.combinator-grammar :as pg]
   [crustimoney.core :as peg]
   [clojure.walk :as walk]))

(defn single-or-vec [xs]
  (if (= 1 (bounded-count 2 xs))
    (first xs)
    (vec xs)))

(defn implicitly-chain [h xs]
  (list h (single-or-vec xs)))

(def peg-data-notation-shortcuts
  {'(*) (fn expand-* [& xs] (implicitly-chain `pg/repeat* xs))
   '(+) (fn expand-+ [& xs] (implicitly-chain `pg/repeat+ xs))
   '(?) (fn expand-? [& xs] (implicitly-chain `pg/maybe xs))
   '(/) (fn expand-choice [& xs] (cons `pg/choice xs))
   '(!) (fn expand-! [& xs] (implicitly-chain `pg/negate xs))

   '. (constantly `#"(?s).")
   '$ (constantly `(pg/eof))
   '>> (constantly `(pg/hard-cut))
   '> (constantly `(pg/soft-cut))})

(defn is? [p x] (p x))

(defn peg-data-notation
  [frm]
    ;; the library has its own data notation but it's `cl:loop` levels of un-lispy
  (let [shorts peg-data-notation-shortcuts
        rm-ns #(symbol (name %))
        regex? #(instance? java.util.regex.Pattern %)]
    (->> frm
         (walk/prewalk
          (fn [subfrm] 
            (condp is? subfrm
              seq? (if-let [sh (shorts (list (rm-ns (first subfrm))))]
                     (apply sh (next subfrm))
                     subfrm)
              symbol? (if-let [sh (shorts (rm-ns subfrm))]
                        (sh)
                        subfrm)
              subfrm)))
         (walk/postwalk
          (fn [subfrm]
            (condp is? subfrm
              map-entry? subfrm
              seq? (condp is? (first subfrm)
                     symbol? (apply (resolve (first subfrm)) (next subfrm))
                     keyword? (pg/with-name (first subfrm) (single-or-vec (next subfrm)))
                     (throw (ex-info "head of seq must be a symbol or a keyword" 
                                     {:head (first subfrm)})))
              vector? (apply pg/chain subfrm)
              string? (pg/literal subfrm)
              regex? (pg/regex subfrm)
              subfrm))))))

(defn pdn [lit] (peg-data-notation lit))

;; actual problem-solving starts here

(defonce day-3-in (util/aoc-input 3))

(defn *| [to-rep delim] 
  `[(* (! ~delim) ~to-rep) ~delim])

(def grammars
  (pdn
   `{:puzzle-2-grammar-elt (/ :comment :puzzle-1-grammar-elt)
     :comment              ["don't()" ~(*| :ignored `(/ "do()" $))]

     :puzzle-1-grammar-elt (/ :mul-insn :ignored)
     :mul-insn             (:mul-insn ["mul(" :factor "," :factor ")"])

     :factor               (:factor [:digit (? :digit) (? :digit)])
     :digit                #"\d"
     :ignored              .}))

(defn rooted [grammar rule]
  (assoc grammar :root rule))

(def puzzle-1-grammar (peg/compile (rooted grammars (pdn `(* :puzzle-1-grammar-elt)))))
(def puzzle-2-grammar (peg/compile (rooted grammars (pdn `(* :puzzle-2-grammar-elt)))))

(defn subtree 
  [x] (subvec x 2))
(defn realized 
  [[_ {:keys [end start]}] strn]
  (subs strn start end))
;; this bit is reeally rough, surely we can do better than manually walk 
;; the hiccup-notation
(defn eval-parsed-muls
  [grammar input]
  (let [muls (subtree (peg/parse grammar input))
        realized' #(realized % input)]
    (transduce (map (fn eval-mul-insn [mulop]
                      (let [[f1 f2] (map realized' (subtree mulop))]
                        (* (parse-long f1) (parse-long f2)))))
      + muls)))

(def solution-1 (eval-parsed-muls puzzle-1-grammar day-3-in))
(def solution-2 (eval-parsed-muls puzzle-2-grammar day-3-in))
E: I knew I could do a bit better haha
(defn eval-parsed
  ([next-eval rules->evaluators x unparsed]
   (if (set? unparsed)
     (throw (ex-info "errors during parsing" {:errors unparsed}))
     (let [h (x 0) bounds (x 1)
           content (delay (let [{:keys [start end]} bounds]
                            (subs unparsed start end)))
           subtree (subvec x 2)]
       ((or (rules->evaluators h) (rules->evaluators ::default))
        next-eval content subtree)))))

(defn parse-and-eval
  [rules->evaluators grammar unparsed]
  (let [parsed (peg/parse grammar unparsed)]
    (if (set? parsed)
      (throw (ex-info "errors during parsing" {:errors parsed}))
      (letfn [(next-eval [x] (eval-parsed next-eval rules->evaluators x unparsed))]
        (next-eval parsed)))))

(def the-eval-rules
  {:factor (fn eval-factor [_ev ct _st] (parse-long @ct))
   :mul-insn (fn eval-mul-insn [ev _ct st] (transduce (map ev) * st))
   nil (fn eval-root [ev _ct st] (transduce (map ev) + st))})

(def solution-1 (parse-and-eval the-eval-rules puzzle-1-grammar day-3-in))
(def solution-2 (parse-and-eval the-eval-rules puzzle-2-grammar day-3-in))

carnundotcom 2024-12-03T21:43:11.412729Z

Cute one today! https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2024/d3.clj

carnundotcom 2024-12-03T21:47:56.826109Z

+1 for team reduce And missed the regex not matching newlines by default thing because my u/input already splits into lines! So was happy to learn about (?s) from yous, above. :)

bhauman 2024-12-03T22:25:48.922479Z

https://github.com/bhauman/adv2024/blob/main/src/adv2024/day03/sol.clj And another +1 for team reduce Part 2 was fairly brief: (->> (re-seq #"don\'t\(\)|do\(\)|mul\((\d{1,3}),(\d{1,3})\)" input) (reduce (fn [{:keys [doing accum] :as a} [com val1 val2]] (if (nil? val1) (assoc a :doing (= com "do()")) (cond-> a doing (update :accum + (* (parse-long val1) (parse-long val2)))))) {:doing true :accum 0}) )

Ingy dΓΆt Net 2024-12-04T02:58:10.252359Z

Part 2 in #yamlscript:

!yamlscript/v0

enabled =: atom(true)
pattern =: /(?x) (?:mul\((\d+),(\d+)\)
               | (do(?:n't)?)\(\))/

defn main(data): !:say
  sum: data:slurp.re-seq(pattern).map(mul)

defn mul(m):
  cond:
    m.3 == 'do':    reset!(enabled true).!
    m.3 == "don't": reset!(enabled false)
    else: enabled:D.when(m.1:N * m.2:N)
from https://github.com/ingydotnet/advent-of-code/tree/main/2024/03

Ryan Fleck 2024-12-04T05:35:34.947829Z

Part 2, looks very similar to the yamlscript laughcry

(->>
 (s/split day-3-input #"do")
 (filter #(not (s/starts-with? % "n't")))
 (apply str)
 (re-seq #"mul\((\d+),(\d+)\)")
 (map #(* (str->int (nth % 1)) (str->int (nth % 2))))
 (apply +))

2024-12-04T06:15:24.246469Z

+1 for team β€œjust clean up your input, no need for complicated reducing or looping, doesn’t fit in my brain”

ghaskins 2024-12-04T17:06:10.531159Z

I tried with instaparse…it works for both part 1&2 test inputs, but only part 1 passes with real https://github.com/ghaskins/adventofcode/blob/main/src/aoc/2024/day3.clj

(time (part1))
"Elapsed time: 130.3685 msecs"
=> 188741603
(time (part2))
"Elapsed time: 176.123375 msecs"
=> 67269799

bhauman 2024-12-04T17:13:06.627699Z

I’m not familliar with instaparse but does this line <ignore> ::= stop (!start any)* (start | eol) handle the case where you have

bhauman 2024-12-04T17:13:44.261429Z

do() do() do() don't()

ghaskins 2024-12-04T17:14:00.894609Z

I believe so, but I can plug that in

bhauman 2024-12-04T17:14:34.630419Z

or of course the opposite case

ghaskins 2024-12-04T17:14:57.014029Z

the intent of that rule is to match if it starts with dont() and gobbles up everything until it either encounters a do() or EOL

exitsandman 2024-12-04T17:15:02.081009Z

the only case that needs handling is upon meeting don't() . dont't()...do()/EOF is essentially a comment, we don't care about what's inside until we meet a do()

bhauman 2024-12-04T17:15:40.986919Z

so it handles don't() don't() don't() do() ?

ghaskins 2024-12-04T17:17:05.506909Z

i believe so

ghaskins 2024-12-04T17:17:22.556079Z

I just ran this

ghaskins 2024-12-04T17:17:24.431309Z

diff --git a/src/aoc/2024/day3.clj b/src/aoc/2024/day3.clj
index 23f258d..502d5a2 100644
--- a/src/aoc/2024/day3.clj
+++ b/src/aoc/2024/day3.clj
@@ -3,11 +3,11 @@
             [instaparse.core :as insta]))

 (def part1-test "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")
-(def part2-test "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")
+(def part2-test "do() do() do() don't()xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")

 (defn parse
   [start-rule]
-  (let [input (slurp "inputs/day3.txt")]
+  (let [input part2-test]
     (-> (io/resource "day3.ebnf")
         (insta/parser)
         (insta/parse input :start start-rule))))

ghaskins 2024-12-04T17:17:31.317229Z

(part2)
=> 40

Karl Xaver 2024-12-04T17:17:39.044479Z

Just a wild guess: does your code handle the implicit first do()?

πŸ‘ 1
ghaskins 2024-12-04T17:17:42.419879Z

and I believe that is correct, as it elides all but the last 8*5

ghaskins 2024-12-04T17:17:55.255819Z

yes, i believe so

ghaskins 2024-12-04T17:18:08.055199Z

the mul statements are counted until the first dont()

bhauman 2024-12-04T17:18:30.767399Z

and is it parsing completely? like to the end?

ghaskins 2024-12-04T17:19:14.065469Z

That is a good question, though it said my result was too high, so id guess yes

ghaskins 2024-12-04T17:19:24.031809Z

it seems more likely i am not processing a dont in the middle

ghaskins 2024-12-04T17:19:31.579189Z

but let me check that

ghaskins 2024-12-04T17:19:43.814759Z

I tried this, btw

diff --git a/src/aoc/2024/day3.clj b/src/aoc/2024/day3.clj
index 23f258d..4f1b7e4 100644
--- a/src/aoc/2024/day3.clj
+++ b/src/aoc/2024/day3.clj
@@ -3,11 +3,11 @@
             [instaparse.core :as insta]))

 (def part1-test "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))")
-(def part2-test "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")
+(def part2-test "don't()don't()don't()do()xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")

 (defn parse
   [start-rule]
-  (let [input (slurp "inputs/day3.txt")]
+  (let [input part2-test]
     (-> (io/resource "day3.ebnf")
         (insta/parser)
         (insta/parse input :start start-rule))))

ghaskins 2024-12-04T17:19:50.621109Z

and I get 48, which is correct

bhauman 2024-12-04T17:21:18.868509Z

yes well sorry I mean don't()mul(1,5)don't()mul(1,5)don't()mul(1,5)do()mul(1,60)

bhauman 2024-12-04T17:21:36.398949Z

and the opposite

exitsandman 2024-12-04T17:22:16.017259Z

remember that only three digits are allowed in a mul factor, I don't see where the grammar checks that

ghaskins 2024-12-04T17:22:33.085429Z

it computes 60 for that input

ghaskins 2024-12-04T17:22:37.644609Z

which i think is correct

bhauman 2024-12-04T17:22:50.826879Z

that[s it!

ghaskins 2024-12-04T17:22:55.798539Z

@doppiaelle1999 ah!

ghaskins 2024-12-04T17:23:02.945049Z

i mustve of missed the criteria

exitsandman 2024-12-04T17:23:11.451929Z

1-3 digits to be specific

ghaskins 2024-12-04T17:23:40.602669Z

dang it

ghaskins 2024-12-04T17:23:42.435169Z

i missed that

ghaskins 2024-12-04T17:23:49.139819Z

thats almost certainly what is wrong, ty

exitsandman 2024-12-04T17:24:42.737039Z

fwiw my own solution with a PEG looks like:

{:root (* :puzzle-2-grammar-elt) ; added for clarity, same approach for puzzle 1
 :puzzle-2-grammar-elt (/ :comment :puzzle-1-grammar-elt)
 :comment              ["don't()" ~(*| :ignored `(/ "do()" $))]

 :puzzle-1-grammar-elt (/ :mul-insn :ignored)
 :mul-insn             (:mul-insn ["mul(" :factor "," :factor ")"])

 :factor               (:factor [:digit (? :digit) (? :digit)])
 :digit                #"\d"
 :ignored              .}

ghaskins 2024-12-04T17:27:10.012879Z

I added this update, but its still wrong..i need to read the criteria more carefully

ghaskins 2024-12-04T17:27:11.298559Z

diff --git a/resources/day3.ebnf b/resources/day3.ebnf
index 1b54666..a6ce3b1 100644
--- a/resources/day3.ebnf
+++ b/resources/day3.ebnf
@@ -7,7 +7,7 @@ mul ::= (<"mul("> digit <","> digit <")">)
 <stop> ::= <"don't()">
 <start> ::= <"do()">

-<digit> ::= #"\d+"
+<digit> ::= #"\d{1,3}"
 <ws> ::= (!mul any)*
 <aws> ::= (ignore / (!mul !ignore any))*
 <eol> ::= #"$"

ghaskins 2024-12-04T17:30:17.335689Z

and looking through my data file, I dont have any numbers more than 3 digits, so that explains why it didnt help. But it was a good find @doppiaelle1999

ghaskins 2024-12-04T17:30:44.484719Z

I dont spy anything else I missed in the criteria

ghaskins 2024-12-04T17:30:57.148379Z

oh well, it was fun nonetheless.. ty all for helping

exitsandman 2024-12-04T17:42:04.864219Z

@ghaskins does $ match the end of the line or the end of the input?

ghaskins 2024-12-04T17:42:52.729809Z

good question. At the time I wrote the EBNF, I thought the input was all one line…i discovered the newlines when I started testing but I didnt update the language nor confirm that was the intended symbol

ghaskins 2024-12-04T17:42:57.111109Z

let me check that

ghaskins 2024-12-04T17:43:17.499569Z

(technically i want the end of input, i think)

exitsandman 2024-12-04T17:50:43.055649Z

my one-to-one translation from the lib I used to instaparse appears to work on my own input

ghaskins 2024-12-04T17:51:43.352789Z

i assume you mean you’ve tested your PEG ported to instaparse, not that you tested my broken EBNF?

exitsandman 2024-12-04T17:51:52.891759Z

yes I tested my peg

ghaskins 2024-12-04T17:51:55.599529Z

roger

exitsandman 2024-12-04T17:52:15.735979Z

gonna try the other way around lol

ghaskins 2024-12-04T17:52:50.209239Z

if its not too much trouble, if you could run your data input through mine and tell me what you get for your correct answer vs whatever mine generates, thats somewhat helpful

ghaskins 2024-12-04T17:53:19.120589Z

aoc tells me my number is too high, which implies I missed an elision but that is just a guess

ghaskins 2024-12-04T17:53:31.848159Z

im just wondering if I am close

exitsandman 2024-12-04T18:00:59.674419Z

I can't find your input though

ghaskins 2024-12-04T18:01:52.074799Z

oh, i didnt add it to git because I thought we werent allowed to. I was just curious of you running your input though both your program and mine and telling me the difference

ghaskins 2024-12-04T18:02:16.121969Z

i can maybe DM you my input, assuming that doesnt run afoul of AOC

exitsandman 2024-12-04T18:03:12.683279Z

I already have done mine, DM away

exitsandman 2024-12-04T18:04:07.599589Z

btw results are personalized, so it's not very important

exitsandman 2024-12-04T18:08:17.972439Z

I wonder if it's due to the grammar being ambiguous

ghaskins 2024-12-04T18:08:52.260929Z

I am open to any possibility, but one of the things I spent time on specifically was making sure it wasnt ambiguous

ghaskins 2024-12-04T18:09:05.757189Z

(my first pass was, and it blew up my REPL the first time I ran it on the real file, heh)

ghaskins 2024-12-04T18:09:31.413169Z

but I reworked the grammar until I verified that the result for the test input was exactly 1 solution

ghaskins 2024-12-04T18:09:37.084729Z

i should check the real file

ghaskins 2024-12-04T18:10:17.792659Z

instaparse has debug modes i can enable to see if it has more than one solution

exitsandman 2024-12-04T18:18:16.977019Z

interestingly enough, your parser works on my input

ghaskins 2024-12-04T18:22:02.118899Z

interesting

exitsandman 2024-12-04T18:22:34.876259Z

but something is off because it straight up errors on yours, unless I copied an old file

ghaskins 2024-12-04T18:23:07.399359Z

i did push the regex fix for 3 digits, but both should have run successfully

ghaskins 2024-12-04T18:23:34.006959Z

by successfully, i mean without crashes

ghaskins 2024-12-04T18:23:48.069289Z

correct answers notwithstanding

ghaskins 2024-12-04T18:24:19.428229Z

oh well, we’ve both probably spent too much time on this. I appreciate the help

ghaskins 2024-12-04T18:40:04.057069Z

My suspicion is in the β€œ$” regex

ghaskins 2024-12-04T18:40:14.438609Z

i bet its getting tripped up by newlines

ghaskins 2024-12-04T18:44:04.673539Z

Hmm, nope. I only have one solution and there is only one EOL symbol parsed

ghaskins 2024-12-04T18:44:35.505139Z

I suppose its not impossible that AOC has a bug and my computed result is incorrectly marked wrong

ghaskins 2024-12-04T18:44:37.593359Z

who knows

ghaskins 2024-12-04T18:45:47.167529Z

ohh…i found something

ghaskins 2024-12-04T18:46:17.247009Z

my list from instaparse looks like this

ghaskins 2024-12-04T18:46:20.455129Z

([:mul "666" "399"]
 [:mul "354" "686"]
 [:mul "449" "25"]
 [:mul "298" "550"]
 [:mul "39" "588"]
 [:mul "255" "532"]
 [:mul "501" "122"]
 [:mul "792" "556"]
 [:mul "459" "837"]
 [:mul "390" "842"]
 [:mul "281" "40"]
 [:mul "19" "457"]
 [:mul "699" "994"]
 [:mul "693" "719"]
 [:mul "561" "466"]
 [:mul "355" "786"]
 [:mul "669" "354"]
 [:mul "691" "921"]
 [:mul "302" "652"]
 [:mul "827" "262"]
 [:mul "636" "791"]
 [:mul "267" "79"]
 [:mul "153" "490"]
 [:mul "429" "93"]
 [:mul "481" "952"]
 [:mul "498" "420"]
 [:mul "40" "723"]
 [:mul "172" "376"]
 [:mul "36" "67"]
 [:mul "553" "221"]
 [:mul "768" "886"]
 [:mul "429" "845"]
 [:mul "130" "55"]
 [:mul "550" "213"]
 [:mul "248" "215"]
 [:mul "9" "131"]
 [:mul "511" "894"]
 [:mul "845" "706"]
 [:mul "968" "989"]
 [:mul "644" "209"]
 [:mul "351" "869"]
 [:mul "449" "265"]
 [:mul "535" "567"]
 [:mul "413" "321"]
 [:mul "647" "475"]
 [:mul "594" "791"]
 [:mul "713" "498"]
 [:mul "19" "524"]
 [:mul "884" "220"]
 [:mul "249" "82"]
 [:mul "746" "775"]
 [:mul "340" "396"]
 [:mul "402" "793"]
 [:mul "760" "463"]
 [:mul "548" "103"]
 [:mul "226" "334"]
 [:mul "619" "629"]
 [:mul "180" "395"]
 [:mul "207" "329"]
 [:mul "194" "625"]
 [:mul "918" "273"]
 [:mul "888" "294"]
 [:mul "189" "104"]
 [:mul "225" "580"]
 [:mul "732" "265"]
 [:mul "52" "690"]
 [:mul "134" "563"]
 [:mul "665" "473"]
 [:mul "209" "717"]
 [:mul "896" "270"]
 [:mul "398" "671"]
 [:mul "47" "963"]
 [:mul "45" "141"]
 [:mul "145" "835"]
 [:mul "795" "657"]
 [:mul "706" "818"]
 [:mul "149" "292"]
 [:mul "85" "519"]
 [:mul "983" "747"]
 [:mul "339" "465"]
 [:mul "16" "661"]
 [:mul "724" "965"]
 [:mul "256" "462"]
 [:mul "819" "930"]
 [:mul "626" "231"]
 [:mul "145" "559"]
 [:mul "52" "260"]
 [:mul "823" "108"]
 [:mul "978" "24"]
 [:mul "645" "292"]
 [:mul "988" "213"]
 [:mul "853" "489"]
 [:mul "551" "740"]
 [:mul "388" "60"]
 [:mul "862" "379"]
 [:mul "922" "276"]
 [:mul "759" "151"]
 [:mul "583" "470"]
 [:mul "915" "695"]
 [:mul "464" "234"]
 [:mul "497" "706"]
 [:mul "613" "813"]
 [:mul "932" "777"]
 [:mul "615" "58"]
 [:mul "919" "955"]
 [:mul "119" "714"]
 [:mul "135" "380"]
 [:mul "427" "667"]
 [:mul "255" "4"]
 [:mul "967" "813"]
 [:mul "68" "67"]
 [:mul "225" "119"]
 [:mul "548" "198"]
 [:mul "382" "457"]
 [:mul "828" "292"]
 [:mul "866" "185"]
 [:mul "810" "863"]
 [:mul "10" "436"]
 [:mul "803" "717"]
 [:mul "982" "590"]
 [:mul "47" "419"]
 [:mul "781" "963"]
 [:mul "67" "556"]
 [:mul "242" "786"]
 [:mul "464" "770"]
 [:mul "160" "674"]
 [:mul "590" "431"]
 [:mul "781" "931"]
 [:mul "496" "694"]
 [:mul "921" "65"]
 [:mul "871" "365"]
 [:mul "807" "79"]
 [:mul "433" "788"]
 [:mul "108" "43"]
 [:mul "789" "645"]
 [:mul "128" "276"]
 [:mul "133" "271"]
 [:mul "618" "659"]
 [:mul "638" "330"]
 [:mul "908" "588"]
 [:mul "552" "454"]
 [:mul "615" "472"]
 [:mul "594" "691"]
 [:mul "23" "914"]
 [:mul "230" "641"]
 [:mul "63" "728"]
 [:mul "810" "461"]
 [:mul "569" "651"]
 [:mul "822" "175"]
 [:mul "213" "296"]
 [:mul "465" "480"]
 [:mul "471" "797"]
 [:mul "596" "891"]
 [:mul "900" "127"]
 [:mul "266" "693"]
 [:mul "155" "347"]
 [:mul "2" "759"]
 [:mul "523" "244"]
 [:mul "277" "553"]
 [:mul "786" "297"]
 [:mul "205" "507"]
 [:mul "123" "841"]
 [:mul "387" "218"]
 [:mul "456" "185"]
 [:mul "7" "112"]
 [:mul "651" "794"]
 [:mul "459" "535"]
 [:mul "627" "389"]
 [:mul "782" "394"]
 [:mul "678" "578"]
 [:mul "955" "180"]
 [:mul "200" "433"]
 [:mul "49" "444"]
 [:mul "846" "858"]
 [:mul "476" "67"]
 [:mul "807" "80"]
 [:mul "842" "301"]
 [:mul "732" "512"]
 [:mul "948" "809"]
 [:mul "891" "479"]
 [:mul "182" "940"]
 [:mul "113" "15"]
 [:mul "313" "46"]
 [:mul "101" "941"]
 [:mul "323" "578"]
 [:mul "54" "574"]
 [:mul "974" "166"]
 [:mul "149" "659"]
 [:mul "48" "9"]
 [:mul "133" "330"]
 [:mul "163" "966"]
 [:mul "366" "101"]
 [:mul "223" "335"]
 [:mul "398" "194"]
 [:mul "736" "464"]
 [:mul "861" "392"]
 [:mul "368" "351"]
 [:mul "418" "855"]
 [:mul "721" "586"]
 [:mul "375" "533"]
 [:mul "342" "13"]
 [:mul "568" "71"]
 [:mul "943" "549"]
 [:mul "922" "154"]
 [:mul "441" "285"]
 [:mul "75" "868"]
 [:mul "118" "644"]
 [:mul "4" "371"]
 [:mul "622" "537"]
 [:mul "857" "96"]
 [:mul "29" "888"]
 [:mul "741" "192"]
 [:mul "740" "164"]
 [:mul "89" "249"]
 [:mul "32" "185"]
 [:mul "28" "824"]
 [:mul "506" "528"]
 [:mul "665" "939"]
 [:mul "114" "937"]
 [:mul "706" "357"]
 [:mul "476" "267"]
 [:mul "94" "991"]
 [:mul "952" "295"]
 [:mul "120" "25"]
 [:mul "421" "23"]
 [:mul "375" "414"]
 [:mul "251" "565"]
 [:mul "991" "687"]
 [:mul "352" "56"]
 [:mul "337" "520"]
 [:mul "553" "348"]
 [:mul "548" "164"]
 [:mul "942" "713"]
 [:mul "273" "911"]
 [:mul "586" "995"]
 [:mul "382" "494"]
 [:mul "109" "2"]
 [:mul "704" "332"]
 [:mul "540" "890"]
 [:mul "582" "19"]
 [:mul "131" "795"]
 [:mul "232" "91"]
 [:mul "198" "512"]
 [:mul "629" "441"]
 [:mul "692" "721"]
 [:mul "676" "426"]
 [:mul "486" "902"]
 [:mul "77" "932"]
 [:mul "488" "898"]
 [:mul "107" "555"]
 [:mul "337" "733"]
 [:mul "480" "439"]
 [:mul "794" "629"]
 [:mul "82" "847"]
 [:mul "241" "602"]
 [:mul "232" "260"]
 [:mul "972" "455"]
 [:mul "299" "267"]
 [:mul "720" "748"]
 [:mul "536" "697"]
 [:mul "713" "265"]
 [:mul "899" "349"]
 [:mul "689" "501"]
 [:mul "39" "378"]
 [:mul "569" "666"]
 [:mul "139" "26"]
 [:mul "662" "726"]
 [:mul "931" "993"]
 [:mul "621" "611"]
 [:mul "670" "589"]
 [:mul "557" "904"]
 [:mul "663" "396"]
 [:mul "650" "882"]
 [:mul "866" "847"]
 [:mul "558" "210"]
 [:mul "470" "671"]
 [:mul "273" "437"]
 [:mul "953" "619"]
 [:mul "820" "300"]
 [:mul "240" "283"]
 [:mul "444" "495"]
 [:mul "742" "891"]
 "")

ghaskins 2024-12-04T18:46:30.437759Z

i bet that quote on the end is messing up the computation

Benjamin 2024-12-04T18:47:06.080889Z

Yesterday I randomly looked at emacs regex manual and learned that {} has a second form, {min,max}. Later on the day I solve day3, using this form. Don't know but sometimes it's epic where the knowledge of a solution comes from

πŸ‘ 1
❀️ 1
ghaskins 2024-12-04T18:48:31.031669Z

I think the best thing about those AOC type exercises is you get a bunch of people focused on the same problem, and its super interesting to see how everyone solves it. I’ve already learned like 4 new things that have been in clojure.core forever that I never knew about

πŸ‘ 1
3
ghaskins 2024-12-04T18:50:52.228739Z

fixed it!

ghaskins 2024-12-04T18:50:58.189399Z

the problem was total dumb

ghaskins 2024-12-04T18:51:15.040639Z

@doppiaelle1999 it was this

diff --git a/resources/day3.ebnf b/resources/day3.ebnf
index a6ce3b1..cd4d2ba 100644
--- a/resources/day3.ebnf
+++ b/resources/day3.ebnf
@@ -10,5 +10,5 @@ mul ::= (<"mul("> digit <","> digit <")">)
 <digit> ::= #"\d{1,3}"
 <ws> ::= (!mul any)*
 <aws> ::= (ignore / (!mul !ignore any))*
-<eol> ::= #"$"
+<eol> ::= <#"$">
 <any> ::= <#"."> | <#"\n">

ghaskins 2024-12-04T18:51:36.896209Z

I wasnt hiding the EOL symbol, so it showed up in the sequence and messed the computation up by 1

ghaskins 2024-12-04T18:51:56.805599Z

thanks for the help, all!

exitsandman 2024-12-04T19:04:23.859909Z

the default behavior of having to hide things really worked against you there, though it might be better suited for larger use cases idk

ghaskins 2024-12-04T19:04:55.414429Z

yeah, agreed..the ratio of symbols i cared about was not favorable

ghaskins 2024-12-04T19:05:08.247759Z

made the EBNF a bit chatty

ghaskins 2024-12-04T19:05:22.699029Z

I use it for work for various things, and its not typically like that

exitsandman 2024-12-04T19:05:50.857679Z

yeah I figured haha

Zach 2024-12-03T08:07:29.233699Z

AOC in x86 🀯 https://github.com/JustinHuPrime/AoC/tree/main/2024

❀️ 1
2024-12-03T16:51:06.778069Z

Ok a little heads up this time. Going live in 10min! https://www.twitch.tv/timpote Also: I'll be perusing the solutions here after solving day 3, so join in and let me know if you want feedback on your solution.

Kathryn Isabelle Lawrence 2024-12-03T19:34:29.328909Z

just watched the vod and im pretty blind but maybe it would also help others to bump the font size up a bit on your ide?

2024-12-03T19:34:50.405079Z

awww man I meant to do that

2024-12-03T19:35:02.727489Z

I will try to remember for tomorrow

πŸ™ 1
Kathryn Isabelle Lawrence 2024-12-03T19:35:26.898459Z

you were also complaining about it being too small πŸ˜‚ we're all blind from too much computer @_@ thx!!

2024-12-03T19:35:49.959979Z

ah I was looking at twitch chat in OBS right then

2024-12-03T19:36:03.688269Z

but I agree the editor text is too small to see comfortably in the stream

2024-12-03T19:36:11.516999Z

😿

Kathryn Isabelle Lawrence 2024-12-03T19:37:44.356729Z

otherwise enjoyed it a lot! will try to catch the live sometime

❀️ 1
2024-12-03T19:39:36.150389Z

thank you for the feedback! hope to see you at 11:00 CST tomorrow!