Fork me on GitHub
<
2021-12-02
>
alekszelark04:12:36

R.A. Porter05:12:08

A bit inelegant, but it got the job done.

👍 3
mchampine06:12:58

Some wasted effort using maps, and could be cleaner but it got the job done.

👍 3
tylerw06:12:52

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)))``````

👍 3
nbardiuk08:12:43

My first implementation was similar to alekszelark, this one is already refactored https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day02.clj

👏 2
Antonio Bibiano08:12:40

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))

(reduce
(fn [[distance depth] [direction step]]
(case direction
:forward [(+ distance step) depth]
:down [distance (+ depth step)]
:up [distance (- depth step)]))
[0 0]
input))

(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))``````

👍 4
Callum Oakley08:12:21

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)))``````

👍 5
1
ajk08:12:35

``````(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))))``````

👍 1
Stuart09:12:17

``````(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))``````

👍 1
Joe10:12:40

``````(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``````

👍 3
Antonio Bibiano10:12:53

What do you think about parsing the file like this:

``````(->> "path"
slurp
(format "{%s}")

Stuart10:12:29

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.

Antonio Bibiano11:12:30

ah right! it's right there in the docs :man-facepalming:

nbardiuk11:12:37

As I understand `clojure.edn/read-string` is safer alternative and works for AoC fine since input is just data, no function definitions, etc.

1
nooga11:12:43

I’m just pasting the input data directly into my code i.e. `(def input '(..data here..))` 😄

😉 1
genmeblog12:12:38

btw. thanks @borkdude, I learned that `case` works on symbols without quoting...

potetm14:12:52

Interesting to see everyone’s slight variations on the exact same thing 😄

potetm14:12:39

@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.

potetm14:12:06

Also good to see how much mine looks like @borkdude’s. Apparently I’m not too far off the beaten path 😄

Stuart14:12:23

How do people decide wether to use `case` , `cond`or `condp` ?

potetm15:12:23

`case` - closed value dispatch `cond` - conditional logic dispatch `condp` - never

Felipe Cortez15:12:33

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

borkdude15:12:56

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. ;)

💯 3
potetm15:12:06

I literally have no idea what `condp` is good for.

borkdude15:12:22

I never use `condp`, it's dead to me ;)

Felipe Cortez15:12:36

@borkdude same! (wrt the lispy rewriting)

potetm15:12:39

I’ve seen people who make messes use it. But that’s it.

potetm15:12:14

@borkdude That sounds like the best kind of over-engineering tbh.

Felipe Cortez15:12:32

I recently finished https://beautifulracket.com/ and it seems like Racket really encourages this

Felipe Cortez15:12:06

read strings, turn them into s-exps somehow, write your DSL logic

kpav15:12:02

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

R.A. Porter16:12:07

I couldn't resist reimplementing part 1 after @borkdude mentioned it...

👌 2
nooga16:12:14

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 🤷

borkdude16:12:05

@UJEK1RGJ0 `case` doesn't expect you to quote the symbols

1
2
borkdude16:12:15

they are literals, not evaluated

borkdude16:12:52

so in clojure you're basically matching against `(quote forward)`

borkdude16:12:56

``````(case 'foo
foo 1) ;;=> 1``````

Chase17:12:21

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

Chase17:12:59

They made the connection that `aim` for part 2 could just be your depth for part 1.

Andrew Byala17:12:57

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

Ben Sless17:12:36

Another sexpr oriented solution is to just compile the instructions:

``(reduce comp (map (fn [[d n]] (fn [sub] (move sub d n))) moves))``

Ben Sless17:12:14

If you compile it, you just get function(s). Why does it matter when you do it?

Mario C.17:12:56

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))``````

Antonio Bibiano19:12:31

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.

Ben Sless20:12:09

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;
}``````

Ben Sless20:12:18

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;}``

😱 1
😍 1
Ben Sless20:12:47

Fits in a tweet

Ben Sless20:12:25

Reminds me of the annoying questions from intro to C, "do it without conditionals"

borkdude20:12:49

and now write an awk interpreter that fits in a tweet. so we can combine both tweets using tweet-def?

Ben Sless20:12:29

I think I'll first need to bootstrap it with tweet-def itself as a dep, then just chain it, but that's cheating

Ben Sless20:12:31

Which reminds me I wanted to solve it with core.logic

ordnungswidrig21:12:34

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 *))'``````

euccastro23:12:22

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

euccastro00:12:22

yeah, I had forgotten about the joys of using `re-seq` or wrapping the whole input to read it as edn...

@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.

Tero Matinlassi21:12:41

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
)``````

potetm14:12:05

(It’s technically a solution, but I doubt most can read awk.)

👀 1
roelof14:12:11

I cannot read and understand it

potetm14:12:01

You want me to explain them?

potetm14:12:26

day-2 is pretty straightforward

roelof14:12:25

you mean the awk syntax. No need to

potetm14:12:01

Too late

😂 1
potetm14:12:03

``````# 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}``````

👏 2
roelof14:12:00

😢 again too late

Stuart14:12:51

its like someone saw regex and thought, that should be an entire programming language in of itself.

Stuart14:12:06

I can't tell yet if I love it or hate it

potetm14:12:01

Oh awk is actually awesome.

potetm14:12:34

I use it less than I used to, but you can really do a lot of work w/ it if you want.

potetm14:12:47

Well… circumstantially.

Stuart14:12:26

People at my work when they saw some CLojure were like "NOPE!, NOT HAPPENING"

Stuart14:12:37

I can't imagine if I showed something I'd written in AWK or APL

Stuart14:12:18

Hell, they even said no chance to F#

roelof14:12:21

also I also not. Can read clojure a little bit and some ruby

Stuart14:12:00

I've basically realised they aren't willing to entertain trying to learn something unless the syntax basically looks like C

potetm14:12:35

Wild to me how close-minded some people are.

potetm14:12:16

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.

roelof14:12:57

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

potetm14:12:02

Yeah just a general lacking of curiosity/willingness to be ignorant.

potetm14:12:18

Willingness to be ignorant is actually a sort of superpower imo.

roelof14:12:29

or believing a source on facebook more then a expert

Stuart14:12:52

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.

potetm14:12:08

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.

Stuart14:12:13

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.

potetm14:12:34

1000 lines???

Stuart14:12:46

yes, thats not a typo, it was over 1000 lines of code

potetm14:12:53

idk, I’ll give a benefit of doubt

potetm14:12:04

things that actually run forever are often more complicated than one might assume

potetm14:12:21

error checking/recovery can occupy a lot of space

roelof15:12:47

that is right

potetm14:12:10

Oh @tws’s Day 2 is real nice.

👏 1
❤️ 3
💯 1
potetm14:12:34

I think you win. 😄

potetm14:12:41

You’re supposed to sum the partition. You’ve clearly seen some math trick that I don’t see.

Stuart14:12:00

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

Stuart14:12:15

so only 1 is actually different

Stuart14:12:29

so you can jsut take diff of 1st item and 3rd item

Stuart14:12:43

i'm guessing thats what his offset of dropping 3 is doing ?

The picture in the problem showed me. The B and C lined up, don't need to add them.

👏 4
potetm14:12:47

I like your style.

borkdude15:12:04

very clever :)

alekszelark18:12:25

@U07S8JGF7 thanks for sharing @tws’s solution, it’s really neat and smart.

2

this is how I build my empire

Chase17:12:56

`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

👀 1
🙂 1
👍 2
nbardiuk18:12:28

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`

roelof18:12:25

I did not see that post. Is there a important change then ?

roelof18:12:26

aha, that is why that post. `parse-long` is new 🙂

i take my AOC way too seriously to use anything alpha.

💯 2
😆 7
borkdude20:12:27

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 :)

3
❤️ 2
👀 1
ordnungswidrig21:12:18

I just used `-I` and let bb to the parsing 😉

borkdude21:12:25

haha awesome!

Vincent Cantin06:12:13

Do you think we could ask a `parse-binary` in the next Clojure release?

borkdude10:12:45

For today's solution it would have been nice if `parse-long` supported the radix argument

R.A. Porter21:12:40

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.