SPOILER ALERT: If you have any inkling, any whatsoever, to work on the Advent of Code…. DO NOT READ THIS BLOG POST. DO NOT LOOK AT MY GITHUB PROJECT. It is no fun if you’re not solving it yourself, and you’ll feel so much better about yourself if you can figure it out without looking up an answer. This blog post is not to give away the answer, but instead, is there for people to learn from.
As always, the following code is in my GitHub: https://github.com/pviafore/AdventOfCode2016
So this one wasn’t too bad. Reminded me of a Project Euler problem. Find the number of triplets that could be a valid triangle (the sum of two sides are always greater than the other)
I chose Clojure for this challenge. The language intrigues me (I’ve always liked the LISP languages) but the ecosystem hasn’t gelled with me. Spinning up Lein has been slow for me, and the docs/package manager/unit test framework never did it for me. But still, its another language. I did maybe 30 Project Euler problems in Clojure years ago, so it’s time for a refresher.
Here’s the code:
(defn read-file  (slurp "../day3.txt")) (defn split-lines [str] (clojure.string/split str #"\n")) (defn make-triangle [string] (->> (clojure.string/split string #" ") (remove #(= % "" )) (map read-string) (sort) ) ) (defn make-triangles [strings] (map make-triangle strings)) (defn is-valid-triangle? [[a b c]] (> (+ a b) c)) (defn get-valid-triangles [triangles] (filter is-valid-triangle? triangles)) (defn main  (-> (read-file) (split-lines) (make-triangles) (get-valid-triangles) (count) ) ) (main)
If there’s one thing I love, its pipelining (or call chaining). I first came across this in Clojure, and I fell in love with it (and took it forwards with me to Elixir). It makes call chaining so pleasurable to look at. I mean, look at the main function, you just read it top to bottom and you know what its doing.
(defn main  (-> (read-file) (split-lines) (make-triangles) (get-valid-triangles) (count) ) )
The heavy lifter here is make-triangle and is-valid-triangle?
make-triangle takes a string, splits it by spaces, removes empty elements, converts to integers, and sorts them.
(defn make-triangle [string] (->> (clojure.string/split string #" ") (remove #(= % "" )) (map read-string) (sort) ) ) (defn is-valid-triangle? [[a b c]] (> (+ a b) c)) (defn get-valid-triangles [triangles] (filter is-valid-triangle? triangles))
The key is the sort. If the triplet is sorted into “a b c”, I only have to check that a + b > c.
This changed things up a bit. Instead of each triplet in each row being a triangle, the triplet was represented vertically.
So in part 1, the following:
1 2 3
4 5 6
7 8 9
would give us the triangles (1,2,3), (4,5,6), (7,8,9)
but for the second part, it would be (1,4,7), (2,5,8), (3,6,9)
Not much of my code had to change, but it did make things more interesting.
Instead of a make-triangles, I converted my functions to make-numbers functions. The key here is that I don’t sort the numbers (as I don’t want to mess with the order). I actually missed this at first and had a bug when I submitted 😦
(defn get-numbers [string] (->> (clojure.string/split string #" ") (remove #(= % "" )) (map read-string) ) ) (defn make-numbers [strings] (map get-numbers strings))
The main function puts this make-numbers function right before making triangles.
(defn main  (-> (read-file) (split-lines) (make-numbers) (make-triangles) (get-valid-triangles) (count) ) )
I thought making triangles would be slightly difficult, but thanks to the magic of list destructuring in clojure, it was quite easy.
I grab three triplets at a time, make 3 triangles out of them, and then recurse into the rest of the list for the next three.
(defn make-triangles [[[a1 b1 c1] [a2 b2 c2] [a3 b3 c3] & triangles]] (let [new-triangles [[a1 a2 a3] [b1 b2 b3] [c1 c2 c3]]] (if (empty? triangles) new-triangles (concat new-triangles (make-triangles triangles)) ) ) )
Lastly, I changed is-valid-triangle to sort the triangle first
(defn is-valid-triangle [t] (let [[a b c] (sort t)] (> (+ a b) c)))
Well, this was my first submission that had an error since I missed a sort. That stunk. But I managed to get most of the Clojure written (and only a little bit too). I got to use some of my favorite features, such as destructuring and pipelining.
Overall Grade: B
Most of my time was googling what functions did what in the Clojure core library. Once I remembered how let statements work and some sequence operations, it wasn’t so bad. All in all, this was a breeze though.
Next up, I think I’m going to use Perl 6. It looks like Regex will help me on Day 4, and I’ve never written a lick of Perl in my life. Let’s go!