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!
...β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))
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 π