Fork me on GitHub
Alex Alemi05:12:08

Day 13 - Solutions

Alex Alemi05:12:56

not the most elegant comparison function, but I tried for speed today

Alex Alemi05:12:43

it was also nice having an input file that was valid clojure

norman06:12:55 Some days I feel like I have no reading comprehension skill....


parsing is easy if we wrap everything into a vector and read edn. Comparator is the meat of the task. I've made a detour trying to normalize packets to the same shape in order to use standard compare, but figured that writing comparator is easier.


Okay, refining is done. Off to bed.


Pretty gross comparator.. I basically wrote it while reading the puzzle text top-down. Was pleasently surprised to find that in part-2, I could slot it into clojure.core/sort without any changes.


(edn/read-string (str "[" input "]"))
doens't this somehow feel like some win condition for lisp?


Maybe.. in JavaScript you could so the same with JSON.parse

Mark Wardle11:12:45

I don't think I've done anything very differently to anyone else here. Feels like this problem designed to be solved with a lisp.... Wonder if my comparator is a bit verbose...

Mark Wardle11:12:29

Just read @UTFAPNRPT’s solution and his use of keep-indexed which is much nicer than my map-indexed and then filter contortions! This is great for learning.

Felipe12:12:18 and TIL > Java comparators are all 3-way, meaning they return a negative, 0, or positive integer depending upon whether the first argument should be considered less than, equal to, or greater than the second argument. > > In Clojure, you may also use boolean comparators that return true if the first argument should come before the second argument, or false otherwise (i.e. should come after, or it is equal). The function < is a perfect example, as long as you only need to compare numbers. > works for sorting numbers in decreasing order. Behind the scenes, when such a Clojure function bool-cmp-fn is "called as a comparator", Clojure runs code that works like this to return an int instead: >

(if (bool-cmp-fn x y)
>   -1     ; x < y
>   (if (bool-cmp-fn y x)  ; note the reversed argument order
>     1    ; x > y
>     0))  ; x = y


Recommended reading on clojure comparators:


[2,3,4] vs 4 are in the right order
because 2<4 makes a decision before right runs out of elements. so [2 3 4] [4] is ok and [2 3 4] [2] is not because 2=2 (no decision), and only after that right runs out of elements and [2] [2 3 4] is ok, because 2=2 (no decision), and left runs out, and thats ok and as a result (every? true? (map correct? left right)) is incorrect


Much much easier than yesterday... It was great decision to write comparator for part1.


The interesting bit

(defn comparer [a b]
    (every? integer? [a b])
    (compare a b)
    (every? sequential? [a b])
    (if-let [res (->> (map comparer a b) (filter #(not (zero? %))) first)]
      (comparer (count a) (count b)))
    :else ;; one is a list and one is an integer
    (apply comparer (map #(cond-> % (integer? %) vector) [a b]))))

✔️ 1

Looking at the source for = led me to next instead of rest, which I always forget about. next especially helps because (compare nil 2 ) (compare 3 nil) (compare nil nil) all do the right thing.


That’s a good thing to remember, @U1Z392WMQ.


Impressed by @UTFAPNRPT’s code of comparator. It’s really concise.

🙏 1

I thought a lot about it (too much!) and made two attempts to normalize and flatten the packets and do a simple element-wise compare, but I kept running into exceptions. I got as close as having only 3 cases that I couldn’t resolve (with my input). Ah well. It’s like the false promise of alchemy.


made an animation how the packets would look like if normalized to the common shape. Although it is only animation, the compare doesn't work on it

🆒 1

Nil is less than everything. And ##-Inf is less than everything else.


not everything trollface

user=> (compare ##-Inf ##NaN)

🤪 1

nil is less than everything, ##-Inf is less than everything else, and ##NaN is less than nothing.


nil is endless void ^_^


Day 13 part 1: I get the right answer for the sample, but it’s wrong for my input. Any tips?


double checked everything, but can’t see a mistake


compared visually the output for every example, it seems correct


The input has empty vectors in strange places that messed me up when I tried to get too tricky.


I use edn/read-string to parse it, should work fine I guess


Came here for the exact same question


(read-string (str "[" input "]"))
   (partition 2)
works fine for the example and the real input also seems correct. Am I wrong?


should be fine, I found a problem with a logic for comparison


I’m using a zipper in a wrong way


For me I realized my logic is wrong for this case:

[[4, 5], 6]
[[4, 5], 3]


(cmp [[[] 6 2]] [[[]] [10]]) a good example to check against, should return false


My mistake is I was trying to use zippers.

Andrew Byala07:12:01

Posting out here to see if someone with clojure-core-match skills can answer a specific question on my solution to day 13.

Andrew Byala07:12:05

In the bottom of, I mention trying to use match to check the types of the two values at a given level of the vector, checking if they're nil, scalar, or vectors. I was able to work with matching on [(type v)] just fine, but once I brought in two types, with [(type v1) (type v2)], I couldn't get it to work. I had to resort to :guard clauses, which just look messy. Does anyone know how to get the matcher to work when using the types of 2 or more values in the input vector?


I started on the same approach! I just went with condp in the end which does the same thing in this trivial case


I had the same idea, but when I saw this in the wiki, I gave up on match as more complex. > Unlike pattern matching found in most functional programming languages core.match does not promote matching on concrete types. Instead core.match matches on abstract interfaces / protocols -`IPersistentVector`, ILookup, Sequential and so on.

Andrew Byala15:12:22

I found a way to make it work, but I still think it's messy. Instead of working with actual types, I had to map the types to keywords. Note the mapv under the m/match call. Surely this isn't the intention?

(defn correct-order?
  ([left right] (correct-order? left right [0]))
  ([left right address]
   (let [[v1 v2 :as values] (map #(get-in % address) [left right])]
     (m/match (mapv #(cond (number? %) :num, (vector? %) :vec, :else nil) values)
              [nil nil] (recur left right (-> address move-up move-right))
              [nil _] true
              [_ nil] false
              [:num :num] (case (u/signum (- v1 v2))
                            -1 true
                            1 false
                            (recur left right (move-right address)))
              [:vec :vec] (recur left right (move-down address))
              [:vec :num] (recur left (vectorize right address) address)
              [:num :vec] (recur (vectorize left address) right address)))))

Alexis Schad16:12:22

why not use guards for types?

Andrew Byala17:12:28

@U01V2D5ALKX - I did the first time through, but I had to repeat the guards multiple times to get all of the conditions to work. Thought it looked a little ugly, unless you know a better way.

(defn correct-order?
  ([left right] (correct-order? left right [0]))
  ([left right address]
   (let [[v1 v2] (map #(get-in % address) [left right])]
     (m/match [v1 v2]
              [nil nil] (recur left right (-> address move-up move-right))
              [nil _] true
              [_ nil] false
              [(_ :guard number?) (_ :guard number?)] (case (u/signum (- v1 v2))
                                                        -1 true
                                                        1 false
                                                        (recur left right (move-right address)))
              [(_ :guard vector?) (_ :guard vector?)] (recur left right (move-down address))
              [(_ :guard vector?) _] (recur left (vectorize right address) address)
              [_ (_ :guard vector?)] (recur (vectorize left address) right address)))))

Alexis Schad17:12:13

It's not that ugly for me, at least you know what's going on

👍 1