This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-03
Channels
- # adventofcode (107)
- # announcements (1)
- # asami (14)
- # babashka (67)
- # beginners (89)
- # calva (34)
- # cider (17)
- # clj-kondo (5)
- # cljs-dev (2)
- # clojure (57)
- # clojure-europe (52)
- # clojure-india (1)
- # clojure-italy (1)
- # clojure-losangeles (2)
- # clojure-nl (6)
- # clojure-uk (39)
- # clojurescript (40)
- # community-development (3)
- # conjure (3)
- # cursive (17)
- # datomic (11)
- # docker (13)
- # events (3)
- # figwheel-main (3)
- # fulcro (12)
- # graalvm (7)
- # holy-lambda (7)
- # honeysql (9)
- # introduce-yourself (5)
- # malli (9)
- # minecraft (3)
- # missionary (21)
- # nextjournal (7)
- # off-topic (52)
- # pathom (3)
- # polylith (11)
- # portal (3)
- # re-frame (21)
- # reagent (34)
- # reclojure (7)
- # reitit (1)
- # reveal (11)
- # shadow-cljs (68)
- # tools-build (12)
- # tools-deps (5)
- # vim (4)
- # xtdb (9)
I'm super boring about my solutions. here's days 1 and 2 https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527
the same
and the part two has a pitfall ^_^
@U067R559Q what pitfall did you notice?
@U06B54Y95 actually it wasnât a pitfall, I just didnât read the description carefully.
@U067R559Q Yeah, when the problem text is that long and involved, itâs so easy to get some little detail wrong. So to me it had several potential pitfalls there! Not to mention the usual risks of off-by-ones and edge cases. I couldnât use max-key vs min-key in part 2 because theyâre not complements like > and <= are. @U1NLKFVC4 I copy/pasted on my first pass, but couldnât stand to look at it. đ
𧔠Day 3 answers thread: post your answers here
Ugly code ...
(ns aoc2021.day3
(:require [ :as io]
[clojure.string :as str]
[clojure.edn :as edn]))
(defn parse-binary [s]
(edn/read-string (str "2r" (str/triml s))))
(def input
(->> (io/resource "day3.txt")
io/reader
line-seq))
;; Part 1
(let [s (for [index (-> input first count range)
:let [{zeroes \0
ones \1} (->> input
(map (fn [bin] (nth bin index)))
frequencies)]]
(if (< zeroes ones)
[\1 \0]
[\0 \1]))
gamma (->> s
(map first)
str/join
parse-binary)
epsilon (->> s
(map second)
str/join
parse-binary)]
(* gamma epsilon))
;; Part 2
(defn most-common-bit [coll index]
(let [{zeroes \0
ones \1} (->> coll
(map (fn [x] (nth x index)))
frequencies)]
(if (<= zeroes ones) \1 \0)))
(defn least-common-bit [coll index]
(let [{zeroes \0
ones \1} (->> coll
(map (fn [x] (nth x index)))
frequencies)]
(if (<= zeroes ones) \0 \1)))
(let [[[oxygen] _] (->> [input 0]
(iterate (fn [[s index]]
(let [bit (most-common-bit s index)]
[(filter (fn [n]
(= (nth n index) bit))
s)
(inc index)])))
(drop-while (comp not #{1} count first))
first)
[[co2] _] (->> [input 0]
(iterate (fn [[s index]]
(let [bit (least-common-bit s index)]
[(filter (fn [n]
(= (nth n index) bit))
s)
(inc index)])))
(drop-while (comp not #{1} count first))
first)]
(* (parse-binary oxygen)
(parse-binary co2)))
(defn read-data []
(->> (slurp "data/day3.txt")
clojure.string/split-lines
(map (fn [s]
(->> (seq s)
(map #(- (int %) (int \0))))))))
(defn to-decimal [ns]
(read-string (apply str "2r" ns)))
(defn part1 []
(let [data (read-data)
n (count data)
counts (apply map + data)
v1 (map #(if (< % ( * n 0.5)) 1 0) counts )
v2 (map #(if (< % ( * n 0.5)) 0 1) counts )]
(* (to-decimal v1)) (to-decimal v2)))
(defn bit-to-keep-o2 [ones zeroes]
(cond
(= ones zeroes) 1
(> ones zeroes) 1
:else 0))
(defn bit-to-keep-co2 [ones zeroes]
(cond
(= ones zeroes) 0
(< ones zeroes) 1
:else 0))
(defn part2-rating [f ratings]
(loop [rs ratings
n 0]
(if (= 1 (count rs))
(to-decimal (first rs))
(let [counts (->> rs
(map #(nth % n))
(reduce +))
keep-bit (f counts (- (count rs) counts))]
(recur (filter #(= (nth % n) keep-bit ) rs)
(inc n))))))
(defn part2 []
(let [data (read-data)]
(* (part2-rating bit-to-keep-o2 data)
(part2-rating bit-to-keep-co2 data))))
Any improvements welcome.Maybe Iâll refact it later ^_^ https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_03.clj
Btw, I found out that to get nice code coloring, start by clicking the lightning bolt in the lower left of the composition box, then select âcreate a text snippetâ. It supposedly has language auto-detect but I havenât tried it. It also doesnât color it right away - takes a minute or so after you post!
this is my solution
; part 1
(defn rate [key-compare input]
(->> input
(apply map vector)
(map frequencies)
(map #(key (apply key-compare val %)))
string/join)
)
(def gamma (rate max-key large))
(def epsilon (rate min-key large))
(* (Integer/parseInt gamma 2) (Integer/parseInt epsilon 2))
; part 2
(defn rate [comparison input]
(loop [pos 0
input input]
(if (= 1 (count input))
(first input)
(let [{zeros \0 ones \1} (group-by #(nth % pos) input)]
(if (comparison (count zeros) (count ones))
(recur (inc pos) ones)
(recur (inc pos) zeros))))))
(def oxygen (rate <= large))
(def co2 (rate > large))
(* (Integer/parseInt oxygen 2) (Integer/parseInt co2 2))
https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day03.clj
surprised I donât see anybody above using bit-test
bit-set
etc! https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/03.clj
https://github.com/RedPenguin101/aoc2021/blob/main/day03.md https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day03.clj Haven't read any other solutions yet, but whenever there's one of these binary problems I always feel like I've missed a trick by not actually using any bitwise operators. Like that plane seating problem, I forget which year.
Even if I remove all the comment blocks, I'm still pretty long today. So a link instead - https://github.com/coyotesqrl/advent-of-code/blob/main/src/coyotesqrl/2021/day3.clj
Like @U1EP3BZ3Q, I also used bit-and
and bit-not
in part 1. Both parts today, in fact, have that inverse, mirror symmetry. I used filter
/`remove` to get to the O2/CO2 values.
I have the feeling this could be a one-or-two liner so it's probably more verbose than necessary: https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_03-clj But it runs in insignificant time with bb (60ms including startup).
Hereâs mine. I used core.matrix and didnât end up using it much. I have the feeling thereâs a function Iâm missing that wouldâve made things easier.
Looking forward to reading othersâ solutions later to compare, but gotta do some real work first đ
I'll paste my solution here. I feel like I made it too complicated. I'm still too reliant on loops - Feedback is very welcome
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d03.clj
after a vain search for bitwise brilliance (deeper than bit-test
and bit-and-not
I just went with strings. I like my part1 (no temporary variables), but p2 still needs work.
My unreadable solution of part 2, making each bitstring a function that pushes a counter up or down and adds itself to a set, the sign of counter then picks next set of bitstrings to inspect.
(defn pick [l test]
(let [make-fn (fn [idx f]
(fn [[n m]] [(f n) (update m f (fnil conj #{}) idx)]))
to-weird-format (fn [a]
(map-indexed #(mapv (partial make-fn %1) (mapv {\1 inc \0 dec} %2)) a))
pos-or-neg (fn [xs idx]
(reduce #(%2 %1) [0 {}] (map #(nth % idx) xs)))
l2 (to-weird-format l)]
(loop [candidates l2, bit-index 0]
(let [[n m] (pos-or-neg candidates bit-index)
next-indices (if (test n) (m inc) (m dec))]
(if (< 1 (count next-indices))
(recur (reduce #(conj %1 (nth l2 %2)) [] next-indices)
(inc bit-index))
(nth l (first next-indices)))))))
(defn sol [input-string]
(apply * (map #(Integer/parseInt % 2)
(map #(pick (str/split-lines input-string) %) [(partial <= 0) (partial > 0)]))))
a little late to the party but I finally found time to do it today! https://github.com/theianjones/aoc_2021/blob/master/src/theianjones/aoc-2021/d03/answer.clj
This one felt like a chore for some reason https://gist.github.com/galuque/2fec8a886e1cb24f17662fda438d7e83
https://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day3.clj - here is mine. somehow managed to reuse most of the extract logic from part 1. But accessing things positionally in Clojure always feels kind of dirty to me đ
I loved the day 3 puzzle. Hereâs a link to my blog about my solution and its many refactorings, with a link to the source at the top. I really enjoyed making composable functions, like most-common-bit
, least-common-bit
, one-pass-bit-check
, and multi-pass-bit-check
that all built up my gamma, epsilon, O2, and CO2 calculations. Very fun day!
https://github.com/abyala/advent-2021-clojure/blob/main/docs/day03.md
Oh man, part 2 ate me alive. I don't know why I struggled so much but that's kind of sad this early in the game. Haven't had a chance to process and clean it up. I just can't figure out how to think in terms of reduce
. https://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2021/day_03.clj
I'm looking forward to reading these answers and figuring out how to approach this in a more simple manner. Things got ugly quick! lol
my solution: https://github.com/euccastro/advent-of-code-2021/blob/main/day3.clj I have the feeling that I left some mathematical insight on the table, but this is much cleaner than the first thing that I got to work
@U067R559Q great one! part 1 esp. blew my mind. this is maybe evil, but (sort-by (juxt second first))
could be (sort-by reverse)
in this case?
Day 3, part 1 (I'll post part 2 when I'm not utterly ashamed of it đ)
(defn get-key-with-highest-val [m]
(if (>= (m \1 0) (m \0 0))
\1
\0))
(defn flip-bits [s]
(map (fn [i] ({\1 \0 \0 \1} i)) s))
(defn binary-str->int [s]
(Integer/parseInt s 2))
(defn char-seq->str [cs]
(->> (map str cs)
(str/join "")))
;; part 1
(let [input (->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day3" parser)
(apply map vector)
(map frequencies))
Îł-bin (->> input
(map get-key-with-highest-val))
Δ (->> γ-bin
(flip-bits)
(char-seq->str)
(binary-str->int))
Îł (->> Îł-bin
(char-seq->str)
(binary-str->int))]
(* Δ γ))
OK, I'm still ashamed of it but :man-gesturing-no: it's 2am here...
(defn has-v-at-idx [idx v xs]
(= v (nth xs idx)))
(defn parser [l]
(map identity l))
(defn reduce-binary-over-f [input f]
(loop [input input, idx 0]
(if (= 1 (count input))
(-> (first input)
char-seq->str
binary-str->int)
(let [bits-at-idx (nth (apply map vector input) idx)
most-common (->> (frequencies bits-at-idx)
(get-key-with-highest-val)
(f))]
(recur (filter (partial has-v-at-idx idx most-common) input)
(inc idx))))))
(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day3" parser)
oxygen-generator (reduce-binary-over-f input identity)
oxygen-scrubber (reduce-binary-over-f input #({\1 \0 \0 \1} %))]
(* oxygen-generator oxygen-scrubber))
you don't need to wrap the map in a function literal; it's already a function as is
a late, long-winded submission: https://samadams.dev/2021/12/03/advent-of-code-day-3.html
@U067R559Q I might be misreading but I think your gamma and epsilon ratings are flip-flopped đ
@U016C0EGHUN youâre right, I was polishing the code and mixed them up. But yesterday evening I refactored the code and there is no even names, just one single thread :star-struck: https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_03.clj
@U65FN6WL9 revers wonât help here
; Execution error (IllegalArgumentException) at zelark.aoc-2021.day-03/eval9970 (REPL:47).
; Don't know how to create ISeq from: clojure.core$reverse
@U067R559Q it seems you have the arguments swapped in your experiment? anyway, you're right it doesn't work, but for a reason that is surprising to me: clojure doesn't know how to compare lists (while it can compare vectors):
(sort '[(3 4) (1 2)])
clojure.lang.PersistentList cannot be cast to java.lang.Comparable
(sort-by (comp vec reverse) {:a 3 :b 1})
;; => ([:b 1] [:a 3])
Yes, the actual exception is âclojure.lang.PersistentList cannot be cast to java.lang.Comparableâ
> I loved the day 3 puzzle. Hereâs a link to my blog about my solution
> and its many refactorings, with a link to the source at the top. I
> really enjoyed making composable functions, like most-common-bit
, least-common-bit
, one-pass-bit-check
, and multi-pass-bit-check
that all built up my gamma, epsilon, O2, and CO2 calculations. Very fun day!
@U01HHBJ56J1 this was a great read and a nice solution, thanks!
a bit late to the party, but here's mine! https://github.com/FelipeCortez/advent-of-code/blob/master/2021/03.clj
looking into the details of clojure list/vector comparison I realized that I could shorten the following thread-last sequence in my solution:
(group-by #(nth % idx))
(sort-by key)
(map second)
(sort-by count)
(where I felt clever for relying on the stability of sort-by
so the order in the first sort would be a tie-breaker in the second one) to just
(group-by #(nth % idx))
vals
sort
because vectors will first be compared by length and then lexicographically on ties, which is exactly what I wantproud of part 2 https://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day3.clj - now I can read your solutions and go aha 7 times đ
https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527#file-3-1-clj
again a very boring solution by me
Why do you @U04V15CAJ do this in your Day 3 solution?
(if more-ones?
(conj bits 1) (conj bits 0))
I don't understand why you are shifting the bits to the left with another 0 or 1 on it...this is not bit shifting per se, it is gradually building up the answer. for every position, determine if that column has more ones or zeros, and append accordingly either 1 or 0 to the answer
I'm in that horrible situation where my code runs on the test data for day 3, and produces correct answer, and runs on the full data without crashing, but the answer is wrong... gah
Maybe youâve missed this âIf `0` and `1` are equally common, keep values with a `1` in the position being considered.â and this âIf `0` and `1` are equally common, keep values with a `0` in the position being considered.â
hmmm. That will be it, I assumed since the page doesnt explain what to do in the event of a tie that its set to never occur, thanks!
It explains (for part 2): "If `0` and `1` are equally common, keep values with a `1` in the position being considered."
omg, i was debugging and had a rogue (take 3)
in! argh! That I forgot to take out once I was using the real data. IT works and I have part 1 completed.
TIL about: https://github.com/clojure/data.int-map seems very useful for AOC
does anyone else find themselves more interested in refactoring part1 so that it can be solved using part2 code, rather than going for sheer speed?
Yes, I am actually focusing on this, this year. I try to write part 1 in such a way that it can be re-used or easily refactored for part2. The less effort required for part 2 means I did a decent job with part 1. Major refactor means I may have made it to specific.
Yeah. I find no joy in just doing the quickest thing, it's far more fun to have unit tests and nice abstractions. Also fun to properly benchmark multiple approaches etc.
This is my first year tracking my progress on a private leaderboard, so I hacked up a pretty gross solution to part 1. After I read part 2, it didn't feel right to do the same. I did refactor part 1 and then came back and finished part 2 this morning. I'm pretty sure I'll end up refactoring it a couple more times.
awesome. sounds like I am in good company, then đ
I mean, I can't be the only person with GitHub Actions running my tests and generating Marginalia docs, right? Right?
All in all, I think speed is rather useless.. Instead, I want to do it badly first, so I can build buckets to put the âhow to do it rightâ knowledge into..
I like to get to a solution as fast as i can and then spend the rest of the day thinking about better ways, that allows me to learn a lot from other people solution throughout the day with no guilt :D
+1 to get solution as quickly as you can and then if you find it interesting enough optimise it đ
Stats show a dip today on part2, almost half of people decided to skip it https://adventofcode.com/2021/stats
I can only assume it was the big wall of text. I know I couldnt process that while I was half asleep last night.
I managed to get part 1 done during a meeting today at work, just haven't had time yet today to even look at part 2