I am new to clojure and I make my way through the aoc2020 problems. I'm interested in your opinions about my day12 code. In python I would check the values and update some data, but with clojure I wanted to stay with away from mutables for the time being. There is two things I noticed. part1 and part2 are very similar but I dont know how to make it more compact. (would you prefer a github link to this?)
(ns advent-of-code.day-12
(:require [clojure.edn :as edn]))
(defn update-position
"returns the coordinate changes from an instruction"
[instruction northsouth eastwest facing]
(let [code (first (re-find #"[NSEWLRF]" instruction))
number (edn/read-string (re-find #"\d+" instruction))]
(cond
(= code \N) [(+ northsouth number) eastwest facing]
(= code \S) [(- northsouth number) eastwest facing]
(= code \E) [northsouth (+ eastwest number) facing]
(= code \W) [northsouth (- eastwest number) facing]
(= code \L) [northsouth eastwest (mod (+ 360 (- facing number)) 360)]
(= code \R) [northsouth eastwest (mod (+ 360 (+ facing number)) 360)]
(= code \F) (cond
(= facing 270) [(+ northsouth number) eastwest facing]
(= facing 90) [(- northsouth number) eastwest facing]
(= facing 0) [northsouth (+ eastwest number) facing]
(= facing 180) [northsouth (- eastwest number) facing]))))
(defn part-1
"Day 12 Part 1"
[input]
(loop
[instructions input
northsouth 0
eastwest 0
facing 0]
(let [instruction (first instructions)
otherinstructions (rest instructions)
[newns, newew, newface] (update-position instruction northsouth eastwest facing)]
(if (empty? otherinstructions)
(+ (Math/abs newns) (Math/abs newew))
(recur otherinstructions newns newew newface)))))
(defn update-position2
"returns the coordinate changes from an instruction"
[instruction northsouth eastwest shipNS shipEW]
(let [code (first (re-find #"[NSEWLRF]" instruction))
number (edn/read-string (re-find #"\d+" instruction))]
(cond
(= code \N) [(+ northsouth number) eastwest shipNS shipEW]
(= code \S) [(- northsouth number) eastwest shipNS shipEW]
(= code \E) [northsouth (+ eastwest number) shipNS shipEW]
(= code \W) [northsouth (- eastwest number) shipNS shipEW]
(= code \F) [northsouth eastwest (+ shipNS (* number northsouth)) (+ shipEW (* number eastwest))]
(= code \L) (cond
(= number 90) [eastwest (- northsouth) shipNS shipEW] ;; n=a e=b => n=b e=-a)
(= number 270) [(- eastwest) northsouth shipNS shipEW]
(= number 180) [(- northsouth) (- eastwest) shipNS shipEW])
(= code \R) (cond
(= number 270) [eastwest (- northsouth) shipNS shipEW] ;; n=a e=b => n=b e=-a)
(= number 90) [(- eastwest) northsouth shipNS shipEW]
(= number 180) [(- northsouth) (- eastwest) shipNS shipEW]))))
(defn part-2
"Day 12 Part 2"
[input]
(loop
[instructions input
northsouth 1
eastwest 10
shipNS 0
shipEW 0]
(let [instruction (first instructions)
otherinstructions (rest instructions)
[newns, newew, newShipNS, newShipEW] (update-position2 instruction northsouth eastwest shipNS shipEW)]
(if (empty? otherinstructions)
(+ (Math/abs newShipNS) (Math/abs newShipEW))
(recur otherinstructions newns newew newShipNS newShipEW)))))
I use the cycle fn to do rotations. Also I find the most enjoyable part is to ‘clean up’ after part 1 and first modularize part 1 and retest, than add your part 2 tweaks on top of that. A good rule of thumb is to keep each function to 3-10 of no more than 80 columns for easier reading. Cheers!
1👀...”3-10 lines whenever possible...”, sorry
It looks ok.
Replacing cond
with case
or condp
would save you a bunch of typing though.
If it would be the code you had to maintain, it would make sense to replace loop
with a step function, and a (->> state (iterate step) (drop-until done?) first calc-score)
"pipeline", to decouple done condition from step logic, and make step function testable and replaceable, etc. But in the context of aoc - it is perfectly fine as is.
I had case first, but it would not evaliate my code
can you show me?
Ah, it was another day. I think I was trying to compare my value to something. Like if x is smaller than 4 and bigger than -14. and that would not work.
Apart from case
and cond
there's also core.match for when you'd prefer something like
(match [code (/ number 90) (<= 4 x 13)]
[\N _ true] (do-something)
[\R d _] (rotate-smth-by d))
1👀Agreed with the above. There are times when the “math puzzle” piece is interesting, but at least for me, personally, I’m trying to build up my Clojure skills through this exercise. I managed to Google my way to the Chinese remainder theorem (and this thread), and happy to see others are in the same boat. This is one case where I was happy to copy/paste some code. 😆 https://github.com/jeff303/advent-of-code-2020/blob/master/src/advent_of_code/day13.clj#L80
I'm having trouble understanding the logic for day 17
If a cube is active and exactly 2 or 3 of its neighbors are also active, the cube remains active. Otherwise, the cube becomes inactive.
If a cube is inactive but exactly 3 of its neighbors are active, the cube becomes active. Otherwise, the cube remains inactive.
z=0
.#.
..#
###
After 1 cycle:
z=-1
#..
..#
.#.
How does top left in z=-1 turn on?
It has 1 neighbour that is on (the top middle on z=0)the examples for this one are confusing, it's not keeping like [0 0] on the top left, its always centering the display around the visible active ones
aaaaah
thanks!
its mentioned but briefly, I spent way to much time trying to make sense of the examples until someone pointed it out to me: > (and the frame of view follows the active cells in each cycle)
i saw that and didn't understand what it meant 😞