An Advent Screencast

tl;dr Screencasting is hard!

To conclude this advent blog series, I thought I’d give something new a try: recording a screencast.

It’s me stumbling through solving one of Eric Normand’s coding challenges from his excellent Clojure newsletter. It’s way too long, it’s awkward, it’s unedited. I’m sipping coffee, I’m commenting on sipping coffee, I ramble incessantly, I make no sense! Nobody should watch it, but I’m still oddly proud of it.

I felt the terrifying pressure of looking and sounding like an idiot, even though I know nobody is going to watch it! But part of the point was realizing that I’d look like a fool, and being okay with that.

I gained a ton of respect for the folks who do this well. They make it look so easy! But it is hard to both solve a problem and explain that solution in real time.

Here’s the code I wound up with:

(ns pf.task-deps)

(def tasks [:clean-breakfast :shoes :socks :cook-breakfast :eat-breakfast])

(def dependencies [[:socks :shoes] ;; socks come before shoes; shoes depend on socks
                   [:cook-breakfast :eat-breakfast] ;; cooking comes before eating
                   [:eat-breakfast :clean-breakfast]])

(defn order-tasks [tasks dependencies]
  (let [deps (reduce (fn [m [dependency dependent]]
                       (assoc m dependent dependency))
                     {}
                     dependencies)]
    (:ordered (reduce (fn [{:keys [deps ordered used] :as state} task]
                        (if (contains? used task)
                          state
                          (loop [t task
                                 t-deps ()
                                 deps deps]
                            (if-let [d (get deps t)]
                              (recur d (conj t-deps d) (dissoc deps t))
                              (let [new-tasks (concat ordered (remove used (concat t-deps [task])))]
                                {:ordered (into [] new-tasks)
                                 :used    (into #{} new-tasks)
                                 :deps    deps})))))
                      {:ordered []
                       :deps deps
                       :used #{}}
                      tasks))))

(comment
  (require 'hashp.core)

  (let [tasks [:cook-breakfast :clean-breakfast :socks :eat-breakfast :shoes]]
    (order-tasks tasks dependencies))

  (let [tasks [:eat-breakfast :cook-breakfast :socks :clean-breakfast :shoes]]
    (order-tasks tasks dependencies))

  (order-tasks #p (-> tasks shuffle vec) dependencies))

Questions? Comments? Contact me!

Tools Used

Clojure
1.10.1
Cursive
1.9.0-2019.3
hashp
0.10.0
IntelliJ IDEA
2019.3 (Community Edition)