This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-12-15
Channels
- # adventofcode (46)
- # announcements (3)
- # aws (7)
- # babashka (47)
- # beginners (86)
- # calva (40)
- # cider (8)
- # clj-kondo (22)
- # clojure (63)
- # clojure-europe (16)
- # clojure-hungary (3)
- # clojure-nl (1)
- # clojure-norway (46)
- # clojure-sweden (1)
- # clojure-uk (3)
- # clojuredesign-podcast (2)
- # conjure (4)
- # datalevin (1)
- # events (1)
- # fulcro (5)
- # graalvm (4)
- # honeysql (8)
- # hyperfiddle (15)
- # music (1)
- # off-topic (5)
- # pathom (7)
- # pedestal (1)
- # polylith (3)
- # portal (19)
- # quil (1)
- # re-frame (36)
- # releases (1)
- # specter (3)
- # sql (3)
- # timbre (11)
- # tools-deps (4)
- # xtdb (55)
array-map
ftw https://github.com/caseneuve/aoc2023/blob/master/day15/solution.clj
Very nice and concise, @UUAKPEMJ9! Mine is https://github.com/gveres/advent-of-code-2023-clojure/blob/main/src/day15.clj
@UUAKPEMJ9 I tried to port your solution to #C03U8L2NXNC and #C03QZH5PG6M but the number I get for my input for part 1 is too low, I'll double check in .clj now
Nothing elegant linear search on vector + rewriting was enough https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day15.clj
ah yes, it's a platform difference, with planck (self-hosted CLJS) I get the same answers as cherry/squint
lol, with @U1EP3BZ3Qโs solution I have the same problem for part 1 in CLJS
@UUAKPEMJ9 you're lucky here:
(class (reduce #(assoc %1 %2 %2) (array-map) (range 8)))
;; => clojure.lang.PersistentArrayMap
(class (reduce #(assoc %1 %2 %2) (array-map) (range 9)))
;; => clojure.lang.PersistentHashMap
@U1EP3BZ3Q Looks like a novice's luck! Was looking for exactly this kind of data structure and found it, but didn't read through all the caveats. Max key count of particular array-map
in my input is 6, so luck it is! But then -- what is the point of such behavior??
@UUAKPEMJ9 array-map is an optimization for small maps
when the map grows, it converts automatically to a hash-map, all for performance trade-offs
Search in array-map is linear, assoc/update/dissoc rewrites whole storage which is ok for maps with less than 9 elements.
The storage is simple Object array which keeps key1,val1,key2,val2,... keyn,valn that's why the order is preserved.
Thanks, @U04V15CAJ, @U1EP3BZ3Q. What do you think about replacing it with ordered-map
from flatland.ordered.map
?
you could do that, it's in babashka as well :) but maybe a nice challenge to solve it without it
in squint, which is based on JS objects, it's easy since they preserve insertion order
(defn lenses [input]
(reduce
(fn [acc [lab foc]]
(update acc (hash* lab) (if foc #(doto % (.put lab foc)) #(doto % (.remove % lab)))))
(zipmap (range 256) (repeat (new java.util.LinkedHashMap)))
(mapv #(re-seq #"\w+" %) input)))
seems to workonly for the first part, the second part doesn't work because of the mutability probably
Just for fun quickly sketched alternative assoc*
and dissoc*
to keep my original solution (mostly) intact (would need only to change the condition in focusing-powers
, and, obviously, exchange maps to vectors):
(defn assoc* [mx a b]
(let [i (.indexOf (mapv first mx) a)]
(if (< i 0) (conj mx [a b]) (assoc mx i [a b]))))
(defn dissoc* [mx a]
(let [i (.indexOf (mapv first mx) a)]
(if (< i 0) mx (into [] cat [(take i mx) (drop (inc i) mx)]))))
It's ~4 ms less performant than array|ordered-map
and it's +6 locs, but can live with it ๐Not seeing any difference on my machine (but still, the whole solution runs in ~20 ms).
Today I made liberal use of :pre
and :post
conditions. It seemed to go much smoother. Testing and typing helps sometimes who knew????
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day15/sol.clj
Whith the help of custom bare bones ordered map
(defn h [s] (reduce (fn [r c] (-> c int (+ r) (* 17) (rem 256))) 0 s))
(->> (str/split input #"\,")
(reduce (fn [acc s]
(let [[l v] (str/split s #"[\=\-]")
b (h l)
acc (vary-meta acc update :i (fnil inc 0))]
(if v
(update-in acc [b l] (fn [[k _]] [(or k (-> acc meta :i)) (read-string v)]))
(update acc b dissoc l))))
{})
(reduce (fn [acc [b m]]
(->> m
(sort-by (comp first second))
(map-indexed (fn [i [_ [_ v]]] (* (inc b) (inc i) v)))
(apply + acc)))
0))
https://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day15.clj Man, I needed a day this easy...
@U064J0EFR thank! the pre/post was indeed very useful also in squint, with that I detected that one thing came in as a string instead of a number which was caused by storing stuff in a JS object, changing that to a js/Map
fixed it!
https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBvcmlnaW5hbCBzb2x1dGlvbiBieSBAYmhhdW1hbjoKOzsgaHR0cHM6Ly9naXRodWIuY29tL2JoYXVtYW4vYWR2MjAyMy9ibG9iL21haW4vc3JjL2FkdjIwMjMvZGF5MTUvc29sLmNsagoKOzsgUmVtZW1iZXIgdG8gdXBkYXRlIHRoZSB5ZWFyIGFuZCBkYXkgaW4gdGhlIGZldGNoLWlucHV0IGNhbGwuCihkZWYgaW5wdXQgKC0%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxNSkpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMKICAgICAgICAgICAgIGZpcnN0CiAgICAgICAgICAgICAoc3RyL3NwbGl0ICMiXCwiKSkpCgo7OyBzcXVpbnQgdjAuNC44MiBkb2Vzbid0IGhhdmUgcmVtLCBuZXh0IHZlcnNpb24gd2lsbAooZGVmbiByZW0gW24gZF0KICAobGV0IFtxIChxdW90IG4gZCldCiAgICAoLSBuICgqIGQgcSkpKSkKCihkZWZuIGxlbnMtaGFzaCBbY2hzXQogICgtPj4gKG1hcCAjKC5jaGFyQ29kZUF0ICUgMCkgY2hzKQogICAgKHJlZHVjZQogICAgICAjKHJlbSAoKiAoKyAlMSAlMikgMTcpIDI1NikKICAgICAgMCkpKQoKOzsgcGFydCAxCiNfKC0%2BPiAobWFwIGxlbnMtaGFzaCBpbnB1dCkgKHJlZHVjZSArKSkKCihkZWZuIHBhcnNlLWluc3QgW3NdCiAgKGlmICguZW5kc1dpdGggcyAiLSIpCiAgICBbKHN1YnMgcyAwIChkZWMgKGNvdW50IHMpKSldCiAgICAodXBkYXRlIChzdHIvc3BsaXQgcyAjIlw9IikgMSBwYXJzZS1sb25nKSkpCgooZGVmbiB2ZWMtYXNzb2MgW2wgayB2XQogIHs6cHJlIFsodmVjdG9yPyBsKV0KICAgOnBvc3QgWyh2ZWN0b3I%2FICUpXX0KICAoaWYgKHNvbWUgI3trfSAobWFwIGZpcnN0IGwpKQogICAgKG1hcHYgIyhpZiAoPSBrIChmaXJzdCAlKSkgW2sgdl0gJSkgbCkKICAgIChjb25qIGwgW2sgdl0pKSkKCihkZWZuIHZlYy1kaXNzb2MgW2wga10KICB7OnByZSBbKHZlY3Rvcj8gbCldCiAgIDpwb3N0IFsodmVjdG9yPyAlKV19CiAgKHZlYyAocmVtb3ZlICMoPSBrIChmaXJzdCAlKSkgbCkpKQoKKGRlZm4gbWFwLWluc3QgW20gW2sgdl1dCiAgezpwcmUgWyhzdHJpbmc%2FIGspIChtYXA%2FIG0pXQogICA6cG9zdCBbKG1hcD8gJSldfQogICh1cGRhdGUgbSAobGVucy1oYXNoIGspCiAgICAoaWYgKG5pbD8gdikKICAgICAgICAgICAgIygoZm5pbCB2ZWMtZGlzc29jIFtdKSAlIGspCiAgICAgICAgICAgICMoKGZuaWwgdmVjLWFzc29jIFtdKSAlIGsgdikpKSkKCihkZWZuIHNjb3JlLXNsb3QgW2JveCBzbG90IFtrIGxlbl1dCiAgezpwcmUgWyhldmVyeT8gbnVtYmVyPyBbYm94IHNsb3QgbGVuXSldCiAgIDpwb3N0IFsobnVtYmVyPyAlKV19CiAgKCogKGluYyBib3gpIChpbmMgc2xvdCkgbGVuKSkKCihkZWZuIHNjb3JlLWJveCBbW2JveCB2ZWMtbWFwXV0KICAoLT4%2BIHZlYy1tYXAKICAgIChtYXAtaW5kZXhlZCAocGFydGlhbCBzY29yZS1zbG90IGJveCkpCiAgICAocmVkdWNlICspKSkKCjs7IHBhcnQgMgojXygtPj4gaW5wdXQKICAgICAgIChtYXAgcGFyc2UtaW5zdCkKICAgICAgIChyZWR1Y2UgbWFwLWluc3QgKG5ldyBqcy9NYXApKQogICAgICAgKG1hcCBzY29yZS1ib3gpCiAgICAgICAocmVkdWNlICspKQ%3D%3D
My https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_15_tokens.clj. Since I was having so much fun with them the other day, I wrote my upsert-lens
as a transducer.
Anyone else feels that day 15 is magnitudes easier than any of the previous 8-9 days? My feeling is that it's a very good fit for Clojurists, as we're indoctrinated in the "reduce using instructions from a data DSL" way of thinking(?). Anyway, I'm curious how people from other languages and disciplines will feel about it...
Last year I did AoC in Clojure. This year I do in Crystal. And when you are keen on functional style, it does not look bad at all. Check it out:
input = File.read("input/input15.txt").delete('\n').split(',')
def hash(str)
str.chars.reduce(0) { |acc, c| (acc + c.ord) * 17 % 256 }
end
ans = input.sum { |s| hash(s) }
puts "Part 1: #{ans}"
boxes = Array.new(256) { |_| Hash(String, Int32).new }
boxes = input.reduce(boxes) do |boxes, step|
label, op, focal = step.partition /[=-]/
box = hash(label)
case op
when "="
boxes[box][label] = focal.to_i
when "-"
boxes[box].delete label
end
boxes
end
ans = boxes.each_with_index.sum do |(box, i)|
box.each_with_index.sum do |((_, focal), k)|
(i + 1) * (k + 1) * focal
end
end
puts "Part 2: #{ans}"
Nah, it should be dead easy in any language:) Bad difficulty pacing from Eric this year.
I think Clojure is an excellent lang for these problems. I.E. I donโt think the problems are good for Clojure but rather the other way around. Clojure has strengths.
This year was super easy so far, no problems where I would get stuck for hours and a lot of really easy ones. Iโve solved all years and this one might be the easiest one of them all, so far. The 2015 was also quite easy, perhaps easier than this.
That crystal solution looks really clean, what really makes it work well here is the fact that you can always fetch the index of the element in a collection during reduce and such. In clojure we have to do with map-indexed and and then you need to pack and unpack tuples everywhere
Actually you may implement reduce-indexed
with one additional line (*vary-meta* acc update :index (*fnil* inc 0))
without altering initial collection and dealing with tuples. Of course, if acc is not of primitive type. Don't forget - we are not in Haskell, Clojure meta rules! ๐
(reduce (fn [acc c]
(let [i (-> acc meta :i (or 0))]
(assoc (with-meta acc {:i (inc i)}) c i)))
{} "hello!")
=> {\h 0, \e 1, \l 3, \o 4, \! 5}
Yeah, I only looked at the problem this morning and my reaction was, "where's the trick?"