adventofcode

Happy Advent 2020! Please put answers in the pinned threads or create one if it does not exist yet. | https://github.com/adventofcode-clojurians/adventofcode-clojurians | Join the private leaderboard with code 217019-4a55b8eb
Christian 2020-12-31T10:38:55.244300Z

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

2021-01-02T20:40:53.256700Z

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👀
2021-01-02T20:42:06.257900Z

...”3-10 lines whenever possible...”, sorry

misha 2020-12-31T11:40:57.244400Z

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.

Christian 2020-12-31T12:40:20.244600Z

I had case first, but it would not evaliate my code

misha 2020-12-31T13:01:17.244800Z

can you show me?

Christian 2020-12-31T14:23:50.245Z

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.

2020-12-31T15:00:32.245400Z

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👀
2020-12-31T18:18:44.245700Z

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

2020-12-31T18:48:56.247100Z

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)

erwinrooijakkers 2021-01-04T18:52:46.258800Z

holymackerels 2020-12-31T18:52:30.247300Z

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

2020-12-31T18:53:12.247500Z

aaaaah

2020-12-31T18:53:16.247700Z

thanks!

holymackerels 2020-12-31T18:54:01.247900Z

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)

2020-12-31T18:54:25.248100Z

i saw that and didn't understand what it meant 😞