adventofcode 2023-12-02

One of my usual AOC habits is to explore transducers after I get my quick and dirty answer out there. I'm curious why my regular version is the same speed (if not slightly faster) when benchmarking with criterium than the transducer version. I usually find quite the opposite.

relevant code for Part 1:

(defn part-1 [data]
  (->> data
       (map #(re-seq #"\d" %))
       (map (juxt first last))
       (map (comp parse-long (partial apply str)))
       (reduce +)))

(defn part-1-transduce [data]
  (let [xform (comp
                (map #(re-seq #"\d" %))
                (map (juxt first last))
                (map (comp parse-long (partial apply str))))]
    (transduce xform + data)))

It probably depends on the size of the data

solving day 2 just reminds me how much I love programming in clojure.

(ns day02
  (:require [ :as io]
            [clojure.string :as string]))

(defn parse-subset [subset]
  (let [[[_ r]] (re-seq #"(\d+) red" subset)
        [[_ g]] (re-seq #"(\d+) green" subset)
        [[_ b]] (re-seq #"(\d+) blue" subset)]
    [(or (some-> r parse-long) 0)
     (or (some-> g parse-long) 0)
     (or (some-> b parse-long) 0)]))

(defn parse [line]
  (let [[_ subsets] (string/split line #":")]
    (->>  (string/split subsets #";")
          (map parse-subset))))

(defn part01 [lines]
  (->> lines
       (map parse)
       (map-indexed
        (fn [idx subsets]
          [(+ idx 1)
           (->> subsets
                (map (fn [[r g b]] (and (<= r 12) (<= g 13) (<= b 14))))
                (flatten)
                (every? identity))]))
       (filter (fn [[_ p]] p))
       (map first)
       (reduce +)))

(defn part02 [lines]
  (->> lines
       (map parse)
       (map
        (fn [subsets]
          (->> subsets
               (reduce (fn [[ar ag ab] [r g b]]
                         [(max ar r) (max ag g) (max ab b)])
                       [0 0 0])
               (reduce *))))
       (reduce +)))

(comment
  (with-open [r (io/reader "day02.txt")]
    (part01 (line-seq r)))
  (with-open [r (io/reader "day02.txt")]
    (part02 (line-seq r))))

Happily, my approach for part 1 dovetailed nicely with part 2, didn’t have to re-write anything, and that rarely happens for me with AoC.

> merge-with max came in quite handy. this is great, did not know about this! +1

yea, same, i happened to set myself up very nicely for part 2 during part 1. https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2023/day02.clj

probably influenced by day 1, but I keep coming back to regex for my solutions: https://github.com/rmrt1n/advent-of-code-2023-clj/blob/main/src/aoc/day02.clj

Had to rewrite parsing logic when part 2 was unveiled, but overall happy how easy today turned out to be https://github.com/skazhy/advent/blob/master/src/advent/2023/day2.clj

https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2F3e871513ab6f2462841f75fc99668f841f33dabb%2Faoc_ui.cljs&amp;repl=true&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmIGlucHV0ICgtPj4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIzIDIpKQogICAgICAgICAgICAgc3RyL3NwbGl0LWxpbmVzKSkKCihkZWYgYmFnCiAgeyJyZWQiIDEyCiAgICJncmVlbiIgMTMKICAgImJsdWUiIDE0fSkKCihkZWZuIHNwbGl0LWN1YmVzCiAgW2N1YmVzXQogICgtPj4gKHN0ci9zcGxpdCBjdWJlcyAiLCAiKQogICAgKG1hcHYgIyhsZXQgW1tuIGNvbG9yXSAoc3RyL3NwbGl0ICUgIiAiKV0KICAgICAgICAgICAgIHtjb2xvciBufSkpCiAgICAoaW50byB7fSkpKQoKKGRlZm4gY29sb3ItcG9zc2libGU%2FCiAgW1tjb2xvciBuXV0KICAoPj0gKGdldCBiYWcgY29sb3IpIG4pKQoKKGRlZm4gcG9zc2libGU%2FCiAgW3NldF0KICAoZXZlcnk%2FIGNvbG9yLXBvc3NpYmxlPyBzZXQpKQoKKGRlZm4gcGFyc2UtZ2FtZQogIFtzXQogIChsZXQgW1tnYW1lIHNldHNdIChzdHIvc3BsaXQgcyAiOiAiKQogICAgICAgIHBhcnNlZC1zZXRzICgtPj4gKHN0ci9zcGxpdCBzZXRzICI7ICIpCiAgICAgICAgICAgICAgICAgICAgICAobWFwdiBzcGxpdC1jdWJlcykpCiAgICAgICAgcG9zc2libGUtYmFnIChhcHBseSBtZXJnZS13aXRoIG1heCBwYXJzZWQtc2V0cyldCiAgICB7OmdhbWUgKC0%2BIChzdHIvc3BsaXQgZ2FtZSAiICIpIGxhc3QgcGFyc2UtbG9uZykKICAgICA6c2V0cyBwYXJzZWQtc2V0cwogICAgIDpwb3NzaWJsZS1iYWcgcG9zc2libGUtYmFnCiAgICAgOnBvd2VyLXNldCAoLT4%2BIHBvc3NpYmxlLWJhZwogICAgICAgICAgICAgICAgICB2YWxzCiAgICAgICAgICAgICAgICAgIHNweQogICAgICAgICAgICAgICAgICAoYXBwbHkgKikpCiAgICAgOnBvc3NpYmxlPyAoZXZlcnk%2FIHBvc3NpYmxlPyBwYXJzZWQtc2V0cyl9KSkKCihkZWYgcGFyc2VkLWdhbWUgKG1hcHYgcGFyc2UtZ2FtZSBpbnB1dCkpCgooLT4%2BIHBhcnNlZC1nYW1lCiAgICAoZmlsdGVyIDpwb3NzaWJsZT8pCiAgICAobWFwIDpnYW1lKQogICAgKGFwcGx5ICspCiAgYXBwZW5kKQoKKC0%2BPiBwYXJzZWQtZ2FtZQogIChtYXB2IDpwb3dlci1zZXQpCiAgKGFwcGx5ICspCiAgYXBwZW5kKQ%3D%3D using the squint playground. merge-with max feels like cheating on part 2.

@mynomoto I wonder if you will manage day 3 with squint, as storing collections as keys doesn't work that well in JS. You can switch to http://squint-cljs.github.io/cherry if you must :)

(but I'd like to challenge you to do it in squint anyway :))

1

I will at least try, let's see how it goes πŸ˜‰

one strategy I've used is to use an object instead of a set and store coordinates like:

(assoc {} coord coord)
This will become {"0,0" [0,0]} in JS

and then also (get obj [0,0]) works

it works only for 1-dimensional arrays though

this was comparatively easier than day 1. Though tons of str/split feels like a code smell: https://gist.github.com/mrnhrd/895b6ad912e3b04d941ab3a943b42678 looking forward to scrolling through other people's solutions.

Decided to go for TDD, because parsing input always gets trickier than I think it will. πŸ˜ƒ

Would love to know from others better at data parsing and shaping how I could have done the data parsing and shaping more efficiently, but for the sake of posterity… https://gist.github.com/maleghast/22d460542ce8f313fb6db54cd92f2196

@maleghast I too felt like I had made the parsing a bit harder than it really is. When I had collected the stars, I asked ChatGPT to write a parser and it did a pretty decent job, I’d say: https://chat.openai.com/share/33e05353-b5e6-45d9-851f-1b532daf0ebb

the format is really easy to just use splits for, thankfully

Yeah, that’s what ChatGPT realized, but I only realized halfly. πŸ˜ƒ

Somehow sorted-map becomes the main data structure so far... https://github.com/caseneuve/aoc2023/blob/master/day02/solution.clj

πŸ†’ 1

Bangs head on keyboard, after a non-optimal night of sleep. The test input works for me, but the "production" input gives a too low number

https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&amp;repl=true&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmbiBwYXJzZS1saW5lIFtsaW5lXQogIChsZXQgW1tpZCBnYW1lXSAoc3RyL3NwbGl0IGxpbmUgIjogIikKICAgICAgICBpZCAoLT4gKHN0ci9yZXBsYWNlIGlkICJHYW1lICIgIiIpCiAgICAgICAgICAgICBwYXJzZS1sb25nKV0KICAgIHs6aWQgaWQKICAgICA6Z2FtZSAoLT4KICAgICAgICAgICAgIGdhbWUKICAgICAgICAgICAgIChzdHIvc3BsaXQgIjsgIikKICAgICAgICAgICAgICgtPj4gKG1hcCAoZm4gW2VdCiAgICAgICAgICAgICAgICAgICAgICAgICAoLT4gKG1hcHYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMoLT4gKHJldmVyc2UgKHN0ci9zcGxpdCAlICIgIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICh1cGRhdGUgMSBwYXJzZS1sb25nKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzdHIvc3BsaXQgZSAiLCAiKSkpKSkKICAgICAgICAgICAgICAgKG1hcHYgIyhpbnRvIHt9ICUpKSkpfSkpCgooY29tbWVudAogIChwYXJzZS1saW5lICJHYW1lIDE6IDMgYmx1ZSwgNCByZWQ7IDIgZ3JlZW4iKQogICkKCihkZWYgZXhhbXBsZSAiR2FtZSAxOiAzIGJsdWUsIDQgcmVkOyAxIHJlZCwgMiBncmVlbiwgNiBibHVlOyAyIGdyZWVuCkdhbWUgMjogMSBibHVlLCAyIGdyZWVuOyAzIGdyZWVuLCA0IGJsdWUsIDEgcmVkOyAxIGdyZWVuLCAxIGJsdWUKR2FtZSAzOiA4IGdyZWVuLCA2IGJsdWUsIDIwIHJlZDsgNSBibHVlLCA0IHJlZCwgMTMgZ3JlZW47IDUgZ3JlZW4sIDEgcmVkCkdhbWUgNDogMSBncmVlbiwgMyByZWQsIDYgYmx1ZTsgMyBncmVlbiwgNiByZWQ7IDMgZ3JlZW4sIDE1IGJsdWUsIDE0IHJlZApHYW1lIDU6IDYgcmVkLCAxIGJsdWUsIDMgZ3JlZW47IDIgYmx1ZSwgMSByZWQsIDIgZ3JlZW4iKQoKKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAyKSkKICAgICAgICAgICAgICNfc3B5CiAgICAgICAgICAgICBzdHIvdHJpbQogICAgICAgICAgICAgc3RyL3NwbGl0LWxpbmVzCiAgICAgICAgICAgICAobWFwdiBwYXJzZS1saW5lKSkpCgooY29tbWVudAogIChzcHkgaW5wdXQpKQoKKGRlZm4gbXktcGx1cyBbJiB4c10KICAoYXBwbHkgKyAobWFwIChmbmlsIGlkZW50aXR5IDApIHhzKSkpCgooY29tbWVudAogIChteS1wbHVzIDEganMvdW5kZWZpbmVkIDIganMvdW5kZWZpbmVkKSkKCihkZWZuIHN1bS1nYW1lIFtnYW1lXQogIChhcHBseSBtYXB2IG15LXBsdXMKICAgIChtYXB2IChqdXh0IDpyZWQgOmdyZWVuIDpibHVlKSBnYW1lKSkpCgooY29tbWVudAogIChzdW0tZ2FtZSBbezpyZWQgMSA6Ymx1ZSAyIDpncmVlbiAzfQogICAgICAgICAgICAgezpyZWQgNSA6Ymx1ZSAxMzM3fV0pKQoKKGRlZm4gcGFydC0xCiAgW10KICAoLT4%2BIGlucHV0CiAgICAoZmlsdGVydiAjKGxldCBbZ2FtZSAoOmdhbWUgJSkKICAgICAgICAgICAgICAgICAgICBbciBnIGJdIChzdW0tZ2FtZSBnYW1lKV0KICAgICAgICAgICAgICAgIChhbmQKICAgICAgICAgICAgICAgICAgKDw9IHIgMTIpCiAgICAgICAgICAgICAgICAgICg8PSBnIDEzKQogICAgICAgICAgICAgICAgICAoPD0gYiAxNCkpKSkKICAgIChtYXB2IDppZCkKICAgIChhcHBseSArKSkpCgooY29tbWVudAogIChwYXJ0LTEpKQ%3D%3D - any hints welcome, I'm going off for lunch ;)

😍 2

I think I got it, I misinterpreted the puzzle, I summed all the red, green, blue and then compared to the max

That's it, part 1 fixed

I had the same mistake, summed the colors instead of using max

@michaeljweaver Love how terse your implementation is! The parsing part certainly took me a while to understand. Also, power could just be #(apply * (vals %)) . Ah, I see that it couldn't, since you keep game id as one of the keys.

I thought I made a mistake earlier by using array indexes as the game id but then I thought: perhaps they use sparse ids, but this wasn't the case in my input

β€’ Sometimes I find spelling out the parser easier to read, though I’m not completely happy with mine it was fast. β€’ using [r g b] tuples in a matrix lets you do things like map >= to check size and makes power just the max of the transpose. https://github.com/tschady/advent-of-code/blob/main/src/aoc/2023/d02.clj

https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmIGlucHV0ICgtPiAoanMtYXdhaXQgKGZldGNoLWlucHV0IDIwMjMgMikpCiAgICAgICAgICAgICBzdHIvdHJpbQogICAgICAgICAgICAgc3RyL3NwbGl0LWxpbmVzKSkKCihkZWZuIGdhbWVzIFtzXQogICgtPj4gKC0%2BIHMgKHN0ci9zcGxpdCAjIjoiKSBzZWNvbmQKICAgICAgICAgKHN0ci9yZXBsYWNlICMiKFxkKykgKFx3KykiICJ7XCIkMlwiOiAkMX0iKQogICAgICAgICAoc3RyL3NwbGl0ICMiWyw7XSIpKQogICAgKG1hcCBqcy9KU09OLnBhcnNlKQogICAgKGFwcGx5IG1lcmdlLXdpdGggbWF4KQogICAgKChqdXh0IDpyZWQgOmdyZWVuIDpibHVlKSkpKQoKKGNvbW1lbnQKICAoZ2FtZXMgKGZpcnN0IGlucHV0KSkpCgooZGVmIHAxCiAgKGxldCBbcnVsZXMgKHZhbHMgeyJyZWQiIDEyICJncmVlbiIgMTMgImJsdWUiIDE0fSkKICAgICAgICBwb3NzaWJsZT8gIyhldmVyeT8gdHJ1ZT8gKG1hcCAoZm4gW2EgYl0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICg8PSBhIGIpKSAlIHJ1bGVzKSldCiAgICAocGFydGlhbCBrZWVwLWluZGV4ZWQKICAgICAgKGZuIFtpZCBnYW1lXSAod2hlbiAocG9zc2libGU%2FIGdhbWUpIChpbmMgaWQpKSkpKSkKCihkZWYgcDIgKHBhcnRpYWwgbWFwICMocmVkdWNlIChmbiBbYSBiXSAoKiBhIGIpKSAlKSkpCgooZGVmbiBzb2x2ZSBbaW5wdXRdCiAgKGxldCBbc29sdmUtd2l0aCAjKC0%2BPiBpbnB1dCAobWFwIGdhbWVzKSAlIChhcHBseSArKSldCiAgICB7OnBhcnQxIChzb2x2ZS13aXRoIHAxKSA6cGFydDIgKHNvbHZlLXdpdGggcDIpfSkpCgooY29tbWVudAogIChzb2x2ZSBpbnB1dCkpCgooY29tbWVudAogIChkZWYgdGVzdC1pbnB1dCAiR2FtZSAxOiAzIGJsdWUsIDQgcmVkOyAxIHJlZCwgMiBncmVlbiwgNiBibHVlOyAyIGdyZWVuCkdhbWUgMjogMSBibHVlLCAyIGdyZWVuOyAzIGdyZWVuLCA0IGJsdWUsIDEgcmVkOyAxIGdyZWVuLCAxIGJsdWUKR2FtZSAzOiA4IGdyZWVuLCA2IGJsdWUsIDIwIHJlZDsgNSBibHVlLCA0IHJlZCwgMTMgZ3JlZW47IDUgZ3JlZW4sIDEgcmVkCkdhbWUgNDogMSBncmVlbiwgMyByZWQsIDYgYmx1ZTsgMyBncmVlbiwgNiByZWQ7IDMgZ3JlZW4sIDE1IGJsdWUsIDE0IHJlZApHYW1lIDU6IDYgcmVkLCAxIGJsdWUsIDMgZ3JlZW47IDIgYmx1ZSwgMSByZWQsIDIgZ3JlZW4iKQogIChkZWYgc29sdmUtd2l0aCAjKC0%2BPiB0ZXN0LWlucHV0CiAgICAgICAgICAgICAgICAgICAgIHN0ci9zcGxpdC1saW5lcwogICAgICAgICAgICAgICAgICAgICAobWFwIGdhbWVzKSAlCiAgICAgICAgICAgICAgICAgICAgIChhcHBseSArKSkpCiAgCiAgKD0gOCAoc29sdmUtd2l0aCBwMSkpCiAgKD0gMjI4NiAoc29sdmUtd2l0aCBwMikpCiAgKQ%3D%3D The above is @piotr.kaznowski’s solution. I used JSON/parse instead of read-string and there were some issues around * and <= not being available as reified functions (https://github.com/squint-cljs/squint/issues/400)

πŸ™Œ 1

(require '[clojure.string :as str])

(defn parse-count [s]
  (let [[cnt color] (str/split s #" ")]
    [(keyword color) (parse-long cnt)]))

(defn parse-hand [s]
  (->> (str/split s #", ")
       (map parse-count)
       (into {})))

(defn game-maxes [s]
  (let [[game-name-str counts-str] (str/split s #": ")
        max-counts (-> counts-str
                       (str/split #"; ")
                       (->> (map parse-hand)
                            (apply merge-with max)))
        game-id (-> game-name-str (str/split #" ")
                    second
                    parse-long)]
    [game-id max-counts]))

(def thresholds {:red 12 :green 13 :blue 14})

(defn game-within-threshold? [[_game-id maxes]]
  (->> (merge-with >= thresholds maxes)
       vals
       (every? true?)))

(defn power-val [[_game-id maxes]]
  (->> maxes
       vals
       (reduce *)))

(def part1-result
  (-> (slurp "aoc/input2.txt")
      (str/split #"\n")
      (->> (map game-maxes)
           (filter game-within-threshold?)
           (map first)
           (reduce +))))

(def part2-result
  (-> (slurp "aoc/input2.txt")
      (str/split #"\n")
      (->> (map game-maxes)
           (map power-val)
           (reduce +))))

less to get snagged on than with Day 1 πŸ™‚

(defn possible? [game]
  (let [c->max {"red" 12, "green" 13, "blue" 14}]
    ;; for every selection in this game...
    (every? #(every? (fn [c] ; ... every color <= max (or absent)
                       (<= (get % c 0) (get c->max c)))
                     (keys c->max))
            (:cubes game))))


;; part 2
(defn min-cubes [game]
  ;; reduce over all 'cubes' (selections of cubes) in this game...
  (reduce (fn [m cube]
            (->> m
                 ;; ... to produce a map of min required for each color
                 (map (fn [[c n]] [c (max n (get cube c 0))]))
                 (into {})))
          {"red" 0
           "green" 0
           "blue" 0}
          (:cubes game)))


(defn solve [input & {:keys [part]}]
  (->> (parse input)
       (keep (fn [game]
               (case part
                 1 (when (possible? game)
                     (:id game))
                 2 (->> (min-cubes game)
                        (vals)
                        (apply *)))))
       (apply +)))
https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2023/d2.clj (if this trend continues...??)

@larzeitlin https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&amp;repl=true&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgoocmVxdWlyZSAnW2Nsb2p1cmUuc3RyaW5nIDphcyBzdHJdKQoKKGRlZm4gcGFyc2UtY291bnQgW3NdCiAgKGxldCBbW2NudCBjb2xvcl0gKHN0ci9zcGxpdCBzICMiICIpXQogICAgWygjPyg6c3F1aW50IGlkZW50aXR5IDpkZWZhdWx0IGtleXdvcmQpIGNvbG9yKSAocGFyc2UtbG9uZyBjbnQpXSkpCgooY29tbWVudAogIChwYXJzZS1jb3VudCAiMSBncmVlbiIpKQoKKGRlZm4gcGFyc2UtaGFuZCBbc10KICAoLT4%2BIChzdHIvc3BsaXQgcyAjIiwgIikKICAgIChtYXAgcGFyc2UtY291bnQpCiAgICAoaW50byB7fSkpKQoKKGNvbW1lbnQKICAocGFyc2UtaGFuZCAiMSBncmVlbiwgMiBibHVlIikpCgooZGVmbiBnYW1lLW1heGVzIFtzXQogIChsZXQgW1tnYW1lLW5hbWUtc3RyIGNvdW50cy1zdHJdIChzdHIvc3BsaXQgcyAjIjogIikKICAgICAgICBtYXgtY291bnRzICgtPiBjb3VudHMtc3RyCiAgICAgICAgICAgICAgICAgICAgIChzdHIvc3BsaXQgIyI7ICIpCiAgICAgICAgICAgICAgICAgICAgICgtPj4gKG1hcCBwYXJzZS1oYW5kKQogICAgICAgICAgICAgICAgICAgICAgIChhcHBseSBtZXJnZS13aXRoIG1heCkpKQogICAgICAgIGdhbWUtaWQgKC0%2BIGdhbWUtbmFtZS1zdHIgKHN0ci9zcGxpdCAjIiAiKQogICAgICAgICAgICAgICAgICBzZWNvbmQKICAgICAgICAgICAgICAgICAgcGFyc2UtbG9uZyldCiAgICBbZ2FtZS1pZCBtYXgtY291bnRzXSkpCgooY29tbWVudAogIChnYW1lLW1heGVzICJHYW1lIDE6IDEgZ3JlZW4sIDIgYmx1ZTsgMiBncmVlbiwgMSByZWQiKSkKCihkZWYgdGhyZXNob2xkcyB7OnJlZCAxMiA6Z3JlZW4gMTMgOmJsdWUgMTR9KQoKKGRlZm4gZ2FtZS13aXRoaW4tdGhyZXNob2xkPyBbW19nYW1lLWlkIG1heGVzXV0KICAoLT4%2BIChtZXJnZS13aXRoICMoPj0gJTEgJTIpIHRocmVzaG9sZHMgbWF4ZXMpCiAgICB2YWxzCiAgICAoZXZlcnk%2FIHRydWU%2FKSkpCgooY29tbWVudAogIChnYW1lLXdpdGhpbi10aHJlc2hvbGQ%2FIChnYW1lLW1heGVzICJHYW1lIDE6IDEgZ3JlZW4sIDIgYmx1ZTsgMiBncmVlbiwgMSByZWQiKSkKICApCgooZGVmbiBwb3dlci12YWwgW1tfZ2FtZS1pZCBtYXhlc11dCiAgKC0%2BPiBtYXhlcwogICAgdmFscwogICAgKHJlZHVjZSAjKCogJTEgJTIpKSkpCgooY29tbWVudAogIChwb3dlci12YWwgKGdhbWUtbWF4ZXMgIkdhbWUgMTogMSBncmVlbiwgMiBibHVlOyAyIGdyZWVuLCAxIHJlZCIpKQogICkKCihkZWYgcGFydDEtcmVzdWx0CiAgKC0%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAyKSkKICAgIHN0ci90cmltCiAgICAoc3RyL3NwbGl0ICMiXG4iKQogICAgKC0%2BPiAobWFwdiBnYW1lLW1heGVzKQogICAgICAoZmlsdGVyIGdhbWUtd2l0aGluLXRocmVzaG9sZD8pCiAgICAgIChtYXAgZmlyc3QpCiAgICAgIChyZWR1Y2UgKykpKSkKCihkZWYgcGFydDItcmVzdWx0CiAgKC0%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAyKSkKICAgIHN0ci90cmltCiAgICAoc3RyL3NwbGl0ICMiXG4iKQogICAgKC0%2BPiAobWFwIGdhbWUtbWF4ZXMpCiAgICAgIChtYXAgcG93ZXItdmFsKQogICAgICAocmVkdWNlICspKSkp

πŸ™Œ 1

I needed to insert str/trim to get rid of the newline in the input, I wonder why that wasn't a problem in your case

ah because it's a difference in squint: user=> (str/split "foo\nbar\n" #"\n") ;;=> [ 'foo', 'bar', '' ] facepalm

@piotr.kaznowski good idea using sorted-map

Fixed issues in squint, * and >= etc can now be used as higher order functions and str/split elides empty splitted elements (when limit = nil), like in CLJS Again @larzeitlin’s https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&amp;repl=true&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgoocmVxdWlyZSAnW2Nsb2p1cmUuc3RyaW5nIDphcyBzdHJdKQoKKGRlZm4gcGFyc2UtY291bnQgW3NdCiAgKGxldCBbW2NudCBjb2xvcl0gKHN0ci9zcGxpdCBzICMiICIpXQogICAgWygjPyg6c3F1aW50IGlkZW50aXR5IDpkZWZhdWx0IGtleXdvcmQpIGNvbG9yKSAocGFyc2UtbG9uZyBjbnQpXSkpCgooY29tbWVudAogIChwYXJzZS1jb3VudCAiMSBncmVlbiIpKQoKKGRlZm4gcGFyc2UtaGFuZCBbc10KICAoLT4%2BIChzdHIvc3BsaXQgcyAjIiwgIikKICAgIChtYXAgcGFyc2UtY291bnQpCiAgICAoaW50byB7fSkpKQoKKGNvbW1lbnQKICAocGFyc2UtaGFuZCAiMSBncmVlbiwgMiBibHVlIikpCgooZGVmbiBnYW1lLW1heGVzIFtzXQogIChsZXQgW1tnYW1lLW5hbWUtc3RyIGNvdW50cy1zdHJdIChzdHIvc3BsaXQgcyAjIjogIikKICAgICAgICBtYXgtY291bnRzICgtPiBjb3VudHMtc3RyCiAgICAgICAgICAgICAgICAgICAgIChzdHIvc3BsaXQgIyI7ICIpCiAgICAgICAgICAgICAgICAgICAgICgtPj4gKG1hcCBwYXJzZS1oYW5kKQogICAgICAgICAgICAgICAgICAgICAgIChhcHBseSBtZXJnZS13aXRoIG1heCkpKQogICAgICAgIGdhbWUtaWQgKC0%2BIGdhbWUtbmFtZS1zdHIgKHN0ci9zcGxpdCAjIiAiKQogICAgICAgICAgICAgICAgICBzZWNvbmQKICAgICAgICAgICAgICAgICAgcGFyc2UtbG9uZyldCiAgICBbZ2FtZS1pZCBtYXgtY291bnRzXSkpCgooY29tbWVudAogIChnYW1lLW1heGVzICJHYW1lIDE6IDEgZ3JlZW4sIDIgYmx1ZTsgMiBncmVlbiwgMSByZWQiKSkKCihkZWYgdGhyZXNob2xkcyB7OnJlZCAxMiA6Z3JlZW4gMTMgOmJsdWUgMTR9KQoKKGRlZm4gZ2FtZS13aXRoaW4tdGhyZXNob2xkPyBbW19nYW1lLWlkIG1heGVzXV0KICAoLT4%2BIChtZXJnZS13aXRoID49IHRocmVzaG9sZHMgbWF4ZXMpCiAgICB2YWxzCiAgICAoZXZlcnk%2FIHRydWU%2FKSkpCgooY29tbWVudAogIChnYW1lLXdpdGhpbi10aHJlc2hvbGQ%2FIChnYW1lLW1heGVzICJHYW1lIDE6IDEgZ3JlZW4sIDIgYmx1ZTsgMiBncmVlbiwgMSByZWQiKSkKICApCgooZGVmbiBwb3dlci12YWwgW1tfZ2FtZS1pZCBtYXhlc11dCiAgKC0%2BPiBtYXhlcwogICAgdmFscwogICAgKHJlZHVjZSAqKSkpCgooY29tbWVudAogIChwb3dlci12YWwgKGdhbWUtbWF4ZXMgIkdhbWUgMTogMSBncmVlbiwgMiBibHVlOyAyIGdyZWVuLCAxIHJlZCIpKQogICkKCihkZWYgcGFydDEtcmVzdWx0CiAgKC0%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAyKSkKICAgIChzdHIvc3BsaXQgIyJcbiIpCiAgICAoLT4%2BIChtYXB2IGdhbWUtbWF4ZXMpCiAgICAgIChmaWx0ZXIgZ2FtZS13aXRoaW4tdGhyZXNob2xkPykKICAgICAgKG1hcCBmaXJzdCkKICAgICAgKHJlZHVjZSArKSkpKQoKKGRlZiBwYXJ0Mi1yZXN1bHQKICAoLT4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIzIDIpKQogICAgKHN0ci9zcGxpdCAjIlxuIikKICAgICgtPj4gKG1hcCBnYW1lLW1heGVzKQogICAgICAobWFwIHBvd2VyLXZhbCkKICAgICAgKHJlZHVjZSArKSkpKQ%3D%3D but essentially the same now except reading the input of course

Nice to put runnable comments for the intermediary steps like this

lol I'm glad ya'll figured out the summing/maxing thing. I was pretty sure I was misinterpreting, but I wasn't' at all sure how.

Fortunately clojure is amazing. (apply merge-with + coll) became (apply merge-with max picks)

re having to rewrite parsing: I've found that lossless parsing really pays off in AoC (and in every day programming as well!)

What do you mean, @potetm, by lossless parsing?

"don't throw away any information"

And where did you end up using merge-with +?

so, e.g. instead of grabbing the min values from each line, have a parsing phase that grabs all the values

merge-with + was a mistake.

It became merge-with max

πŸ‘ 1

I took a gamble and did not do lossless parsing. I think I picked up that trick from @zelark a couple years ago. It paid off this time. I did not keep track of individual sets within each game (which is more effort because the number of sets per game is not fixed), ignored commas and semicolons and just reduced with max. I guess it was lucky that approach worked for both part 1 and part 2. (I had guessed that part 2 would involve some change to the limits, so when it was revealed it was too easy.)

@felipecortezfi yeah, I refactored when the 2nd part was revealed, as it became obvious that only edge cases are important and colors are only needed as "indexes" for unifying data as no further look-ups will follow; then I refactored a bit further, so the solution algorithms accept only vals, not maps.

πŸ‘ 1

I love this ascii art trebuchet.

----@
* ! /^\

https://github.com/chase-lambert/aoc-clojure/blob/main/src/aoc/2023/day_02.clj Another hacky one for me, I'm excited to check out these more elegant solutions from you folks now

folks seem reluctant to tackle part 2 so far but I didn't find it that much more difficult than part 1. Could just be early though

oh man, some of the solutions are so sweet! I feel like my imposter syndrome needs a disclaimer if you spent a good amount of time refactoring to look so nice before posting or is this just naturally how you code off the bat

I would love and "honour-mode" where you get to submit only one solution without running it and you get the star if it passes first time. No repl cheating

I'd be 0/2 this year. coneofshame

That said, I don't redo anything. I finish and insta commit.

Day 2 seems to be very easy compare to Day 1 (especially part 2). Did a Live Coding used Hyperfiddle for TDD and its available on https://www.youtube.com/watch?v=aF4OfRGnobk . https://github.com/muthuishere/advent-of-code-clojure-2023/blob/main/src/day2.clj

Do you mind deleting this comment? By all means send your live coding to the main channel but don’t put solutions into the channel

And use a snippet for such a long code block

βœ… 1

I enjoyed day 2. Just parsing colour and count in part 1 turned out to be helpful for the second part. Though reading this thread it would have been nice to know about merge-with https://github.com/JDurstberger/aoc-2023-clj/tree/main/src/day_2 Here is today's video https://youtu.be/Whff9f_BrL8

(And could you please delete the link preview as well? It’s an awesome share just don’t want spoilers leaking out) edit: link previews are fine here in the thread, just don’t want code solutions in the main channel for people who are still solving them)

my day 2 in squint -- didn't use the playground this time due to time constraints (I ended up spending more time working on the playground than doing the actual problems): https://gist.github.com/corasaurus-hex/e800b30d092db6efaaa182aa51d57431

πŸŽ‰ 2

Wanted to make a poll asking people about their approach to AoC questions. Is this not possible in slack without a plugin?

I guess not. I often do things like: How do you do X? β€’ 1️⃣ foo β€’ 2️⃣ bar β€’ 3️⃣ baz and get people to use the emoji reactions 1️⃣ , 2️⃣ , or 3️⃣ and discuss in a thread

1️⃣ 1
πŸ™ 1
βœ… 1

How do you think about performance in your AoC solutions: 1️⃣ Not at all 2️⃣ It's lower priority than some other style / readability considerations 3️⃣ It's an important aspect of my solution - I optimize it intuitively 4️⃣ It's an important aspect of my solution - I measure it 5️⃣ Something else

5️⃣ 2
4️⃣ 2
1️⃣ 14
3️⃣ 1
2️⃣ 24

As long as it runs in tens of seconds at most, I'm happy πŸ˜„ Since I compile my clerk notebooks, the solutions run every time I deploy so I need them fast but I'm not too fussed about shaving milliseconds

I’m β„– 1 all the time… until you get to that day where it takes 10 million years to solve.

βž• 5

I favour readability over performance for this kind of thing, although I guess readability is a bit subjective

πŸ’― 1

I did AoC in Clojure last year, and I found that it’s quite easy (for a novice at least) to write correct and (I think) idiomatic Clojure code that runs quite slow. Then you have to think about lazy vs. not-lazy sequences, reflection, boxing etc. I was especially surprised that not-lazy code can be quicker that lazy (as laziness is mostly explained as a mean to save resources and not perform calculations until they are really needed).

πŸ‘ 2

It depends a little on what you're trying to do. Given that I'm only trying to solve the problems, I only care about perf when it matters, and I care about "readability" not a wit πŸ˜„

fwiw I find "readability" to be a grandly misunderstood topic in software, so I'm probably not representative

I do AoC for fun, so I only think of perf when it's fun to or if the solution space my code searches is too large for more naive/fun solutions

βž• 1

this is also probably why I burn out on AoC every year when it hits double digits -- it typically becomes more of a slog at that point and less fun -- I already have a job that challenges me in that way and so my recreation doesn't have to

I do like to go back and check performance after solving it in my normal hacked up way. I get a little sad when I see my also hacked up Rust code solves it 10x faster with the same lack of initial care. I guess it doesn't mean anything but I wish we could just magically have Clojure be super fast lol (clojure is still 10x more fun to write though of course)

πŸ™Œ 1

@chase-lambert I'm curious to see some side-by-sides. People keep saying rust is great, but my initial take is that it's monstrously complex and forces you to deal with computer tedium. I'd be curious if you came up with relatively straightforward solutions.

Yeah, for example my first few days of 2015 were written how I normally would do Clojure and Rust I guess. When benchmarking them I see that huge performance gain with Rust. I should probably switch the apply to reduce and whatnot. Caveat: my idiomatic code back in 2015 might just suck in general but that's just when I tried some benchmarking recently https://github.com/chase-lambert/aoc-clojure/tree/main/src/aoc/2015 https://github.com/chase-lambert/aoc_rust/tree/main/aoc_2015/src

This is a great resource! Thank you!

I'm using this aoc tool called cargo-aoc though because it does the benchmarking for me but it shouldn't make much of a difference I think

Isn't the big trick to making rust easy just doing copy all the time instead of dealing with ownership?

I feel like someone told me that

I care of the performance when it seems like I’d learn something from it.

gah every other language is so clunky after doing clojure for 10 years. I know part of it is just that clojure is near at hand for me, but emotionally it's like watching kids derp around taking 10x the effort for simple tasks.

I mean that in as non-judgemental a way as possible. It's just my emotional (uninformed) reaction.

(Your code is very good btw. Wasn't a comment on that. I can understand it easily. It's the lang, not the writer.)

Rust definitely gets wild. I find it surprisingly straightforward (once you grok the borrow checker) for regular stuff especially considering how performant it is. It has some nice "high level" features. But when you start really getting into harder tasks, things get crazy quick and I run back to sweet, sweet Clojure.

Did some cryptography puzzles from https://cryptopals.com/ in Rust and found it less painful than i was expecting although I'm pretty sure i was cutting corners in a way that would be considered sloppy by proper rusties

.unwrap() all over the place - tis the season πŸŽ…

πŸ˜‚ 1

I got 50 stars last year with Clojure, and in the second half of the event I was optimizing every solution. This usually comes to: β€’ deftypes instead of maps β€’ arrays and unboxed numbers for anything heavy on the math β€’ iterators and loops instead of map/filter/etc. (this usually counts as a microoptimization and is unnecessary most of the time for AoC tasks) Overall, I'd say that if you picked the right algorithm (one that was intended by Eric for that task), you won't have to think about performance at all. But having a performance-optimized solution sometimes lets you succeed with a suboptimal (from an algorithmic standpoint) approach.

πŸ‘ 1

is the site down for anyone else?

oh, no, it works now

Yeah it goes down sometimes, it's just one guy's simple perl site for the most part πŸ˜„

πŸ˜… 1

I decided to try to use Pharo for development, at least to learn about gtoolkit. I am almost giving up - documentation is close to zero, lots of videos (no copy-paste to simplify things), and lots of missing things that I don't even know if it exist (like using capture groups in regexes)