(ns oz.day1
(:require [cyrik.omni-trace.instrument :as i]
[cyrik.omni-trace :as o]
[cyrik.omni-trace.graph :as flame]
[advent.day1]))
Trying to build a solution for: Advent of Code day 1
The problem is how many times n + 1 is higher than n in an array.
I'll use omni-trace to help me find my mistakes and oz to build this doc.
The initial numbers:
(def depths [199 200 208 210 200 207 240 269260 263])
A runner function thats going to be used inside reduce to count the number of times n is smaller then n+1
(defn runner1 [acc val] (if (< val (second acc))
[(inc (first acc)) val]
[(first acc) val]))
The actual solution function:
(defn count-increases1 [input]
(reduce runner1
(rest input)
[0 (first input)]))
I'll just reduce over the input depths and an accumulator, that seems easy!
A run function so its easier to run the solution:
(defn run1 [] (count-increases1 depths))
Let's run it and see what we get:
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run1)]
[201 199]
That is not what I expected. Let's use omnitrace to see what happened:
[:vega (assoc (cyrik.omni-trace/rooted-flamegraph 'advent.day1/run1) :width 1200 :height 450)]
Oh, I see, when hovering over the calls in the flamegraph it's easy to see that reduce was called with the args switched.
Let's redefine it:
(defn count-increases2 [input]
(reduce runner1
[0 (first input)
(rest input)]))
(defn run2 [] (count-increases2 depths))
And run it again:
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run2)]
{:via [{:type java.lang.IllegalArgumentException, :message "Don't know how to create ISeq from: java.lang.Long", :at [clojure.lang.RT seqFrom "RT.java" 557]}], :trace [[clojure.lang.RT seqFrom "RT.java" 557] [clojure.lang.RT seq "RT.java" 537] [clojure.lang.RT next "RT.java" 714] [clojure.core$next__5403 invokeStatic "core.clj" 64] [clojure.core$second__5409 invokeStatic "core.clj" 98] [clojure.core$second__5409 invoke "core.clj" 98] [advent.day1$runner1 invokeStatic "day1.clj" 18] [advent.day1$runner1 invoke "day1.clj" 18] [clojure.lang.AFn applyToHelper "AFn.java" 156] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 92] [clojure.lang.PersistentVector reduce "PersistentVector.java" 329] [clojure.core$reduce invokeStatic "core.clj" 6825] [clojure.core$reduce invoke "core.clj" 6812] [advent.day1$count_increases2 invokeStatic "day1.clj" 36] [advent.day1$count_increases2 invoke "day1.clj" 35] [clojure.lang.AFn applyToHelper "AFn.java" 154] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 90] [advent.day1$run2 invokeStatic "day1.clj" 39] [advent.day1$run2 invoke "day1.clj" 39] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 88] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.deep_trace$run_traced$fn__18188 invoke "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced invokeStatic "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced doInvoke "deep_trace.clj" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [clojure.lang.AFn applyToHelper "AFn.java" 154] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.lang.Var applyTo "Var.java" 705] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace$run_traced invokeStatic "omni_trace.cljc" 67] [cyrik.omni_trace$run_traced doInvoke "omni_trace.cljc" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [oz.day1$eval66922 invokeStatic "NO_SOURCE_FILE" 15] [oz.day1$eval66922 invoke "NO_SOURCE_FILE" 15] [clojure.lang.Compiler eval "Compiler.java" 7181] [clojure.lang.Compiler eval "Compiler.java" 7136] [clojure.core$eval invokeStatic "core.clj" 3202] [clojure.core$eval invoke "core.clj" 3198] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416$fn__65417 invoke "next.clj" 899] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416 invoke "next.clj" 898] [oz.next$evaluate_block_BANG_$fn__65402 invoke "next.clj" 897] [clojure.core.async$thread_call$fn__45672 invoke "async.clj" 484] [clojure.lang.AFn run "AFn.java" 22] [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1136] [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 635] [java.lang.Thread run "Thread.java" 833]], :cause "Don't know how to create ISeq from: java.lang.Long"}
Wow, it blows up? I guess I'll try to see why.
[:vega (assoc (cyrik.omni-trace/rooted-flamegraph 'advent.day1/run2) :width 1200 :height 500)]
It seems we accidentally put the collection into the starting argument! Let's fix that.
(defn count-increases3 [input]
(reduce runner1
[0 (first input)]
(rest input)))
(defn run3 [] (count-increases3 depths))
And run it again
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run3)]
[2 263]
Wrong again? This is starting to be embarrassing...
[:vega (assoc (cyrik.omni-trace/rooted-flamegraph 'advent.day1/run3) :width 1200 :height 500)]
It seems runner is only returning increased counts when the first arg is larger than the second.
I mixed up our prefix less then again ... let's fix it and run:
(defn runner2 [acc val] (if (< (second acc) val)
[(inc (first acc)) val]
[(first acc) val]))
(defn count-increases4 [input]
(reduce runner2
[0 (first input)]
(rest input)))
(defn run4 [] (count-increases4 depths))
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run4)]
[7 263]
Puh finally correct!
Let's try to do the advanced version as well!
This time I need to check a window of 3 numbers against the window moved up by one. That's the same thing right?
Let's see if we can use the same solution just interleaving the depths while dropping one every time:
[:pprint (interleave (range 10) (drop 1 (range 10)) (drop 2 (range 10)))]
(0 1 2 1 2 3 2 3 4 3 4 5 4 5 6 5 6 7 6 7 8 7 8 9)
Put it in:
(defn runner3 [acc val] (if (< (apply + (second acc)) (apply + val))
[(inc (first acc)) val]
[(first acc) val]))
(defn count-increases5 [input]
(reduce runner3
(rest (interleave input (drop 1 input) (drop 2 input)))
[0 (first (interleave input (drop 1 input) (drop 2 input)))]))
(defn run5 [] (count-increases5 depths))
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run5)]
{:via [{:type java.lang.IllegalArgumentException, :message "Don't know how to create ISeq from: java.lang.Long", :at [clojure.lang.RT seqFrom "RT.java" 557]}], :trace [[clojure.lang.RT seqFrom "RT.java" 557] [clojure.lang.RT seq "RT.java" 537] [clojure.core$seq__5419 invokeStatic "core.clj" 139] [clojure.core$apply invokeStatic "core.clj" 662] [clojure.core$apply invoke "core.clj" 662] [advent.day1$runner3 invokeStatic "day1.clj" 74] [advent.day1$runner3 invoke "day1.clj" 74] [clojure.lang.AFn applyToHelper "AFn.java" 156] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 92] [clojure.lang.PersistentVector reduce "PersistentVector.java" 343] [clojure.core$reduce invokeStatic "core.clj" 6829] [clojure.core$reduce invoke "core.clj" 6812] [advent.day1$count_increases5 invokeStatic "day1.clj" 79] [advent.day1$count_increases5 invoke "day1.clj" 78] [clojure.lang.AFn applyToHelper "AFn.java" 154] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 90] [advent.day1$run5 invokeStatic "day1.clj" 83] [advent.day1$run5 invoke "day1.clj" 83] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.instrument$trace_fn_call$fn__17843 invoke "instrument.cljc" 51] [cyrik.omni_trace.instrument$trace_fn_call invokeStatic "instrument.cljc" 49] [cyrik.omni_trace.instrument$trace_fn_call invoke "instrument.cljc" 40] [cyrik.omni_trace.instrument$instrumented$instrumented__17851 invoke "instrument.cljc" 88] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace.deep_trace$run_traced$fn__18188 invoke "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced invokeStatic "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced doInvoke "deep_trace.clj" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [clojure.lang.AFn applyToHelper "AFn.java" 154] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.lang.Var applyTo "Var.java" 705] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace$run_traced invokeStatic "omni_trace.cljc" 67] [cyrik.omni_trace$run_traced doInvoke "omni_trace.cljc" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [oz.day1$eval68071 invokeStatic "NO_SOURCE_FILE" 0] [oz.day1$eval68071 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.java" 7181] [clojure.lang.Compiler eval "Compiler.java" 7136] [clojure.core$eval invokeStatic "core.clj" 3202] [clojure.core$eval invoke "core.clj" 3198] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416$fn__65417 invoke "next.clj" 899] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416 invoke "next.clj" 898] [oz.next$evaluate_block_BANG_$fn__65402 invoke "next.clj" 897] [clojure.core.async$thread_call$fn__45672 invoke "async.clj" 484] [clojure.lang.AFn run "AFn.java" 22] [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1136] [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 635] [java.lang.Thread run "Thread.java" 833]], :cause "Don't know how to create ISeq from: java.lang.Long"}
exception again?
[:vega (assoc (cyrik.omni-trace/rooted-flamegraph 'advent.day1/run5) :width 1200 :height 500)]
It seems we called runner with the wrong inputs. Wouldn't it be great to see what reduce got as inputs to know what happened?
Let's take off the security breaks:
(defn run6 [] (count-increases5 depths))
[:pprint (reset! cyrik.omni-trace.instrument/ns-blacklist [])]
[]
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run6)]
{:via [{:type java.lang.NullPointerException, :message "Cannot invoke \"java.util.concurrent.Future.get()\" because \"fut\" is null", :at [clojure.core$deref_future invokeStatic "core.clj" 2304]}], :trace [[clojure.core$deref_future invokeStatic "core.clj" 2304] [clojure.core$deref invokeStatic "core.clj" 2324] [clojure.core$deref invoke "core.clj" 2310] [cyrik.omni_trace.deep_trace$run_traced$fn__18188 invoke "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced invokeStatic "deep_trace.clj" 72] [cyrik.omni_trace.deep_trace$run_traced doInvoke "deep_trace.clj" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [clojure.lang.AFn applyToHelper "AFn.java" 154] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.lang.Var applyTo "Var.java" 705] [clojure.core$apply invokeStatic "core.clj" 667] [clojure.core$apply invoke "core.clj" 662] [cyrik.omni_trace$run_traced invokeStatic "omni_trace.cljc" 67] [cyrik.omni_trace$run_traced doInvoke "omni_trace.cljc" 66] [clojure.lang.RestFn invoke "RestFn.java" 410] [oz.day1$eval68737 invokeStatic "NO_SOURCE_FILE" 0] [oz.day1$eval68737 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.java" 7181] [clojure.lang.Compiler eval "Compiler.java" 7136] [clojure.core$eval invokeStatic "core.clj" 3202] [clojure.core$eval invoke "core.clj" 3198] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416$fn__65417 invoke "next.clj" 899] [oz.next$evaluate_block_BANG_$fn__65402$fn__65416 invoke "next.clj" 898] [oz.next$evaluate_block_BANG_$fn__65402 invoke "next.clj" 897] [clojure.core.async$thread_call$fn__45672 invoke "async.clj" 484] [clojure.lang.AFn run "AFn.java" 22] [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1136] [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 635] [java.lang.Thread run "Thread.java" 833]], :cause "Cannot invoke \"java.util.concurrent.Future.get()\" because \"fut\" is null"}
(reset! cyrik.omni-trace.instrument/ns-blacklist ['cljs.core 'clojure.core])
[:vega (assoc (cyrik.omni-trace/rooted-flamegraph 'advent.day1/run6) :width 1200 :height 690)]
interesting interlude: the traces show how lazily some of clojure's seq functions work
Oh! I called the final partition with the first element instead of calling first on partition! easy fix:
(defn count-increases6 [input]
(reduce runner3
(partition 3 (rest (interleave input (drop 1 input) (drop 2 input))))
[0 (first (partition 3 (interleave input (drop 1 input) (drop 2 input))))]))
Ah switched around again, this time i see it! (plus the indexes are matching again ...)
(defn count-increases7 [input]
(reduce runner3
[0 (first (partition 3 (interleave input (drop 1 input) (drop 2 input))))]
(partition 3 (rest (interleave input (drop 1 input) (drop 2 input))))))
(defn run7 [] (count-increases7 depths))
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run7)]
[5 (269 260 269)]
I got that working as well, finally.
Although it does look a little ugly, let's clean it up by using the step version of partition and not running it twice:
(defn count-increases-final [input]
(let [windowed (partition 3 1 input)]
(reduce runner3
[0 (first windowed)]
(rest windowed))))
(defn run-final [] (count-increases-final depths))
[:pprint (cyrik.omni-trace/run-traced 'advent.day1/run-final)]
[5 (269 260 263)]