This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-02
Channels
- # adventofcode (153)
- # announcements (29)
- # architecture (6)
- # babashka (5)
- # beginners (197)
- # calva (71)
- # clj-kondo (27)
- # cljfx (4)
- # cljs-dev (33)
- # cljsrn (1)
- # clojure (52)
- # clojure-australia (5)
- # clojure-boston (1)
- # clojure-europe (38)
- # clojure-france (1)
- # clojure-hungary (5)
- # clojure-italy (1)
- # clojure-nl (19)
- # clojure-uk (5)
- # clojurescript (12)
- # conjure (4)
- # core-async (3)
- # cursive (22)
- # datalog (70)
- # datomic (32)
- # deps-new (8)
- # emacs (79)
- # events (2)
- # fulcro (15)
- # graalvm (15)
- # leiningen (2)
- # lsp (5)
- # minecraft (1)
- # nbb (1)
- # off-topic (37)
- # polylith (11)
- # re-frame (9)
- # reagent (1)
- # reitit (3)
- # releases (1)
- # reveal (2)
- # shadow-cljs (42)
- # spacemacs (1)
- # tools-build (4)
- # tools-deps (55)
- # vim (11)
- # xtdb (6)
🧵 Day 2 answers thread: post your answers here
Here is mine https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_02.clj
Here’s mine:
(def input (->> (u/day-input-source 2)
(into [] (map (comp edn/read-string #(str "{:" % "}"))))))
(defn t1
[input]
(let [combined (reduce (fn [acc x] (merge-with + acc x)) input)
{:keys [forward up down]} combined]
(* forward (- down up))))
(defn t2
[input]
(let [f (fn [acc action]
(let [[direction x] (-> action seq first)]
(case direction
:down (update acc :aim + x)
:up (update acc :aim - x)
:forward (-> acc
(update :horiz + x)
(update :depth + (* (:aim acc) x))))))
init (zipmap [:horiz :depth :aim] (repeat 0))
{:keys [horiz depth]} (reduce f init input)]
(* horiz depth)))
My solution using recursion: https://github.com/raicotop/advent-of-code-2021/blob/main/src/advent_of_code_2021/day-02.clj
My first implementation was similar to alekszelark, this one is already refactored https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day02.clj
I also went with a vector instead of a map because I think the argument destructuring makes it quite clear anyway
(defn answer [[distance depth]]
(* distance depth))
(answer
(reduce
(fn [[distance depth] [direction step]]
(case direction
:forward [(+ distance step) depth]
:down [distance (+ depth step)]
:up [distance (- depth step)]))
[0 0]
input))
(answer
(reduce
(fn [[distance depth aim] [direction step]]
(case direction
:forward [(+ distance step) (+ depth (* aim step)) aim]
:down [distance depth (+ aim step)]
:up [distance depth (- aim step)]))
[0 0 0]
input))
part-2 aim is identical to part-1 depth, so the same reduction works for both
(defn parse [s]
(->> s (re-seq #"\w+") (map read-string) (partition 2)))
;; This covers parts 1 and 2: for part-1 treat aim as depth and ignore dep
(defn dive [commands]
(reduce (fn [[hor aim dep] [op x]]
(case op
forward [(+ hor x) aim (+ (* aim x) dep)]
down [hor (+ aim x) dep]
up [hor (- aim x) dep]))
[0 0 0]
commands))
(defn part-1 []
(let [[hor dep _] (->> "input/2021/02" slurp parse dive)]
(* hor dep)))
(defn part-2 []
(let [[hor _ dep] (->> "input/2021/02" slurp parse dive)]
(* hor dep)))

(defn parse-input [input]
(map (fn [line]
(let [[direction amount] (string/split line #" ")]
[(keyword direction)
(Integer/parseInt amount)]))
(string/split-lines input)))
(def input (parse-input (slurp "aoc-day-2.txt")))
(defn part-one [commands]
(loop [commands commands
horizontal-position 0
vertical-position 0]
(if-let [[direction amount] (first commands)]
(case direction
:forward (recur (rest commands)
(+ horizontal-position amount)
vertical-position)
:up (recur (rest commands)
horizontal-position
(- vertical-position amount))
:down (recur (rest commands)
horizontal-position
(+ vertical-position amount)))
(* horizontal-position vertical-position))))
(defn part-two [commands]
(loop [commands commands
aim 0
horizontal-position 0
depth 0]
(if-let [[direction amount] (first commands)]
(case direction
:forward (recur (rest commands)
aim
(+ horizontal-position amount)
(+ depth (* amount aim)))
:up (recur (rest commands)
(- aim amount)
horizontal-position
depth)
:down (recur (rest commands)
(+ aim amount)
horizontal-position
depth))
(* horizontal-position depth))))
https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_02-clj
(defn parser [l]
(let [[dir v] (str/split l #" ")]
{:dir dir
:v (Integer/parseInt v)}))
; part 1
(->> (f/read-all-lines-and-parse puzzle-input parser)
(reduce (fn [[x y] {:keys [dir v]}]
(condp = dir
"forward" [(+ x v) y]
"up" [x (- y v)]
"down" [x (+ y v)])) [0 0])
(reduce * 1))
; part 2
(->> (f/read-all-lines-and-parse puzzle-input parser)
(reduce (fn [[x y aim] {:keys [dir v]}]
(condp = dir
"forward" [(+ x v) (+ y (* aim v)) aim]
"up" [x y (- aim v)]
"down" [x y (+ aim v)])) [0 0 0])
(take 2)
(reduce * 1))
https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day02.clj
(defn parse [line]
(let [x (Long/parseLong (re-find #"\d+" line))]
(case (first line)
\f [x 0]
\u [0 (- x)]
\d [0 x])))
(->> input
(map parse)
(apply map +)
(apply *))
;; => 2073315
(defn proc [[x y aim] [p d-aim]]
[(+ x p)
(+ y (* p aim))
(+ aim d-aim)])
(->> input
(map parse)
(reduce proc [0 0 0])
(take 2)
(apply *))
;; => 1840311528
What do you think about parsing the file like this:
(->> "path"
slurp
(format "{%s}")
read-string)
As I understand it, its probably fine for Advent of Code, but you wouldn't want to read untrusted input with (read-string)
in real world stuff as it can execute code.
ah right! it's right there in the docs :man-facepalming:
As I understand clojure.edn/read-string
is safer alternative and works for AoC fine since input is just data, no function definitions, etc.

I’m just pasting the input data directly into my code i.e. (def input '(..data here..))
😄
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d02.clj same as @U01HL2S0X71
https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day02.clj
@U0105JJK1L3 Did one novel thing in that he resolved to a direction tuple (e.g. [-1 0]
) in the first step, which eliminated later switches.
Also good to see how much mine looks like @borkdude’s. Apparently I’m not too far off the beaten path 😄
heres my solution https://github.com/theianjones/aoc_2021/blob/master/src/theianjones/aoc-2021/d02/answer.clj
same as everyone else's https://github.com/FelipeCortez/advent-of-code/blob/master/2021/02.clj
haven't profiled it, but I imagine case is always faster so I use it when I can, cond when case isn't enough, condp when cond isn't enough condp when it's cleaner than cond
I considered making the most hacky version for 2 day by rewriting the input to s-expressions, (forward 2)
, etc and then making functions for forward
, etc so I could just run the program. ;)
@borkdude same! (wrt the lispy rewriting)
I recently finished https://beautifulracket.com/ and it seems like Racket really encourages this
read strings, turn them into s-exps somehow, write your DSL logic
A little late to the party https://gist.github.com/galuque/b7d60d2f2ac4c9b4658b4d21f02b12df
Did it last night, but here it is (not at all clean or clojurey, but im still learning!) https://github.com/kwpav/advent-of-code-2021/blob/master/src/advent_of_code_2021/day02.clj
https://github.com/bsless/clj-aoc-2021/blob/master/src/bsless/clj_aoc_2021/day2.clj 🙃
@U01GXCWSRMW awesome ;)
Note that this won’t work in Clojure. ⭐ for the one who tells me why.
I still don’t have proper assoc
/`update` and destructuring so it looks a bit weird 🤷
https://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2021/day_02.clj Oh man, some of the answers here are great. I could not figure out how to use reduce
for part-2 because I kept thinking I needed a 2 arity function but I have to track 3 things so I had to resort to my usual ugly loop/recur method
This Python solution for Day 2 seems so clean to me: https://www.reddit.com/r/adventofcode/comments/r6zd93/2021_day_2_solutions/hmwbtbe/
I refactored mine to create a "mover" function which knows how to move forward, down, and up for both parts, and then plugged the mover into a common solver function that uses reduce. Curious about anyone's thoughts. https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day02.clj
Another sexpr oriented solution is to just compile the instructions:
(reduce comp (map (fn [[d n]] (fn [sub] (move sub d n))) moves))
My solution for day2. Maybe too much abstraction :thinking_face: 😅
(def puzzle-input
(->> (str/split (input "day2.txt") #"\n")
(mapv (fn [instruction]
(let [[direction steps] (str/split instruction #" ")]
[(keyword direction) (read-string steps)])))))
(def instruction-map
{:forward [(fn [{:keys [x] :as current-position} steps]
(assoc current-position :x (+ x steps)))]
:down [(fn [{:keys [y] :as current-position} steps]
(assoc current-position :y (+ y steps)))]
:up [(fn [{:keys [y] :as current-position} steps]
(assoc current-position :y (- y steps)))]})
(def instruction-map-z
{:forward [(fn [{:keys [x] :as current-position} steps]
(assoc current-position :x (+ x steps)))
(fn [{:keys [y z] :as current-position} steps]
(assoc current-position :y (+ y (* z steps))))]
:down [(fn [{:keys [z] :as current-position} steps]
(assoc current-position :z (+ z steps)))]
:up [(fn [{:keys [z] :as current-position} steps]
(assoc current-position :z (- z steps)))]})
(defn move-sub [instruction-map input]
(reduce (fn [current-position [direction steps]]
(reduce (fn [cp f] (f cp steps))
current-position
(get instruction-map direction)))
{:x 0 :y 0 :z 0}
input))
(defn solution [instruction-map input]
(let [{:keys [x y]} (move-sub instruction-map input)]
(* x y)))
(comment
;; Part 1
(solution instruction-map puzzle-input)
;; Part 2
(solution instruction-map-z puzzle-input))
My unoriginal take: https://samadams.dev/2021/12/02/advent-of-code-day-2.html
love the blogging approach 🙂
@U016C0EGHUN which tool do you use to process your source to create that blog? i was looking at marginalia but it didn’t quite fit.
@tws If you're looking for a home-made solution: https://blog.michielborkent.nl/writing-clojure-highlighter.html
Solved with awk for fun
BEGIN {
x=0;
y=0;
a=0
#
t["forward"]=0;
t["up"]=-1;
t["down"]=1;
#
h["forward"]=1;
h["up"]=0;
h["down"]=0;
#
v["forward"]=1;
v["up"]=0;
v["down"]=0;
}
{
a = a + t[$1]*$2
x = x + h[$1]*$2;
y = y + v[$1]*$2*a;
}
END {
print x*y;
}
minified!
BEGIN {x=0; y=0; a=0 t["f"]=0; t["u"]=-1; t["d"]=1; h["f"]=1; h["u"]=0; h["d"]=0; v["f"]=1; v["u"]=0; v["d"]=0;} {c=substr($1,1,1) a = a + t[c]*$2 x = x + h[c]*$2; y = y + v[c]*$2*a;} END {print x*y;}
and now write an awk interpreter that fits in a tweet. so we can combine both tweets using tweet-def?
I think I'll first need to bootstrap it with tweet-def itself as a dep, then just chain it, but that's cheating
Babashka and pointless (threading style)
# part one
pbpaste | bb -I -e '(->> *input* (partition 2) (reduce (fn [[x y] [c v]] (case (keyword (name c)) :forward [(+ x v) y] :down [x (+ y v)] :up [x (- y v)])) [0 0]) (apply *))'
# part two
pbpaste | bb -I -e '(->> *input* (partition 2) (reduce (fn [[x y a] [c v]] (case (keyword (name c)) :forward [(+ x v) (+ y (* a v)) a] :down [x y (+ a v)] :up [x y (- a v)])) [0 0 0]) butlast (apply *))'
my solution to day2. I'll read your solutions now; I know there are some crazy people who avoided using reduce 🙂 https://github.com/euccastro/advent-of-code-2021/blob/main/day2.clj
yeah, I had forgotten about the joys of using re-seq
or wrapping the whole input to read it as edn...
I'm real boring https://gist.github.com/corasaurus-hex/389968ca616083ba0feb630330ba1739
@tws thanks! I’m interspersing the code with markdown line-comments like ;; # Header
, like one does with [Clerk](https://github.com/nextjournal/clerk), and then I have a little [script](https://github.com/samharad/samharad.github.io/blob/master/src/script/aoc.clj) for transforming the namespace into a markdown file. Then [Jekyll](https://jekyllrb.com/) takes it from there.
https://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day2.clj still learning
Little bit late to the game, but here goes, nevertheless…
(ns day2
(:require [clojure.string]))
(comment
; part 1
(->> "input"
slurp
clojure.string/split-lines
(map #(clojure.string/split % #" "))
(map (fn [[command value]] [command (Integer/parseInt value)]))
(reduce (fn [[pos depth] [command value]]
(case command
"forward" [(+ pos value) depth]
"down" [pos (+ depth value)]
"up" [pos (- depth value)]))
[0 0])
(apply *))
;=> 1698735
)
(comment
; part 2
(->> "input"
slurp
clojure.string/split-lines
(map #(clojure.string/split % #" "))
(map (fn [[command value]] [command (Integer/parseInt value)]))
(reduce (fn [[pos depth aim] [command value]]
(case command
"forward" [(+ pos value) (+ depth (* aim value)) aim]
"down" [pos depth (+ aim value)]
"up" [pos depth (- aim value)]))
[0 0 0])
(take 2)
(apply *))
;=> 1594785890
)
# For lines that start with "u", subtract the second token (i.e. the number)
# from variable "d".
/^u/ {d-=$2}
# For lines that start with "d", add the second token (i.e. the number)
# to variable "d".
/^d/ {d+=$2}
# For lines that start with "f", add the second token (i.e. the number)
# to variable "h".
/^f/ {h+=$2}
# At the end, print the product of "d" and "h"
END {print d*h}
its like someone saw regex and thought, that should be an entire programming language in of itself.
I've basically realised they aren't willing to entertain trying to learn something unless the syntax basically looks like C
Like, if I see something I don’t like, I just say, “Yeah I don’t really like that or want to spend my time on that.” But to respond, “NOOO. THAT’S TERRIBLE. ARE YOU KIDDING?” is nuts.
im afraid a lot of people are closed minded. Even if I look at the dicussion take a vaccin or not. Looks like there are 2 sides and both said there are right and will not listen to the other side
To be fair, they do seem to be happy to hack away on just completely awful code, mainly because I don't think they know any better.
See. The real problem is that usually when people are “just hacking away on completely awful code” very little (or nothing) is actually getting done.
like a program we had internally that downloaded a zip file, and extracted it to disc and ran an exse in the folder was 1000+ lines of code.
@tws How does this work? https://github.com/tschady/advent-of-code/blob/8bc31afea74cfd522ac3c0bcf79321f059ca9352/src/aoc/2021/d01.clj#L9-L10
You’re supposed to sum the partition. You’ve clearly seen some math trick that I don’t see.
if you have
A B C D E F
and you partition it by 3 and a step of 1 you get
(A B C) (B C D) (C D E)
etc
The picture in the problem showed me. The B and C lined up, don't need to add them.
parse-long
is getting so much usage already. You can tell who saw the 1.11.0-alpha3
update post and who didn't. Haha
I am waiting for usage of clojure.java.math
. I've just grepped my last year solution and there are only 3 cases of Math
Here is list of changes https://clojure.org/releases/devchangelog
And here is a highlights of changes https://clojure.org/news/2021/11/24/deref
I added the new parse-long, parse-boolean, etc functions from clojure 1.11 in #babashka 0.6.8 in case anyone wants to play with that for AoC :)

I just used -I
and let bb to the parsing 😉
Do you think we could ask a parse-binary
in the next Clojure release?
.. kidding
For today's solution it would have been nice if parse-long
supported the radix argument
Interesting observation that doesn't mean anything (though there's probably some small degree of correlation with something). A quick scan down the list of current members of the Clojurians private leaderboard (code in this channel's description if you've not joined) shows that there are a fair number of supporters of AoC, all in the top third.
Certainly not my intent, but 👍