Clojure solution to Advent of Code 2016 day 1
I saw someone on Twitter solving old Advent of Code challenges with Clojure and I got inspired to try it myself. So here’s my solution to Advent of Code 2016 day 1 using Clojure.
The code is on GitLab but I’ll include the main function here:
(defn start [document]
(loop [distq [0 0] facing 0 orders (parse-doc document)]
(if (empty? orders)
(apply + (map #(Math/abs %) distq))
(let [[RL nblocks] (first orders)
delta (* nblocks ([1 1 -1 -1] facing) RL)]
(recur
[(last distq) (+ (first distq) delta)]
(mod (+ RL facing) 4)
(rest orders))))))
I was able to find a few shortcuts which reduced the amount of code I had to write.
First, I chose to represent “right” as the number 1 and “left” as the number -1. This makes it easy to move and change direction, as we’ll see.
The compass rose directions are represented with increasing numbers “clock-wise”. North is 0, east is 1, south is 2, and west is 3. To change direction after a move I add either 1 or -1 depending on if we went right (1) or left (-1), and finally take the modulus 4 of the result to get back into range [0 3].
A key point is that for each iteration through the loop, the current position only moves along either the X- or the Y-axis. We start facing north and then turn either right or left, thus only affecting our position on the X axis. If we turned right, we start the next loop facing east and can only move on the Y-axis.
Because we alternate between X and Y this way, each iteration need only
be concerned with our position on that axis. This is where the variable
distq
comes into play. Its first element is our position on the
current axis. That’s why in the call to recur
their positions are
swapped.
On computing delta
. The variable delta represents how much the
position on the current axis will change due to our move. If the move is
“R5” then nblocks
will be 5. If we are facing north (0) or east (1)
and go right, then the axis value will increase, represented by 1. If we
are facing south (2) or west (3), then the axis value will decrease if
we go right, represented by -1. Finally we multiply by RL
, which is 1
if we went right, and -1 if we went left.