Advent of Code 2022 - Day 05

2 minute read

Day 05

The main challenge for this day is manipulating the datastructure which consists of n stacks. Having peek, pop and conj functions makes this job easier. First we represent the structure as vector of lists of characters. I added an empty list in the first place because the ‘commands’ in the challenge start from 1 not from 0.

1;    [D]    
2;[N] [C]    
3;[Z] [M] [P]
4; 1   2   3 
5(def sample-input 
6  ['() '(\N \Z) '(\D \C \M) '(\P)])

The parsing of ‘commands’ is similar to what we have been doing in the previous challenges. The main difference is that I discovered re-seq that matches all regex and returns the matches in a list. With this function finding all the numbers is as simple as giving the function a regex \d+.

1(defn commands-to-list
2  [s]
3  (map 
4    (comp (partial map parse-long) (partial re-seq #"\d+")) 
5    (string/split s #"\n *")))

Part 1

To manipulate the datastructure using recursion we define a loop that takes a source stack, target stack and number of letters to move. We than ask if the number of letters to move is positive (indicating we have letters to move) and if it is recuring with source without the top element, target with the top element of source and a decreased n. If there are no more letters to move we just build back the strucure by associating the stack at the from index with the new source and the stack at to index with the new target.

 1(defn move1
 2  [stacks [n from to]]
 3  (loop [source (stacks from)
 4         target (stacks to)
 5         n      n]
 6    (if (pos? n)
 7      (recur 
 8        (pop source) ; source without the top element
 9        (conj target (peek source)) ; target with top element of source on top
10        (dec n))
11      (assoc stacks ; put new stacks in position
12          from source
13          to target))))

I didn’t want to parse the stack structure because it is small so I can input it by hand without a problem, and also I am kinda lazy to do that.

For solving the challenge we just need to apply all the commands and get the top element from each stack.

1(defn part1
2  [stacks commands-string]
3  (->> (reduce move1 stacks (commands-to-list commands-string))
4       (map peek)
5       (apply str)
6       ))

Part 2

Now we don’t move elements one by one, instead we first assemble the list of element to move in temp and the move them at the end of recursion.

 1(defn move2
 2  [stacks [n from to]]
 3  (loop [source (stacks from)
 4         temp ()
 5         n      n]
 6    (if (pos? n)
 7      (recur 
 8        (pop source)
 9        (conj temp (peek source))
10        (dec n))
11      (assoc stacks
12          from source
13          to (into (stacks to) temp)))))

Code to solve the second part is the same we just use move2 instead of move1.

1(defn part2
2  [stacks commands-string]
3  (->> (reduce move2 stacks (commands-to-list commands-string))
4       (map peek)
5       (apply str)
6       ))