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."
ah, im on part 1!
ah! do you have a tie in your dataset? (I don't have, it may happen in part 2)
I don't, as even putting that condition I'm getting back same answer
epsilon is always just gamma with the bits flipped right?
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.
wall of text today 😄
I didn't do part 2 only due to too long didn't read
meme from reddit:
At least you wouldn't have the leaderboard filled in 2 minutes!
TIL about: https://github.com/clojure/data.int-map seems very useful for AOC
if your ints are sequential, you can just use a vector
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.
Rich always solves part 2 while hammoking on part 1
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.
Yeah, I waisted time debugging code while the problem was in my reading skils
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
And I'm going out tonight, so will have to do part 2 tomorrow before I do day 4
That a good point, tomorrow is a weekend, people will have plenty of time to catch up
for me at least, part 2 was a considerable step up in difficulty from part 1
just finished day3, it's 1:46 am here and I'm pretty drunk. Very not proud of my code
I'm super boring about my solutions. here's days 1 and 2 https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527
sick. I learned about the args to partition from this
Done with day3 but it’s too ugly to post before some cleanup. :)
the same
and the part two has a pitfall ^_^
hah did everyone copy and paste their code for part2?
@zelark what pitfall did you notice?
@mchampine actually it wasn’t a pitfall, I just didn’t read the description carefully.
@zelark 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. @peterc I copy/pasted on my first pass, but couldn’t stand to look at it. 🙂
🧵 Day 3 answers thread: post your answers here
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
https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day03.clj
https://github.com/DeLaGuardo/adventofcode2021/blob/main/src/aoc/day_3.cljc
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
I used bit-not and bit-and in part 1
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 @tsulej, 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.
https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day03.clj
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
oh yeah, frequencies would have helped in part one
TIL (or was reminded of) %& in function literals
@zelark 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 🙅♂️ 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
What do you mean ?
#({\1 \0 \0 \1} %) could be just {\1 \0 \0 \1}
that part 2 solution looks fine to me, nothing to be ashamed of
ah okay! I see, thank you!
kudos on the greek chars for part 1! 😄
https://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_3.clj
Basically the same as 3-4 others I saw.
I’m kinda convinced there’s no pretty way to do Part 2.
a late, long-winded submission: https://samadams.dev/2021/12/03/advent-of-code-day-3.html
Maybe tomorrow I’ll benchmark a frequencies -based solution too
@zelark I might be misreading but I think your gamma and epsilon ratings are flip-flopped 🙂
@sam.h.adams 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 🤩 https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_03.clj
@euccastro 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$reverseproud 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
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!
Why do you @borkdude 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...eh, lemme check
honest answer: I don't remember, day 3 is already too long ago ;)
alright, never mind. thanks anyway
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
indeed
@zelark 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])
of course once you have to (comp vec reverse) it stops being that much prettier
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!
@abyala 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
oh, I can do str/join instead of apply str. nice!
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 want