This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-12-04
Channels
- # adventofcode (161)
- # asami (2)
- # babashka (56)
- # beginners (128)
- # calva (57)
- # cider (10)
- # circleci (1)
- # clj-kondo (4)
- # clojure (13)
- # clojure-europe (44)
- # clojure-france (32)
- # clojure-italy (3)
- # clojure-nl (18)
- # clojure-spec (7)
- # clojure-uk (26)
- # clojurescript (18)
- # code-reviews (15)
- # community-development (7)
- # conjure (5)
- # cryogen (8)
- # cursive (31)
- # datomic (18)
- # emacs (8)
- # events (4)
- # figwheel-main (7)
- # fulcro (42)
- # juxt (3)
- # kaocha (58)
- # lambdaisland (1)
- # malli (1)
- # minimallist (1)
- # pathom (11)
- # pedestal (9)
- # re-frame (28)
- # reagent (20)
- # reclojure (4)
- # releases (1)
- # reveal (23)
- # schema (2)
- # shadow-cljs (7)
- # test-check (67)
- # xtdb (23)
I spent a lot of time counting all the trees passed vertically for when the sled goes 1 right, 2 down. I don’t know why I started to think I should do that when I didn’t do it horizontally… Anyway, if someone ever needs a sequence of x-deltas for a instructions like “x right, y down, forever”, here goes:
(defn dxs [dx' dy']
(map (fn [line dx dy]
(* (+ line dy) dx))
(range)
(repeat dx')
(cycle (range dy'))))
¯\(ツ)/¯I’m a bit stuck on day 3, step 2. I get the right answer for the sample data, but too low for the real input. Not sure how I should go about debugging it. My solution looks like so, so far. (In the reply.)
(defn landing [dx line]
(->> line
(seq)
(repeat)
(flatten)
(drop dx)
(first)))
(defn count-trees [[dx dy] woods]
(->> woods
(take-nth dy)
(map landing (map #(* % dx) (range))) ; is (take-nth dx (range)) better?
(filter #{\#})
(count)))
(comment
(def input (util/fetch-input 3))
(as-> input $
(s/split-lines $)
(map #(count-trees % $) [[1 2] [3 1] [5 1] [7 1] [1 2]])
(apply * $)))
1. replace
(repeat)
(flatten)
with (cycle) for probably x2 speedup
2. replace (cycle) with (mod dx line-len) for next x5-x10 speedup(let [s (str/join (range 1000))]
(time (nth s 2000))
(time (first (drop 2000 s))))
"Elapsed time: 0.01144 msecs"
"Elapsed time: 0.264392 msecs"
Replacing drop, first with nth gained me x1.2-ish, but I’ll of course keep that and celebrate the speed gain, since it is WAY clearer.
(time (nth (cycle "abcd") 100000))
"Elapsed time: 7.717277 msecs"
=> \a
(time (nth "abcd" (mod 100000 (count "abcd"))))
"Elapsed time: 0.093352 msecs"
=> \a
This is super helpful to me. I often reach for mod
quickly. This time it was much easier for me to visualize it if I actually repeated the pattern indefinitely. But I should of course have remembered/realized to translate it to mod
once it worked.
I updated my input-fetcher to read the cookie from a file instead, like @plexus does in his bash script: https://gist.github.com/PEZ/bcd23b9bc099b8b21a41c8c9de78a0f4
Live stream for day 4 starting soon https://youtu.be/K3f10iwxtOw
And the recording: https://youtu.be/XaXB0kbpvjw Code: https://github.com/lambdaisland/aoc_2020/
oh … I feel stupid, I did not think about that (str/split real-input #"\R\R")
https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle04.clj#L35-L44 the fields are not used anywhere, so they could be removed ^_^
What does #"\R\R"
match on? From context it looks like a double carriage return, but is it different from #"\r\r"
? https://regexr.com/ says \R
is just an escaped R, which it clearly isn't in this case.
it matches "\r" "\n" "\r\n" or a number of unicode newline characters. It does not backtrack between "\r\n", so #"\R\R" will match "\r\r" but not "\r\n" (it will match "\r\n\r\n")
I woke up too late today, bye bye leaderboard 😢
yeah i went to bed early and didn't do yesterday's problem until right before tonight's so also dropped 😞
so true, and so boring
I was just thinking "if this doesn't work from the first try it's going to suck to debug", but luckily it did
yeah can't say day 4 was particularly interesting... just tediously converting rules into code
so far the puzzles have been surprisingly easy though... was it like this in the past? it's been two years since I participated so maybe I remember it wrong, I guess it'll get harder in a few days.
Last year, for some of the puzzles, we built up a little byte code VM and our inputs were programs, it was pretty cool
Yeah, I loved it.
Last year, the first a bit challenging puzzle for me was on day 10, then day 12.
Day 22, part 2 was pretty hard for the most of the participants.
Yes, it gets harder, and perhaps this year they toned it down a little bit, because i remember last year the were some frustrated participants.
It seems to me the past years I have done it, it gets steeper pretty fast after the first 3 or 4 days. It also tends to go back an re-factor off of your old solutions, so it’s hard to jump right in if you get behind.
last year day 3 was already challenging. If you look at stats https://adventofcode.com/2019/stats you can find where people have dropped off. Like days 3, 7, 18
Last year became really challenging for me, but first four days were similar to this year. It was interesting last year with puzzle inputs being programs in a fictional language called intcode you fed in various ways to your own interpreter(s) that you build up over the days with various stories around it (having a robot that runs on a computer that has to perform certain tasks by feeding it input and the coordinates it spit out in return will display a word which is your answer, stuff like that). Also a puzzle that could best be solved using trigonemetry and one with fast fourier transforms. Was magical and instructive.
My solution to day 4: https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_4.clj
@plexus I used Regal 🙂
I am happy I spent time to get familiar with it, it might be useful one day.
That was way harder than it needed to be.. 😉. I really need to learn my destructuring better..
Not super happy with what I came up with today. But I'm still new to clojure https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/04.clj

indeed very nic
always fun to see core.match!
Also, if you want to destructure map keys into vars with the same name, you can use the handy :keys
syntax (defn validate-passport-fields [{:keys [ecl pid eyr hcl byr iyr hgt]} ,,,)
Missed my alarm, tedious puzzle luckily everything worked first try
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day4.clj
https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day04.cljc
AOC made bad job generating invalid passports 😆 you code proves that • all years fields are actually numbers • height does not have other text than number and unit of measure • documents do not have keys other than explicitly specified
(remove #(not-empty (dissoc % "hgt" "byr" "eyr" "iyr" "ecl" "hcl" "cid")))
and
(defn parse-int [s else]
(try
(Integer/parseInt s 10)
(catch Exception e else)))
(parse-int "foo" -1)
=> -1
would fix thatMy solution to day 4, but I’m going to refactor it https://github.com/zelark/AoC-2020/blob/72968c3e2baa8fcb2a2a5a0ff84d9a6fb689f644/src/zelark/aoc_2020/day_04.clj#L1
a refactored version https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_04.clj
and mine solution (possibly over-engineered 🙂) https://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day04.clj
I think it is super nice. I learn a lot by looking at it. One thing makes me wonder “why?” though, and that is your between?
function. Is (partial between? 1920 2002)
more readable to you than #(<= 1920 % 2020)
?
https://redpenguin101.github.io/posts/2020_12_04_aoc2020_day4.html - clojure.spec seems tailor-made for this 🙃. No-one else seemed tempted though? Just not worth it for such a simple use case?
I've given up on specs, but when I got a wrong answer regretted it. Spec's explain would be very useful to debug which rule invalidated an entry
I was in a hurry. Would have loved to use Malli or spec
I solve the puzzle using Minimallist, a library inspired by Malli and Spec. https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_4.clj
My solution to Day 4 with clojure.spec: https://github.com/benfle/advent-of-code-2020/blob/main/day4.clj
Great to see someone use spec! My solution is very boring, I’m sure parse-passport
and valid-hgt?
could be more terse, but it was a bit to boring to refactor. https://github.com/motform/advent-of-clojure/blob/master/src/advent-of-clojure/2020/four.clj
Also, general question! Dones anyone have any examples of fancy ways of doing validation? Rule based systems?
My day 4. Not a great solution, but it worked in the end. https://gist.github.com/stuartstein777/7b69f6f39fe44669c77e935ba1249aec
I am really glad I used spec for part 1 😄 First practical use of spec for me:
(def text (slurp "adv4.input.txt"))
;(def text "ecl:gry pid:860033327 eyr:2020 hcl:#fffffd\nbyr:1937 iyr:2017 cid:147 hgt:183cm\n\niyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884\nhcl:#cfa07d byr:1929\n\nhcl:#ae17e1 iyr:2013\neyr:2024\necl:brn pid:760753108 byr:1931\nhgt:179cm\n\nhcl:#cfa07d eyr:2025 pid:166559648\niyr:2011 ecl:brn hgt:59in")
(defn parse-line [l]
(let [
psa (string/split l #"[\s+]")
pa (map #(string/split %1 #"\:") psa)
ma (map (fn [p] {(first p) (second p)}) pa)
m (apply merge ma)]
m))
(def entries (map parse-line (string/split text #"\n\n")))
(s/def ::byr (s/and string? #(<= 1920 (bigint %1)) #(>= 2002 (bigint %1))))
(s/def ::iyr (s/and string? #(<= 2010 (bigint %1)) #(>= 2020 (bigint %1))))
(s/def ::eyr (s/and string? #(<= 2020 (bigint %1)) #(>= 2030 (bigint %1))))
(s/def ::hgt (s/and string? (s/or ::in #(re-matches #"\d{2}in" %1) ::cm #(re-matches #"\d{3}cm" %1))))
(s/def ::hcl (s/and string? #(re-matches #"\#[0-9a-f]{6}" %1)))
(s/def ::ecl #{"amb" "blu" "brn" "gry" "grn" "hzl" "oth"})
(s/def ::pid (s/and string? #(re-matches #"[0-9]{9}" %1)))
(s/def ::passport
(dict {"ecl" ::ecl
"pid" ::pid
"eyr" ::eyr
"hcl" ::hcl
"byr" ::byr
"iyr" ::iyr
"hgt" ::hgt}))
(def v (count (filter #(s/valid? ::passport %1) entries)))
(println "Valid: " v " total " (count entries))
@USAGL3YUS As the topic says, please put spoilers in thread replies. Thank you.
links to code are also ok
Right, sorry i'll use thread replies or links next time.
Thanks for the hint, @U01CNM6254M - I saw that in other submissions. Lots of improvements to make!
another spec sol’n. To handle part1 being less specific, I would up with a non s/keys
spec for it. Any ideas there? I didn’t want to start undef’ing specs for half the problem.
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d04.clj
i have unit tests that verify part-1 and part-2 are still correct as I refactor and optimize, so I need both parts to work at same time.
btw, you could a bit simplify the spec for part 1
(every? (partial contains? %) required-fields)
would work
are you assuming for day4, part1 that the “values” are always non-empty?
One thing I learned today is (<= 150 height 193)
- which is a nice readable short form for (and (…) (…))

;; part 1
(def input (str/split-lines (slurp "resources/day05.data")))
(def fblrbits {\F 0 \B 1 \L 0 \R 1})
(defn seatcode [v]
(-> (apply str (map fblrbits v)) (Integer/parseInt 2)))
(def codes (map seatcode input))
(apply max codes)
;; part 2
(let [dc (partition 2 1 (sort codes))]
(inc (ffirst (filter (fn [[a b]] (= 2 (- b a))) dc))))
Explanation:
Part 1: FBLR code is just binary. Convert to 1's and 0's and then to base 10.
Part 2, You’re looking for a gap. Sort the codes and make pairs of (code, nextcode). Where that difference is 2, your seat number is in-between them, so add one to the first value.Definitely more verbose than the previous one 🙂. This is my post-submission cleaned-up version: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day05bis.clj
Hi 👋 here's https://github.com/ocisly/advent2020/blob/94b52d8bb63865a8ace75f34226f6acb390c69ef/day-5.clj#L5-L36
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_5.clj is here.
https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle05.clj
https://github.com/jreighley/aoc2020/blob/master/src/day5.clj. Kinda messy — I always feel clever when I can map gibberish data to functions.
with clojure.set
I go for readability with some lets
. https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d05.clj
(def l->b {\B 1 \F 0 \R 1 \L 0})
(def powers-of-2 (iterate (partial * 2) 1))
(->> s
(map l->b)
reverse
(map * powers-of-2)
(apply +))
My final decode is
(defn decode [code]
(-> (str/escape code {\F 0 \L 0 \B 1 \R 1})
(Long/parseLong 2)))
That’s all you need 🙂https://redpenguin101.github.io/posts/2020_12_05_aoc2020_day5.html - I didn't pick up on the 'trick', very cool though! Even without it it can be solved very concisely.
I'm also linking to and trying to summarize and comment on other peoples solutions on that page, hope no-one minds
My day 5 solution: https://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day05.clj
https://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day5.clj
(ns advent.day5
(:require [advent.core :as core]
[clojure.string :as s]))
(defn seat-id [boarding-pass]
(-> boarding-pass
(s/replace #"[FL]" "0")
(s/replace #"[BR]" "1")
(Integer/parseInt 2)))
(->> (core/input-file "day5.txt")
(map seat-id)
(reduce max))
;; => 998
(defn my-seat? [[a b]]
(= 2 (- b a)))
(->> (core/input-file "day5.txt")
(map seat-id)
sort
(partition 2 1)
(filter my-seat?)
first
first
inc)
;; => 676
I thought the partition
for part 2 was clever, but wondering if theres a better way to do the filter, first, first, inc chain?@U0ESCTA1E yes, as Arne showed you could use some
instead.
(some (fn [[lo hi]] (when (= (+ lo 2) hi) (inc lo))))
;; day 5 super golf
(let [ec #(-> (str/escape % {\F 0 \B 1 \L 0 \R 1})
(Integer/parseInt 2))
sc (sort (map ec (str/split-lines
(slurp "resources/day05.data"))))
p2 (ffirst (drop-while #(apply = %)
(partition 2 (interleave (iterate inc (first sc)) sc))))]
{:part1 (last sc) :part2 p2})
my day 5, didnt pick up on the trick until I was nearly done but still fairly happy with the result (I did a scala solution using the trick afterwards) https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/05.clj
scala version if anyone cares to see that: https://github.com/listba/advent-of-code-2020/blob/master/scala/src/main/scala/aoc2020/solutions/day-05.scala
Interesting to see all different/similar solutions 🙂 Here's my take https://github.com/teppix/advent-of-code-2020/blob/main/src/advent/day05.clj Used bit-shifting instead of the '2r' trick, but same idea.
Well, that was https://github.com/ocisly/advent2020/blob/1a4b5d46c17a67b86b274e12a37a13cd5d035b92/day-6.clj#L5-L11!

Mine was basically the same as Adam’s, just more verbose 🙂. https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day06.clj
(->> (slurp "input6.txt")
((fn [v] (str/split v #"\n\n")))
(map str/split-lines)
(map (fn [xs] (-> xs str/join (str/split #""))))
(map frequencies)
(map keys)
(map count)
(apply +))
(->> (slurp "input6.txt")
((fn [v] (str/split v #"\n\n")))
(map str/split-lines)
(map (fn [xs] [(count xs) (-> xs str/join (str/split #""))]))
(map (fn [[count xs]] (filter #(= count %) (vals (frequencies xs)))))
(map count)
(apply +))
https://github.com/jreighley/aoc2020/blob/master/src/day6.clj. I really seem to like sets this year.
Mine looks similar to others..
;; part 1
(def input
(->> (slurp "resources/day06.data")
str/split-lines
(partition-by empty?)
(take-nth 2)))
(apply + (map #(count (set (apply str %))) input))
;; part 2
(defn groupcnt [l]
(count
(for [x (set (apply str l))
:when (every? #(str/includes? % (str x)) l)] x)))
(apply + (map groupcnt input))
I used frequencies
for part 2
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_6.clj
And I used union for the part 1, and intersection for the part 2. Just went with the same data structure for the both parts. https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_06.clj
Turns out both parts differs only whether it is set intersection or union https://github.com/nbardiuk/adventofcode/blob/c30b10fc2320c8f29fb9e84dd9afeaad3b04363b/2020/src/day06.clj#L17-L18
I had that intuition as well, but the timer told me to write first and think later 😛
I rewrote my part 1 after noticing the same thing about the set operations https://gist.github.com/KennyMonster/ef878c0a789cebe2df3e572a11803f01
definitely a pretty easy one with set operations https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/06.clj
I want more of these easy ones.
(comment
(def input (util/fetch-input 6))
; step 1
(->> (clojure.string/split input #"\R\R")
(map #(clojure.string/replace % #"\R" ""))
(map #(clojure.string/split % #""))
(map set)
(map count)
(apply +))
; step 2
(->> (clojure.string/split input #"\R\R")
(map clojure.string/split-lines)
(#(for [answers %]
(->> answers
(map set)
(apply clojure.set/intersection))))
(map count)
(apply +)))
;; part 1
(defn count-answers [s]
(->> (mapcat #(str/split % #"") s)
(into #{})
(count)))
;; part 2
(defn count-answers-2 [s]
(let [num-people (count s)
combined (apply str s)
answer-frequencies (frequencies combined)]
(->> (filter (fn [[_ v]] (= num-people v)) answer-frequencies)
(count))))
;; shared
(as-> (slurp "puzzle-inputs/2020/day6") o
(str/split o #"\R\R")
(map #(str/split % #"\n") o)
(map count-answers-2 o)
#_(map count-answers o)
(reduce + o))
I did something really silly at first lol -- forgot you could just (set "string")
-- https://github.com/neeasade/AdventOfCode/commit/aa941beeb54407bde2b7a00c6678d34345eff80c
https://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day6.clj
My solution using spec… probably poorly since I just recently learned it 🙂 https://gist.github.com/KennyMonster/a51c03c53403e76413aa2fe4d61d57a4
My day-4 solution. I have a feeling I could have used spec for the parsing, but I’m such a newbie with spec so what do I know. https://gist.github.com/PEZ/42375289c032e43ee6dd8cd40b3c1b42
I've been using re-seq
with capturing groups pretty heavily in some of these, just in case someone wasn't aware of it! Can be a really nice way of parsing the input sometimes if it follows a simple pattern. Less string splitting and you get a seq of the values you're interested in right away.
I used it for my day 4 parser, which ended up like so:
(defn parse [card]
(->> (clojure.string/replace card #"\s" " ")
(re-seq #"(\S+):(\S+)")
(map rest)
(reduce
(fn [m [k v]]
(assoc m
(keyword k)
v))
{})))
I just refactored mine from a giant nasty looking threading macro doing all sorts of terrible hack n slash
(defn parse-passport-chunk [s]
"key/val pairs separated by whitespace into a map"
(into {} (map (fn [[_ key val]] [(keyword key) val])
(re-seq #"(\w+):(\S+)" s))))
(defn input->passports [s]
"Raw input -> map of passwords w/ keyword keys"
(->> (str/split s #"\n\n")
(map parse-passport-chunk)))
Yeah, ours are pretty similar now. And I can also get rid of that (map rest)
and do what you do there:
(defn parse [card]
(->> (clojure.string/replace card #"\s" " ")
(re-seq #"(\S+):(\S+)")
(reduce
(fn [m [_ k v]]
(assoc m
(keyword k)
v))
{})))
given how your regex is defined, I don’t think there’s even a need to do the replace
call to normalize the whitespace, since it will be thrown out by re-seq
regardless
thanks for mentioning re-seq, I remember when I first encountered it and then suddenly I use it literally everywhere. Another tip: with destructuring, you get really smooth group matches to bound names: EG from my day2 of Advent:
(let [[_ lower upper letter pass] (first (re-seq #"([0-9]+)-([0-9]+) ([a-zA-Z]): (.+)" line))]
;; do stuff with lower, upper, letter, pass
)
@U4TGNN19D If you use re-matches
you don’t even need the first
:
(let [[_ pmin pmax pc password]
(re-matches #"(\d+)-(\d+) ([a-z]): ([a-z]+)" s)])
@UBHTL6AF3 thanks!
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_5.clj is here.
https://redpenguin101.github.io/posts/2020_12_05_aoc2020_day5.html - I didn't pick up on the 'trick', very cool though! Even without it it can be solved very concisely.