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'))))
¯\(ツ)/¯(def raw-input (str/split-lines (slurp "resources/day03.data")))
(defn trees [inp [x y]]
(let [expinp (map #(apply str (repeat 80 %)) inp)
lines (rest (take-nth y expinp))]
(count (filter #{\#} (map #(nth % %2) lines (range x 2300 x))))))
(trees raw-input [3 1]) ;; part 1
(apply * (map (partial trees raw-input) [[1 1] [3 1] [5 1] [7 1] [1 2]])) ;; part 2
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.)
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.
nth is linear lookup. with cycle, each next line does longer and longer linear lookups
e.g.:
...
.....
.......
.........
...........
.............
if you mod
your Xs, your lookups will be:
...
.....
.......
...
.....
.......
(time (nth (cycle "abcd") 100000))
"Elapsed time: 7.717277 msecs"
=> \a
(time (nth "abcd" (mod 100000 (count "abcd"))))
"Elapsed time: 0.093352 msecs"
=> \a
Gotcha. Down to 2.5 msec now. That’s x200 in total!
:tatatananana:
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.
(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 * $)))
Found it! I fed it [1 2]
instead of [1 1]
for the first slope….
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
It takes about half a sec on my pretty fast MacBook.
that second part was a lot of minutiae haha
1. replace
(repeat)
(flatten)
with (cycle) for probably x2 speedup
2. replace (cycle) with (mod dx line-len) for next x5-x10 speedup3. replace drop, first with nth for 3rd 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"
Live stream for day 4 starting soon https://youtu.be/K3f10iwxtOw
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 ^_^
yes, I know
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")
basically it matches everything that conceptually is a newline
Ah nice, thanks
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 😞
meh... the leaderboards are really the last of my concerns 🙂
Argh. Tonight's took much longer than it should. I'm much more rusty than I thought.
Parsing and validation feels too much like real work 😆
https://github.com/djblue/advent-of-code/blob/master/src/advent_of_code/core_2020.clj#L106
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 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.
Last year, for some of the puzzles, we built up a little byte code VM and our inputs were programs, it was pretty cool
We even got to chain the programs together via input/output ports
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.
so true, and so boring
And the recording: https://youtu.be/XaXB0kbpvjw Code: https://github.com/lambdaisland/aoc_2020/
I was just thinking "if this doesn't work from the first try it's going to suck to debug", but luckily it did
80% of my part 1 solution is parsing 😞
Sweet! I got a x10 when replacing (seq) (repeat) (flatten)
with (cycle)
.
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.
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'm glad someone did :rolling_on_the_floor_laughing:
I am happy I spent time to get familiar with it, it might be useful one day.
> 2. replace (cycle) with (mod dx line-len) for next x5-x10 speedup Not following here.
oh … I feel stupid, I did not think about that (str/split real-input #"\R\R")
That was way harder than it needed to be.. 😉. I really need to learn my destructuring better..
Today is a bit boring, but I've spend some creativity on refactoring parsing rules
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
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
interesting that you reach to core.match
for this!
indeed very nic
e
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]} ,,,)
I'm a scala dev by trade so pattern matching calls to me, and great tip thanks!
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
over-engineering, over-engineering everywhere 🤦
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
true
(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
and mine solution (possibly over-engineered 🙂) https://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day04.clj
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
My solution to Day 4 with clojure.spec: https://github.com/benfle/advent-of-code-2020/blob/main/day4.clj
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
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?
a refactored version https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_04.clj
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))
Right, sorry i'll use thread replies or links next time.
Thanks for the hint, @ben.list89 - I saw that in other submissions. Lots of improvements to make!
@narve As the topic says, please put spoilers in thread replies. Thank you.
links to code are also ok
fyi you can do (<= min num max)
instead of (and (<= min num) (>= max num)
:d:
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.
(like ::hgt
needs refactoring)
btw, you could a bit simplify the spec for part 1
(every? (partial contains? %) required-fields)
would work
much better, updated, thanks!
are you assuming for day4, part1 that the “values” are always non-empty?
Ohh I should have used spec for this one
One thing I learned today is (<= 150 height 193)
- which is a nice readable short form for (and (…) (…))
Day 5 Answers Thread .. Post your answers here
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 🙂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
Not super proud of part 2 - I think that could have a simpler solution
Hmm subvec
Ohh reduce
clever I did a recursive loop
omg a binary decode
sigh 🙂
Should have recognized that
(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?@jculp yes, as Arne showed you could use some
instead.
(some (fn [[lo hi]] (when (= (+ lo 2) hi) (inc lo))))
clever!
;; 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})
some+when is a useful pattern. I vastly prefer it nowadays over filter+first
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.
I am extremely jealous of @mchampine’s solution
https://gist.github.com/devn/29ee7fc152e359dd6c3a604b372291fb
Day 6 Answers Thread .. Post your answers here
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 +)))
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d06.clj
https://redpenguin101.github.io/posts/2020_12_06_aoc2020_day6.html
https://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day06.clj
;; 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
Check the pinned threads people - no spoilers in the main channel
yes, if there is a key it has a value
My solution using spec… probably poorly since I just recently learned it 🙂 https://gist.github.com/KennyMonster/a51c03c53403e76413aa2fe4d61d57a4
If there is a will there is a way.
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 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)
?
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.
@risinglight thanks!
this would have simplified parsing on day 4 for me!
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
Yeah, I realized that when I saw your code. 😃