These are the Voyages of the Porkostomus
https://porkostomus.gitlab.io/
Cryogen blog created with Clojure
Fri, 26 Oct 2018 01:30:34 +0000
clj-rss
https://porkostomus.gitlab.io/posts-output/2018-10-23-minesweeper/
https://porkostomus.gitlab.io/posts-output/2018-10-23-minesweeper/
Minesweeper in Reagent
<p><img src="/img/minesweeper-logo.png" alt="Minesweeper" /> </p><p>I had previously written an <a href="https://gitlab.com/porkostomus/tsweep">ASCII Minesweeper game</a> in Clojure that you play in the terminal, but wanted to make a version that runs in the browser.</p><p>Then I realized I could just put it in a KLIPSE snippet, and we'll be able to play it right here on this page! In the process we'll improve upon the code as well as make it easier to understand and even change to other games, like Sudoku or Othello.</p><p>KLIPSE makes it really easy to use Reagent. We just <code>require</code> it like usual: </p><pre><code class="klipse-cljs nohighlight">(require '[reagent.core :as r])
</code></pre><p>First we'll define some constants for our game, like the board dimensions and number of mines:</p><pre><code class="klipse-cljs nohighlight">(def board-width 12)
(def board-height 12)
(def num-mines 18)
</code></pre><p>We'll use the <code>for</code> macro to generate a sequence of x and y coordinates, and then use <code>shuffle</code> to scramble them - that way when we set our mines they will be in random positions.</p><pre><code class="klipse-cljs nohighlight">(defn rand-positions []
(shuffle
(for [i (range board-width)
j (range board-height)]
[i j])))
(defn set-mines []
(loop [squares (repeat num-mines 1)]
(if (= (count squares) (* board-width board-height))
squares
(recur (conj squares 0)))))
(defn init-matrix []
(into {}
(map vector
(rand-positions)
(set-mines))))
(def app-state
(r/atom
{:matrix (init-matrix)
:stepped []
:game-status :in-progress
:message "Tread lightly..."}))
</code></pre><p>Now we need to implement the mine-detector, and have it do the thing where it recursively clears the squares with no surrounding mines. We start with a simple predicate function to find out if a given square is mined:</p><pre><code class="klipse-cljs nohighlight">(defn mine? [x y]
(= 1 (get (:matrix @app-state) [x y])))
</code></pre><p>Now the fun part - we define a function for each of the 8 directions, which will take a square and a number of mines and add 1 to it if that neighboring square has a mine in it. Each one will return the current coordinates as well as the mine count, so we can chain them together. You know what... let's do this right, by going clockwise from the top-left.</p><pre><code class="klipse-cljs nohighlight">(defn top-left? [x y n]
(if (mine? (dec x) (dec y))
[x y (inc n)]
[x y n]))
(defn top? [x y n]
(if (mine? x (dec y))
[x y (inc n)]
[x y n]))
(defn top-right? [x y n]
(if (mine? (inc x) (dec y))
[x y (inc n)]
[x y n]))
(defn right? [x y n]
(if (mine? (inc x) y)
[x y (inc n)]
[x y n]))
(defn bottom-right? [x y n]
(if (mine? (inc x) (inc y))
[x y (inc n)]
[x y n]))
(defn bottom? [x y n]
(if (mine? x (inc y))
[x y (inc n)]
[x y n]))
(defn bottom-left? [x y n]
(if (mine? (dec x) (inc y))
[x y (inc n)]
[x y n]))
(defn left? [x y n]
(if (mine? (dec x) y)
[x y (inc n)]
[x y n]))
</code></pre><p>Now we take this neat little thing and spin it around like so:</p><pre><code class="klipse-cljs nohighlight">(defn mine-detector [x y]
(->> [x y 0]
(apply top-left?)
(apply top?)
(apply top-right?)
(apply right?)
(apply bottom-right?)
(apply bottom?)
(apply bottom-left?)
(apply left?)
last))
</code></pre><p>When we click on a square it will activate this function:</p><pre><code class="klipse-cljs nohighlight">(defn step! [x y]
(swap! app-state assoc-in [:stepped]
(conj (:stepped @app-state) [x y])))
</code></pre><p>In the case that <code>mine-detector</code> returns <code>0</code>, we want to auto-step all around it:</p><pre><code class="klipse-cljs nohighlight">(defn clear-squares [x y]
(swap! app-state assoc-in [:stepped]
(conj (:stepped @app-state)
[(dec x) (dec y)]
[x (dec y)]
[x (inc y)]
[(dec x) y]
[(inc x) y]
[(inc x) (dec y)]
[(inc x) (inc y)]
[(dec x) (inc y)])))
</code></pre><p>A side effect of this is that our <code>:stepped</code> vector ends up with duplicates and invalid squares in it (due to the edges). This isn't a problem, but we need to filter them out so we can use the count to see if we've won:</p><pre><code class="klipse-cljs nohighlight">(defn valid-square? [[x y]]
(and (<= 0 x (dec board-width))
(<= 0 y (dec board-width))))
(defn filter-squares [[x y]]
(filter valid-square? (distinct (:stepped @app-state))))
(defn win? []
(= num-mines
(- (* board-height board-width)
(count (filter-squares (:stepped @app-state))))))
</code></pre><p>Now here are our rendering functions:</p><pre><code class="klipse-reagent nohighlight">(defn blank [x y]
[:rect
{:width 0.9
:height 0.9
:fill "grey"
:x (+ 0.05 x)
:y (+ 0.05 y)
:on-click
(fn blank-click [e]
(when (= (:game-status @app-state) :in-progress)
(step! x y)
(if (win?)
(do (swap! app-state assoc :game-status :win)
(swap! app-state assoc :message "Congratulations!")))
(if (= 1 (get (:matrix @app-state) [x y]))
(do (swap! app-state assoc :game-status :dead)
(swap! app-state assoc :message "Fuck. You blew up."))
(if (zero? (mine-detector x y))
(clear-squares x y)))))}])
(defn rect-cell
[x y]
[:rect.cell
{:x (+ 0.05 x) :width 0.9
:y (+ 0.05 y) :height 0.9
:fill "white"
:stroke-width 0.025
:stroke "black"}])
(defn text-cell [x y]
[:text
{:x (+ 0.5 x) :width 1
:y (+ 0.72 y) :height 1
:text-anchor "middle"
:font-size 0.6}
(if (zero? (mine-detector x y))
""
(str (mine-detector x y)))])
(defn cross [i j]
[:g {:stroke "darkred"
:stroke-width 0.4
:stroke-linecap "round"
:transform
(str "translate(" (+ 0.5 i) "," (+ 0.5 j) ") "
"scale(0.3)")}
[:line {:x1 -1 :y1 -1 :x2 1 :y2 1}]
[:line {:x1 1 :y1 -1 :x2 -1 :y2 1}]])
(defn render-board []
(into
[:svg.board
{:view-box (str "0 0 " board-width " " board-height)
:shape-rendering "auto"
:style {:max-height "500px"}}]
(for [i (range board-width)
j (range board-height)]
[:g
[rect-cell i j]
(if (some #{[i j]} (:stepped @app-state))
(if (= 1 (get (:matrix @app-state) [i j]))
[cross i j]
[text-cell i j])
[blank i j])])))
(defn mine []
[:center
[:h1 (:message @app-state)]
[:button
{:on-click
(fn new-game-click [e]
(swap! app-state assoc
:matrix (init-matrix)
:message "Welcome back"
:game-status :in-progress
:stepped []))}
"Reset"]
[:div [render-board]]])
[mine]
</code></pre>
Tue, 23 Oct 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-29-Just-Juxt-46/
https://porkostomus.gitlab.io/posts-output/2018-09-29-Just-Juxt-46/
Just Juxt #46: Comparisons (4clojure #166)
<p><img src="/img/comparisons.png" alt="Comparisons" /></p><blockquote><p>For any orderable data type it's possible to derive all of the basic comparison operations (<_ _="_" and="and">) from a single operation (any operator but = or ≠ will work). Write a function that takes three arguments, a less than operator for the data and two items to compare. The function should return a keyword describing the relationship between the two items. The keywords for the relationship between x and y are as follows: </_></p></blockquote><ul><li>x = y → :eq</li><li>x > y → :gt</li><li>x < y → :lt</li></ul><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn comparisons [a b c]
(case (map (juxt a (complement a)) [b c] [c b])
[[true false] [false true]] :lt
[[false true] [false true]] :eq
[[false true] [true false]] :gt))
(deftest comparisons-test
(is (= :gt (comparisons < 5 1)))
(is (= :eq (comparisons (fn [x y] (< (count x) (count y))) "pear" "plum")))
(is (= :lt (comparisons (fn [x y] (< (mod x 5) (mod y 5))) 21 3)))
(is (= :gt (comparisons > 0 2))))
(run-tests)
</code></pre>
Sat, 29 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-28-Just-Juxt-45/
https://porkostomus.gitlab.io/posts-output/2018-09-28-Just-Juxt-45/
Just Juxt #45: Map Defaults (4clojure #156)
<p><img src="/img/mapdefaults.jpg" alt="Map Defaults" /></p><p>When retrieving values from a map, you can specify default values in case the key is not found:</p><pre><code>(= 2 (:foo {:bar 0, :baz 1} 2))
</code></pre><p>However, what if you want the map itself to contain the default values?</p><blockquote><p>Write a function which takes a default value and a sequence of keys and constructs a map. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn map-defaults [v ks]
(into {}
(map (juxt
identity
(constantly v))
ks)))
(deftest map-defaults-test
(is (= (map-defaults 0 [:a :b :c])
{:a 0 :b 0 :c 0}))
(is (= (map-defaults "x" [1 2 3])
{1 "x" 2 "x" 3 "x"}))
(is (= (map-defaults [:a :b] [:foo :bar])
{:foo [:a :b] :bar [:a :b]})))
(run-tests)
</code></pre>
Fri, 28 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-27-Just-Juxt-44/
https://porkostomus.gitlab.io/posts-output/2018-09-27-Just-Juxt-44/
Just Juxt #44: Pairwise Disjoint Sets (4clojure #153)
<p><img src="/img/disjoint.png" alt="Disjoint sets" /></p><p>Given a set of sets, create a function which returns true if no two of those sets have any elements in common and false otherwise. Such sets are usually called pairwise disjoint or mutually disjoint. Some of the test cases are a bit tricky, so pay a little more attention to them.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn disjoint [s]
((comp (partial apply ==)
(juxt
(comp (partial reduce +) (partial map count))
(comp count (partial apply clojure.set/union)))) s))
(deftest disjoint-test
(is (= (disjoint #{#{\U} #{\s} #{\e \R \E} #{\P \L} #{\.}})
true))
(is (= (disjoint #{#{:a :b :c :d :e}
#{:a :b :c :d}
#{:a :b :c}
#{:a :b}
#{:a}})
false))
(is (= (disjoint #{#{[1 2 3] [4 5]}
#{[1 2] [3 4 5]}
#{[1] [2] 3 4 5}
#{1 2 [3 4] [5]}})
true))
(is (= (disjoint #{#{'a 'b}
#{'c 'd 'e}
#{'f 'g 'h 'i}
#{''a ''c ''f}})
true))
(is (= (disjoint #{#{'(:x :y :z) '(:x :y) '(:z) '()}
#{#{:x :y :z} #{:x :y} #{:z} #{}}
#{'[:x :y :z] [:x :y] [:z] [] {}}})
false))
(is (= (disjoint #{#{distinct?}
#{#(-> %) #(-> %)}
#{#(-> %) #(-> %) #(-> %)}
#{#(-> %) #(-> %) #(-> %)}})
true))
(is (= (disjoint #{#{(#(-> *)) + (quote mapcat) #_ nil}
#{'+ '* mapcat (comment mapcat)}
#{(do) set contains? nil?}
#{, , , #_, , empty?}})
false)))
(run-tests)
</code></pre>
Thu, 27 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-26-Just-Juxt-43/
https://porkostomus.gitlab.io/posts-output/2018-09-26-Just-Juxt-43/
Just Juxt #43: Latin Square Slicing (4clojure #152)
<p><img src="/img/latin.png" alt="Latin square" /></p><p>A <a href="http://en.wikipedia.org/wiki/Latin_square">Latin square</a> of order n is an n x n array that contains n different elements, each occurring exactly once in each row, and exactly once in each column. For example, among the following arrays only the first one forms a Latin square:</p><pre><code>A B C A B C A B C
B C A B C A B D A
C A B C A C C A B
</code></pre> <p>Let V be a vector of such vectors(Of course, we can consider sequences instead of vectors) that they may differ in length(Length of a vector is the number of elements in the vector). We will say that an arrangement of vectors of V in consecutive rows is an alignment (of vectors) of V if the following conditions are satisfied:</p><p>All vectors of V are used. Each row contains just one vector. The order of V is preserved. All vectors of maximal length are horizontally aligned each other. If a vector is not of maximal length then all its elements are aligned with elements of some subvector of a vector of maximal length. Let L denote a Latin square of order 2 or greater. We will say that L is included in V or that V includes L iff there exists an alignment of V such that contains a subsquare that is equal to L. For example, if V equals <a href="">[1 2 3</a>[3 1 2]] then there are nine alignments of V (brackets omitted):</p><pre><code>
1 2 3
1 2 3 1 2 3 1 2 3
A 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
1 2 3 1 2 3 1 2 3
B 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
1 2 3 1 2 3 1 2 3
C 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
</code></pre> <p>Alignment A1 contains Latin square <a href="">[1 2 3</a>[3 1 2]], alignments A2, A3, B1, B2, B3 contain no Latin squares, and alignments C1, C2, C3 contain <a href="">[2 1</a>]. Thus in this case V includes one Latin square of order 3 and one of order 2 which is included three times. Our aim is to implement a function which accepts a vector of vectors V as an argument, and returns a map which keys and values are integers. Each key should be the order of a Latin square included in V, and its value a count of different Latin squares of that order included in V. If V does not include any Latin squares an empty map should be returned. In the previous example the correct output of such a function is {3 1, 2 1} and not {3 1, 2 3}.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn latin-slice [m]
(let [width (apply max (map count m))
squares (fn [m]
(let [[c-max c-min] (apply (juxt max min) (map count m))
n (count m)
sizes (map count m)
space #(- (apply min (map - sizes %)) n)
invert (fn [v] (map #(map (partial - (apply max %)) %) v))
cart (fn cart [[a & r]]
(if a (for [x a y (cart r)] (cons x y)) [[]]))
aligns (filter
#(>= (space %) 0)
(distinct (invert (cart
(map #(range (inc (- width (count %)))) m)))))
shift (fn [v] (mapv
#(subvec %2 %1 (+ n %1))
v m))]
(map shift
(for [a aligns t (range (inc (space a)))]
(map #(+ t %) a)))))
latin? (fn [m]
(and
(= (count (set (flatten m))) (count m))
(every?
#(apply distinct? %)
(concat m (apply map vector m)))))
max-sub (reduce
#(if (> %1 %2) (dec %1) %1)
(count m)
(map count m))]
(apply hash-map
(mapcat
(fn[n] (#(if (> % 0) [n %] [])
(count
(filter latin?
(reduce #(conj %1 %2)
#{}
(mapcat squares (partition n 1 m)))))))
(range 2 (inc max-sub))))))
(deftest latin-slice-test
(is (= (latin-slice '[[A B C D]
[A C D B]
[B A D C]
[D C A B]])
{}))
(is (= (latin-slice '[[A B C D E F]
[B C D E F A]
[C D E F A B]
[D E F A B C]
[E F A B C D]
[F A B C D E]])
{6 1}))
(is (= (latin-slice '[[A B C D]
[B A D C]
[D C B A]
[C D A B]])
{4 1, 2 4}))
(is (= (latin-slice '[[B D A C B]
[D A B C A]
[A B C A B]
[B C A B C]
[A D B C A]])
{3 3}))
(is (= (latin-slice [ [2 4 6 3]
[3 4 6 2]
[6 2 4] ])
{}))
(is (= (latin-slice [[1]
[1 2 1 2]
[2 1 2 1]
[1 2 1 2]
[] ])
{2 2}))
(is (= (latin-slice [[3 1 2]
[1 2 3 1 3 4]
[2 3 1 3] ])
{3 1, 2 2}))
(is (= (latin-slice [[8 6 7 3 2 5 1 4]
[6 8 3 7]
[7 3 8 6]
[3 7 6 8 1 4 5 2]
[1 8 5 2 4]
[8 1 2 4 5]])
{4 1, 3 1, 2 7})))
(run-tests)
</code></pre>
Wed, 26 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-25-Just-Juxt-42/
https://porkostomus.gitlab.io/posts-output/2018-09-25-Just-Juxt-42/
Just Juxt #42: Pascal's trapezoid (4clojure #147)
<p><img src="/img/pacsal.jpg" alt="Pascal" /></p><p>Write a function that, for any given input vector of numbers, returns an infinite lazy sequence of vectors, where each next one is constructed from the previous following the rules used in <a href="http://en.wikipedia.org/wiki/Pascal" s_triangle="s_triangle">Pascal's Triangle</a>. For example, for [3 1 2], the next row is [3 4 3 2].</p><p>Beware of arithmetic overflow! In clojure (since version 1.3 in 2011), if you use an arithmetic operator like + and the result is too large to fit into a 64-bit integer, an exception is thrown. You can use +' to indicate that you would rather overflow into Clojure's slower, arbitrary-precision bigint.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn pascal [ss]
(iterate (fn [v] (apply map +(map #(conj % 0)
((juxt vec seq) v)))) ss))
(deftest pascal-test
(is (= (second (pascal [2 3 2])) [2 5 5 2]))
(is (= (take 5 (pascal [1])) [[1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]]))
(is (= (take 2 (pascal [3 1 2])) [[3 1 2] [3 4 3 2]]))
(is (= (take 100 (pascal [2 4 2])) (rest (take 101 (pascal [2 2]))))))
(run-tests)
</code></pre>
Tue, 25 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-24-Just-Juxt-41/
https://porkostomus.gitlab.io/posts-output/2018-09-24-Just-Juxt-41/
Just Juxt #41: Tricky card games (4clojure #141)
<p><img src="/img/trick.jpg" alt="Cards" /></p><p>In <a href="http://en.wikipedia.org/wiki/Trick-taking_game">trick-taking card games</a> such as bridge, spades, or hearts, cards are played in groups known as "tricks" - each player plays a single card, in order; the first player is said to "lead" to the trick. After all players have played, one card is said to have "won" the trick. How the winner is determined will vary by game, but generally the winner is the highest card played in the suit that was led. Sometimes (again varying by game), a particular suit will be designated "trump", meaning that its cards are more powerful than any others: if there is a trump suit, and any trumps are played, then the highest trump wins regardless of what was led.</p><p>Your goal is to devise a function that can determine which of a number of cards has won a trick. You should accept a trump suit, and return a function winner. Winner will be called on a sequence of cards, and should return the one which wins the trick. Cards will be represented in the format returned by <a href="http://www.4clojure.com/problem/128/">Problem 128, Recognize Playing Cards</a>: a hash-map of :suit and a numeric :rank. Cards with a larger rank are stronger.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn trick [t]
(fn [[l :as c]]
(last (sort-by (juxt #(= (:suit %) t)
#(= (:suit %) (:suit l))
:rank) c))))
(deftest trick-test
(is (= {:suit :club :rank 9} ((trick nil) [{:suit :club :rank 4}
{:suit :club :rank 9}])))
(is (= {:suit :spade :rank 2} ((trick nil) [{:suit :spade :rank 2}
{:suit :club :rank 10}])))
(is (= {:suit :club :rank 10} ((trick :club) [{:suit :spade :rank 2}
{:suit :club :rank 10}])))
(is (= {:suit :heart :rank 8}
((trick :heart) [{:suit :heart :rank 6} {:suit :heart :rank 8}
{:suit :diamond :rank 10} {:suit :heart :rank 4}]))))
(run-tests)
</code></pre>
Mon, 24 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-23-Just-Juxt-40/
https://porkostomus.gitlab.io/posts-output/2018-09-23-Just-Juxt-40/
Just Juxt #40: Intervals (4clojure #171)
<p><img src="/img/intervals.jpg" alt="Intervals" /></p><blockquote><p>Write a function that takes a sequence of integers and returns a sequence of "intervals". Each interval is a a vector of two integers, start and end, such that all integers between start and end (inclusive) are contained in the input sequence. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn intervals [c]
(let [s (set c)]
(map (juxt first last)
(take-nth 2 (partition-by #(contains? s %)
(and (seq s)
(range (apply min s) (inc (apply max s)))))))))
(deftest intervals-test
(is (= (intervals [1 2 3]) [[1 3]]))
(is (= (intervals [10 9 8 1 2 3]) [[1 3] [8 10]]))
(is (= (intervals [1 1 1 1 1 1 1]) [[1 1]]))
(is (= (intervals []) []))
(is (= (intervals [19 4 17 1 3 10 2 13 13 2 16 4 2 15 13 9 6 14 2 11])
[[1 4] [6 6] [9 11] [13 17] [19 19]])))
(run-tests)
</code></pre>
Sun, 23 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-22-Just-Juxt-39/
https://porkostomus.gitlab.io/posts-output/2018-09-22-Just-Juxt-39/
Just Juxt #39: Veitch, Please! (4clojure #140)
<p><img src="/img/veitch.jpg" alt="Veitch" /></p><p>You may want to read about <a href="https://en.wikipedia.org/wiki/Karnaugh_map">kmaps</a> first.</p><blockquote><p>Create a function which accepts as input a boolean algebra function in the form of a set of sets, where the inner sets are collections of symbols corresponding to the input boolean variables which satisfy the function (the inputs of the inner sets are conjoint, and the sets themselves are disjoint... also known as canonical minterms). Note: capitalized symbols represent truth, and lower-case symbols represent negation of the inputs. Your function must return the minimal function which is logically equivalent to the input.<br /></p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.set :as set]
[clojure.string :as str]))
(defn veitch [ss]
(let [sets
(->> [ss #{}]
(iterate (fn [[sets acc]]
(->> (for [a sets, b (disj sets a)] [a b])
(map (fn [[a b]]
(->> (set/union
(set/difference a b)
(set/difference b a))
(map (comp str/lower-case str))
((fn [[x & xs :as all]]
(and (seq all)
(apply = x xs)
[(set/intersection a b) a b]))))))
(filter identity)
((juxt
#(->> % (map first) set)
#(->> %
(reduce (fn [z x] (disj z (second x) (last x))) sets)
(set/union acc)))))))
(take-while #(seq (first %)))
last
(apply set/union))]
(->> ss
(map (fn [x] (filter #(set/subset? % x) sets)))
(filter #(= 1 (count %)))
(map first)
set)))
(deftest veitch-test
(is (= (veitch #{#{'a 'B 'C 'd}
#{'A 'b 'c 'd}
#{'A 'b 'c 'D}
#{'A 'b 'C 'd}
#{'A 'b 'C 'D}
#{'A 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'B 'C 'd}})
#{#{'A 'c}
#{'A 'b}
#{'B 'C 'd}}))
(is (= (veitch #{#{'A 'B 'C 'D}
#{'A 'B 'C 'd}})
#{#{'A 'B 'C}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'a 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'B 'c 'D}
#{'A 'B 'C 'd}
#{'A 'B 'C 'D}
#{'A 'b 'C 'd}
#{'A 'b 'C 'D}})
#{#{'a 'c}
#{'A 'C}}))
(is (= (veitch #{#{'a 'b 'c}
#{'a 'B 'c}
#{'a 'b 'C}
#{'a 'B 'C}})
#{#{'a}}))
(is (= (veitch #{#{'a 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'b 'C 'D}
#{'a 'b 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'd}})
#{#{'a 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'b 'C 'D}
#{'a 'b 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'd}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'a 'B 'c 'd}
#{'A 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}})
#{#{'a 'c}
#{'B 'c}}))
(is (= (veitch #{#{'a 'B 'c 'd}
#{'A 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'b 'C 'D}
#{'A 'b 'c 'D}
#{'A 'b 'C 'D}
#{'a 'B 'C 'd}
#{'A 'B 'C 'd}})
#{#{'B 'd}
#{'b 'D}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'A 'b 'c 'd}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'D}
#{'a 'b 'C 'd}
#{'A 'b 'C 'd}})
#{#{'B 'D}
#{'b 'd}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'A 'b 'c 'd}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'D}
#{'a 'b 'C 'd}
#{'A 'b 'C 'd}})
#{#{'B 'D}
#{'b 'd}})))
(run-tests)
</code></pre>
Sat, 22 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-21-Just-Juxt-38/
https://porkostomus.gitlab.io/posts-output/2018-09-21-Just-Juxt-38/
Just Juxt #38: Digits and bases (4clojure #137)
<p><img src="/img/digits.jpg" alt="Digits and bases" /></p><blockquote><p>Write a function which returns a sequence of digits of a non-negative number (first argument) in numerical system with an arbitrary base (second argument). Digits should be represented with their integer values, e.g. 15 would be [1 5] in base 10, [1 1 1 1] in base 2 and [15] in base 16.<br /></p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn digits [n b]
(if (zero? n)
[0]
(loop [n n, digits []]
(if (zero? n)
(reverse digits)
(let [[res rm] ((juxt #(quot % b) #(rem % b)) n)]
(recur res (conj digits rm)))))))
(deftest digits-test
(is (= [1 2 3 4 5 0 1] (digits 1234501 10)))
(is (= [0] (digits 0 11)))
(is (= [1 0 0 1] (digits 9 2)))
(is (= [1 0] (let [n (rand-int 100000)](digits n n)))))
(run-tests)
</code></pre>
Fri, 21 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-20-Just-Juxt-37/
https://porkostomus.gitlab.io/posts-output/2018-09-20-Just-Juxt-37/
Just Juxt #37: Re-implement Map (4clojure #118)
<p><img src="/img/map.jpg" alt="Map" /></p><blockquote><p>Map is one of the core elements of a functional programming language. Given a function <code>f</code> and an input sequence <code>s</code>, return a lazy sequence of <code>(f x)</code> for each element <code>x</code> in <code>s</code>. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn juxt-map [f s]
(flatten (keep (juxt f) s)))
(deftest juxt-map-test
(is (= [3 4 5 6 7]
(juxt-map inc [2 3 4 5 6])))
(is (= (repeat 10 nil)
(juxt-map (fn [_] nil) (range 10))))
(is (= [1000000 1000001]
(->> (juxt-map inc (range))
(drop (dec 1000000))
(take 2)))
(= [1000000 1000001]
(->> (juxt-map inc (range))
(drop (dec 1000000))
(take 2)))))
(comment "uncomment to run tests - this may take awhile..."
(run-tests))
</code></pre>
Thu, 20 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-20-day-6/
https://porkostomus.gitlab.io/posts-output/2018-09-20-day-6/
100 Days Of Clojure Code Day 6 - Make a Lisp - Part 2
<p>I want to take a different approach today, and set up the simplest interpreter I can.</p><p>Here's one that Eric Normand shared on <a href="https://youtu.be/WFWZlbpZ4Qg">Apropos</a>. We begin by defining some predicates for things that evaluate to themselves, like numbers and strings:</p><pre><code class="klipse-cljs nohighlight">(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr))
(my-eval {} 10)
</code></pre><pre><code class="klipse-cljs nohighlight">(my-eval {} "yo")
</code></pre><p>Symbols get the value out of the <code>env</code>:</p><pre><code class="klipse-cljs nohighlight">(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(symbol? expr)
(get env expr)))
(my-eval {'x 10} 'x)
</code></pre><p>Now lists, booleans and conditional logic:</p><pre><code class="klipse-cljs nohighlight">(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(boolean? expr)
expr
(symbol? expr)
(get env expr)
(list? expr)
(let [[op & args] expr]
(case op
'if
(let [[test then else] args]
(if (my-eval env test)
(my-eval env then)
(my-eval env else)))))))
(my-eval {} '(if true 10 20))
</code></pre><pre><code class="klipse-cljs nohighlight">(my-eval {} '(if false 10 20))
</code></pre><p>Now function calls:</p><pre><code class="klipse-cljs nohighlight">(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(boolean? expr)
expr
(symbol? expr)
(get env expr)
(list? expr)
(let [[op & args] expr]
(case op
'if
(let [[test then else] args]
(if (my-eval env test)
(my-eval env then)
(my-eval env else)))
(let [[f & args](doall (map #(my-eval env %) expr))]
(apply f args))))))
(my-eval {'+ +} '(+ 1 2))
</code></pre><pre><code class="klipse-cljs nohighlight">(my-eval {'+ +} '(+ 1 2 5))
</code></pre><pre><code class="klipse-cljs nohighlight">(my-eval {'+ +} '(+ 1 2 5
(if true 10 0)))
</code></pre>
Thu, 20 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-19-day-5/
https://porkostomus.gitlab.io/posts-output/2018-09-19-day-5/
100 Days Of Clojure Code Day 5 - Make a Lisp
<p><img src="/img/mal.png" alt="Mal" /></p><p>Today I'm gonna start an implementation of Lisp in Clojure following the <a href="https://github.com/kanaka/mal">mal - Make a Lisp</a> guide. It is a learning tool, a language with many of the features of Clojure that has been done in 73 languages! It is deeply rooted in the Clojure community, originally inspired by <a href="https://github.com/alandipert/gherkin">gherkin</a>, a functional programming language and interpreter written in GNU Bash 4. Since this is part of my 100 Days of Clojure challenge, I'm gonna make a Lisp in Clojure.</p><p>The first thing that usually comes to mind when doing such a thing is that it somehow feels like cheating. But this has been one of the most <a href="http://www.sicpdistilled.com/section/4.1/">famous</a> and <a href="https://www.youtube.com/watch?v=OyfBQmvr2Hc">beautiful</a> exercises in the Lisp tradition.</p><p>The way I see it, the project that I'm taking on is to build a toolbox. And to do it, it just so happens that I have one of the best toolboxes with which to accomplish that, Clojure.</p><p><img src="/img/lisp.png" alt="Lisp" /></p><p>In particular, the following features will make the task relatively easy:</p><ul><li>Sequential compound data structures (lists, vectors, etc)</li><li>Associative compound data structures (hash-maps)</li><li>Function references (first class functions, function pointers, etc)</li><li>Real exception handling (try/catch, raise, throw, etc)</li><li>Variable argument functions (variadic, var args, splats, apply, etc)</li><li>Function closures</li><li>regular expressions</li><li>Dynamic typing / boxed types (specifically, the ability to store different data types in the sequential and associative structures and the language keeps track of the type for you)</li><li>Compound data types support arbitrary runtime "hidden" data (metadata, metatables, dynamic fields attributes)</li></ul><p>Here is an illustration of the basic framework of our interpreter:</p><p><img src="/img/step0_repl.png" alt="Step 0" /></p><p>So we're gonna make a REPL!</p><p>We will first take a high-level overview of what the process will be like. We're gonna need 4 functions: <code>READ</code>, <code>EVAL</code>, <code>PRINT</code>, and <code>rep</code> (read-eval-print), which will go in a loop:</p><pre><code>(ns lisp.step0-repl
(:require [lisp.readline :as readline])
#?(:clj (:gen-class)))
(defn READ [& [strng]]
strng)
(defn EVAL [ast env]
ast)
(defn PRINT [exp]
exp)
(defn rep [strng] (PRINT (EVAL (READ strng), {})))
(defn repl-loop []
(let [line (readline/readline "user> ")]
(when line
(when-not (re-seq #"^\s*$|^\s*;.*$" line) ; blank/comment
(println (rep line)))
(recur))))
(defn -main [& args]
(repl-loop))
</code></pre><p>For our readline library, we can use either GNU readline or editline via the <a href="https://github.com/Chouser/clojure-jna">clojure-jna</a> project (Java Native Access) to dynamically load and use native C libs.</p><pre><code>(ns lisp.readline
(:require [clojure.string :refer [split]]
[clojure.java.io :refer [file]]
[net.n01se.clojure-jna :as jna]))
(defonce history-loaded (atom nil))
(def HISTORY-FILE (str (System/getProperty "user.home") "/.mal-history"))
;;
;; Uncomment one of the following readline libraries
;;
;; editline (BSD)
#_
(do
(def readline-call (jna/to-fn String edit/readline))
(def add-history (jna/to-fn Void edit/add_history))
(def load-history #(doseq [line (split (slurp %) #"\n")]
(jna/invoke Void edit/add_history line))))
;; GNU Readline (GPL)
;; WARNING: distributing your code with GNU readline enabled means you
;; must release your program as GPL
;#_
(do
(def readline-call (jna/to-fn String readline/readline))
(def add-history (jna/to-fn Void readline/add_history))
(def load-history (jna/to-fn Integer readline/read_history)))
(defn readline [prompt & [lib]]
(when (not @history-loaded)
(reset! history-loaded true)
(when (.canRead (file HISTORY-FILE))
(load-history HISTORY-FILE)))
(let [line (readline-call prompt)]
(when line
(add-history line)
(when (.canWrite (file HISTORY-FILE))
(spit HISTORY-FILE (str line "\n") :append true)))
line))
</code></pre><p>We have also added history support. Now we need to read and print:</p><p><img src="/img/step1_read_print.png" alt="Step 1" /></p><p>We'll make a namespace for functions related to the reader:</p><pre><code>(ns lisp.reader
(:refer-clojure :exclude [read-string])
#?(:clj (:require [clojure.tools.reader :as r]
[clojure.tools.reader.reader-types :as rt]))
#?(:cljs (:require [cljs.tools.reader :as r]
[cljs.tools.reader.reader-types :as rt])))
;; change tools.reader syntax-quote to quasiquote
(defn- wrap [sym]
(fn [rdr _] (list sym (#'r/read rdr true nil))))
(defn- wrap-with [sym]
(fn [rdr arg _] (list sym (#'r/read rdr true nil) arg)))
;; Override some tools.reader reader macros so that we can do our own
;; metadata and quasiquote handling
(def new-rmacros
(fn [f]
(fn [ch]
(case ch
\` (wrap 'quasiquote)
\~ (fn [rdr comma]
(if-let [ch (rt/peek-char rdr)]
(if (identical? \@ ch)
((wrap 'splice-unquote) (doto rdr rt/read-char) \@)
((wrap 'unquote) rdr \~))))
\^ (fn [rdr comma]
(let [m (#'r/read rdr)]
((wrap-with 'with-meta) rdr m \^)))
\@ (wrap 'deref)
(f ch)))))
#?(:clj (alter-var-root #'r/macros new-rmacros)
:cljs (set! r/macros (new-rmacros r/macros)))
(defn read-string [s]
(r/read-string s))
</code></pre><p>And for the printer:</p><pre><code>(ns lisp.printer)
#?(:clj (import '(java.io Writer)))
;; TODO Better:
;; (extend-protocol IPrintWithWriter
;; Atom
;; ...
;; PersistentArrayMap
;; ...
;; PersistentHashMap
;; ...)
;; Override atom printer
#?(:clj (defmethod clojure.core/print-method clojure.lang.Atom [a writer]
(.write writer "(atom ")
(.write writer (pr-str @a))
(.write writer ")"))
:cljs (extend-type Atom
IPrintWithWriter
(-pr-writer [a writer _]
(-write writer (str "(atom " (pr-str @a) ")")))))
;; Override hash-map printer to remove comma separators
#?(:clj (defmethod print-method clojure.lang.IPersistentMap [hm ^Writer w]
(.write w "{")
(when-let [xs (seq hm)]
(loop [[[k v] & xs] xs]
(print-method k w)
(.write w " ")
(print-method v w)
(when xs (.write w " ") (recur xs))))
(.write w "}"))
:cljs (extend-type PersistentHashMap
IPrintWithWriter
(-pr-writer [hm w _]
(-write w "{")
(when-let [xs (seq hm)]
(loop [[[k v] & xs] xs]
(-write w (pr-str k))
(-write w " ")
(-write w (pr-str v))
(when xs (-write w " ") (recur xs))))
(-write w "}"))))
;; Add a version of str that is the same all the way down (no
;; print-readably and nil printing all the way down)
(defn- pr-
([] nil)
([x]
#?(:clj (print-method x *out*)
:cljs (pr x)))
([x & more]
(pr- x)
(if-let [nmore (next more)]
(recur (first more) nmore)
(apply pr- more))))
(defn _str [& xs]
(binding [*print-readably* nil]
(with-out-str (apply pr- xs))))
</code></pre><p>That's enough to chew on for now, as I said this is just to give us an idea of what's going on. In the upcoming posts we'll go into more detail.</p>
Wed, 19 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-19-Just-Juxt-36/
https://porkostomus.gitlab.io/posts-output/2018-09-19-Just-Juxt-36/
Just Juxt #36: The Balance of N (4clojure #115)
<p><img src="/img/balnum.jpg" alt="Balanced Numbers" /></p><p>A balanced number is one whose component digits have the same sum on the left and right halves of the number.</p><blockquote><p>Write a function which accepts an integer n, and returns true iff n is balanced. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn bal-num [n]
(-> n
str
count
(/ 2)
((juxt take take-last)
(str n))
(->> (map sort) (reduce =))))
(deftest bal-num-test
(is (= true (bal-num 11)))
(is (= true (bal-num 121)))
(is (= false (bal-num 123)))
(is (= true (bal-num 0)))
(is (= false (bal-num 88099)))
(is (= true (bal-num 89098)))
(is (= true (bal-num 89089)))
(is (= (take 20 (filter bal-num (range)))
[0 1 2 3 4 5 6 7 8 9 11 22 33 44 55 66 77 88 99 101])))
(run-tests)
</code></pre>
Wed, 19 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-18-Just-Juxt-35/
https://porkostomus.gitlab.io/posts-output/2018-09-18-Just-Juxt-35/
Just Juxt #35: Game of Life (4clojure #94)
<p><img src="/img/conway.jpg" alt="Game of life" /></p><p>The game of life is a cellular automaton devised by mathematician John Conway.</p><p>The ‘board' consists of both live (#) and dead ( ) cells. Each cell interacts with its eight neighbours (horizontal, vertical, diagonal), and its next state is dependent on the following rules:</p><ol><li>Any live cell with fewer than two live neighbours dies, as if caused by under-population.</li><li>Any live cell with two or three live neighbours lives on to the next generation.</li><li>Any live cell with more than three live neighbours dies, as if by overcrowding.</li><li>Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.</li></ol><p>Write a function that accepts a board, and returns a board representing the next generation of cells.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn conway [board]
(let [w (count (first board))
c (juxt quot mod)
g (set (keep-indexed #({\# (c % w)} %2)
(mapcat seq board)))
neighbours (fn [[x y]]
(for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
[(+ dx x) (+ dy y)]))
ng (set (for [[loc n] (frequencies (mapcat neighbours g))
:when (or (= n 3) (and (= n 2) (g loc)))]
loc))]
(->>
(range (* w (count board)))
(map #(if (ng (c % w)) \# " "))
(partition w)
(map #(apply str %)))))
(deftest conway-test
(is (= (conway [" "
" ## "
" ## "
" ## "
" ## "
" "])
[" "
" ## "
" # "
" # "
" ## "
" "]))
(is (= (conway [" "
" "
" ### "
" "
" "]))
[" "
" # "
" # "
" # "
" "])
(is (= (conway [" "
" "
" ### "
" ### "
" "
" "])
[" "
" # "
" # # "
" # # "
" # "
" "])))
(run-tests)
</code></pre>
Tue, 18 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-17-Just-Juxt-34/
https://porkostomus.gitlab.io/posts-output/2018-09-17-Just-Juxt-34/
Just Juxt #34: Read Roman numerals (4clojure #92)
<p><img src="/img/clock.jpg" alt="Clock" /></p><p>Roman numerals are easy to recognize, but not everyone knows all the rules necessary to work with them. Write a function to parse a Roman-numeral string and return the number it represents. </p><p>You can assume that the input will be well-formed, in upper-case, and follow the <a href="http://en.wikipedia.org/wiki/Roman_numerals#Subtractive_principle">subtractive principle</a>. You don't need to handle any numbers greater than MMMCMXCIX (3999), the largest number representable with ordinary letters.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn roman-numeral [s]
(let [symbol-values {\I 1 \V 5
\X 10 \L 50
\C 100 \D 500
\M 1000}]
(->>
(partition-by identity s)
(map (juxt first count))
(partition-all 2 1)
(map
(fn [[[symbol cardinality] [next-symbol _]]]
(let [value (symbol-values symbol)]
(* cardinality value
(if (and next-symbol
(< value (symbol-values next-symbol)))
-1 1)))))
(apply +))))
(deftest roman-numeral-test
(is (= 14 (roman-numeral "XIV")))
(is (= 827 (roman-numeral "DCCCXXVII")))
(is (= 3999 (roman-numeral "MMMCMXCIX")))
(is (= 48 (roman-numeral "XLVIII"))))
(run-tests)
</code></pre>
Mon, 17 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-16-Just-Juxt-33/
https://porkostomus.gitlab.io/posts-output/2018-09-16-Just-Juxt-33/
Just Juxt #33: Graph Connectivity (4clojure #91)
<p><img src="/img/graph.png" alt="Graph connectivity" /></p><blockquote><p>Given a graph, determine whether the graph is connected. A connected graph is such that a path exists between any two given nodes. </p></blockquote><ul><li>Your function must return true if the graph is connected and false otherwise.</li><li>You will be given a set of tuples representing the edges of a graph. Each member of a tuple being a vertex/node in the graph.</li><li>Each edge is undirected (can be traversed either direction).</li></ul><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn graph [g]
(= 1 (count (reduce
(fn [acc pair]
(let [pred (partial some (set pair))
[conn dis] ((juxt filter remove) pred acc)]
(set (cons (set (apply concat pair conn)) dis))))
#{}
g))))
(deftest graph-test
(is (= true (graph #{[:a :a]})))
(is (= true (graph #{[:a :b]})))
(is (= false (graph #{[1 2] [2 3] [3 1]
[4 5] [5 6] [6 4]})))
(is (= true (graph #{[1 2] [2 3] [3 1]
[4 5] [5 6] [6 4] [3 4]})))
(is (= false (graph #{[:a :b] [:b :c] [:c :d]
[:x :y] [:d :a] [:b :e]})))
(is (= true (graph #{[:a :b] [:b :c] [:c :d]
[:x :y] [:d :a] [:b :e] [:x :a]}))))
(run-tests)
</code></pre>
Sun, 16 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-16-day-2/
https://porkostomus.gitlab.io/posts-output/2018-09-16-day-2/
100 Days Of Clojure Code - Day 2
<p>Alright, so I realize that a big part of this challenge is to struggle... and do it publicly. So what I'm gonna do here is dig up one of my dark secrets. Something that I couldn't figure out and instead of asking for help, just decided to bury it down somewhere where no one would ever find it... and that way no one would ever know...</p><p>No one would ever know that I don't know how to handle exceptions.</p><p>What!?</p><p>Yes, I got stuck on something that should be so easy, and couldn't find the answer and was too embarassed to ask, and just moved on. So today, I'm gonna try to fix it. Or else struggle some more and completely embarrass myself. Then maybe someone will tell me how to do it and then I'll feel really silly.</p><p>The project is called <a href="https://github.com/porkostomus/ctrain">ctrain</a>. I wanted a way to run <a href="http://www.4clojure.com/">4clojure</a> problems from the terminal. Why? Well for one, I had built myself a tiny computer with a Raspberry Pi Zero:</p><p><img src="/img/pi.jpg" alt="Pi" /></p><p>It was inspired by Star Trek, and I made the case out of the box that the screen came in. But having just a single-core processor, and such a tiny screen, doing anything in the browser or even a graphical environment was super-awkward if not impossible. What I wanted was a cool little portable coding computer, just to do 4clojure problems and stuff. But I wanted to do it all from the command line, without even needing to start a desktop session.</p><p>First I needed a way to get the problems. There's over 100 of them and I was not about to start copying them manually. We're learning programming to make our lives easier, right? The code for the site is on Github, so I cloned the repository and got it running locally according to <a href="https://github.com/4clojure/4clojure#setup-instructions-for-running-locally">the instructions in the README</a>. This is a fun thing to do, and a worthwhile exercise in dealing with databases because it uses MongoDB. This alone took me several attempts, and I think I gave up more than once. But it sure was rewarding when I finally got the db to connect.</p><p>Success! I had my very own copy of the 4clojure site running on my machine. Now to figure out how to get the problems out of the database.</p><p>I probably could have used a JSON parser, but instead I looked at the code and saw that it used <a href="https://github.com/congomongo/congomongo">CongoMongo</a>, so I loaded it up in a REPL to try it out. It was actually pretty simple just to run a query to make it spit out all its guts, which I saved to a file.</p><p>I made myself a little convenience macro for that, by slightly modifying the <code>pp</code> macro:</p><pre><code>user=> (source pp)
(defmacro pp
"A convenience macro that pretty prints the last thing output. This is
exactly equivalent to (pprint *1)."
{:added "1.2"}
[] `(pprint *1))
</code></pre><pre><code>user=> (defmacro pf
"A convenience macro that pretty prints the last result to a file named pf.edn. "
[] `(pprint *1 (clojure.java.io/writer "pf.edn")))
</code></pre><p>Then, when I was all done scraping the dataset, I noticed that there is already <a href="https://github.com/4clojure/4clojure/blob/develop/src/foreclojure/data_set.clj">a file called data_set.clj</a> with the problems in it!</p><p>It's OK to point and laugh at me right now.</p><p>So then I had a file with my problem data, which is a giant vector of maps:</p><pre><code>[{:_id 1 :title "Nothing but the Truth"
:tests ["(= __ true)"],
:description "Complete the expression so it will evaluate to true."}
{:_id 2 :title "Simple Math"
:tests ["(= (- 10 (* 2 3)) __)"]
:description "Innermost forms are evaluated first."} ...
</code></pre><p>So that means I could <code>slurp</code> it in and grab any problem by its index:</p><pre><code>(def problems
(read-string (slurp "problems")))
(defn problem [n]
(println (str "\n#" n ": " (:title (nth problems (- n 1)))))
(println (str "\n" (:description (nth problems (- n 1)))) "\n")
(run! println (:tests (nth problems (- n 1))))
(spit (str "ans-" n)(read-line)))
</code></pre><p>We print out the problem's title, description, and each of the unit tests. Then we get input from the user and save it to a file on disk.</p><p>Next, we need to replace the double-underscore (<code>__</code>) in the problem with the answer, evaluate it, and compare the answer to what it's supposed to be:</p><pre><code>(defn final [results]
(loop [coll results]
(if (empty? coll)
(do
(spit "prob" (inc (read-string (slurp "prob"))))
(println "\nGOOD JOB! Here's the next one:")
(-main)))
(if (= false (first coll))
(do
(println "\nNope... try again or Ctrl+C to quit")
(-main)))
(recur (rest coll))))
(defn evaluator [answers]
(loop [totest answers results []]
(if (empty? totest)
(final results)
(recur (rest totest) (conj results (eval (read-string (first totest))))))))
(defn replacer [n]
(let [ans (slurp (str "ans-" n))]
(loop [tests (:tests (problems (- n 1))) replaced []]
(if (empty? tests)
(evaluator replaced)
(recur (rest tests) (conj replaced (s/replace (first tests) "__" ans)))))))
</code></pre><p>And it worked! But after playing with it for awhile, I noticed that something wasn't right. I tried entering a blank line, and it said it was correct! My program must be broken!</p><p>What could be causing this behavior? Eventually I figured it out.</p><p>The unit tests all ask whether the result of evaluating your answer is equal to something. And anything is equal to itself!</p><p>See:</p><pre><code class="klipse-cljs nohighlight">(= 1)
</code></pre><p>So it turns out there was nothing wrong with my program, I just needed to make it reject a blank answer:</p><pre><code>(if (= ans "")
(do
(println "Nice try, but blank answers are not allowed.")
(-main)))
</code></pre><p>At this point the program totally works. That is... until you enter an undefined symbol! We are (rather dangerously) using <code>eval</code> on arbitrary input, so the program will crash if you forget to quote a list or something. And on a Pi Zero, firing up the JVM takes like a couple minutes. This can be avoided by running it from the REPL, of course, but this should be a simple case of catching that exception.</p><p>Unfortunately, every attempt I've made has failed, and since this is such a weird application, I don't know how to ask for help.</p><p>How do you evaluate something, <strong>without evaluating it</strong>?</p><p>4clojure uses <a href="https://github.com/Raynes/clojail">Clojail</a>, a library for sandboxing Clojure code. So I suppose I could use that, but for this purpose, I think that is a little bit much.</p><p>Shouldn't I be able to just use a <code>try</code>/<code>catch</code> block?</p><pre><code>(defn safe-eval [exp]
(try
(eval (read-string exp))
(catch Exception e
(prn "Oops... Undefined symbol")
(-main))))
</code></pre><p>Unfortunately this doesn't work, and I feel that my novice is showing real bad right now.</p><p>It catches the undefined symbol, but also the good answers!</p><p>What am I doing wrong?</p><p>See <a href="https://youtu.be/Izb7SkM9pYk">this video</a> for an entertaining demo.</p><p>See you tomorrow!</p>
Sun, 16 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-15-Just-Juxt-32/
https://porkostomus.gitlab.io/posts-output/2018-09-15-Just-Juxt-32/
Just Juxt #32: Cartesian Product (4clojure #90)
<p><img src="/img/cartesian-products.jpg" alt="Cartesian Product" /></p><blockquote><p>Write a function which calculates the <a href="https://en.wikipedia.org/wiki/Cartesian_product">Cartesian product</a> of two sets. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn cartesian [x y]
(into #{} (mapcat #(map (juxt (constantly %) identity) y)) x))
(deftest cartesian-test
(is (= (cartesian #{"ace" "king" "queen"} #{"♠" "♥" "♦" "♣"})
#{["ace" "♠"] ["ace" "♥"] ["ace" "♦"] ["ace" "♣"]
["king" "♠"] ["king" "♥"] ["king" "♦"] ["king" "♣"]
["queen" "♠"] ["queen" "♥"] ["queen" "♦"] ["queen" "♣"]}))
(is (= (cartesian #{1 2 3} #{4 5})
#{[1 4] [2 4] [3 4] [1 5] [2 5] [3 5]}))
(is (= 300 (count (cartesian (into #{} (range 10))
(into #{} (range 30)))))))
(run-tests)
</code></pre>
Sat, 15 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-15-hundred-days-of-code/
https://porkostomus.gitlab.io/posts-output/2018-09-15-hundred-days-of-code/
100 Days Of Clojure Code - Day 1
<p><img src="/img/100DaysOfCode.jpg" alt="100 Days of Code" /> </p><p>Alright, so here we go! For the first day of the <a href="https://www.100daysofcode.com/">100 Days Of Code</a> challenge I did the same thing I've been doing every day for the past month, I published a <a href="https://porkostomus.gitlab.io/posts-output/2018-09-15-Just-Juxt-32/">Just Juxt</a>. </p><p>Let's see what the other participants did!</p><p>Taking a look at <a href="https://github.com/jr0cket/100-days-of-clojure-code/blob/master/log.md">jr0cket's log</a>, he already began yesterday by testing and describing his development environment, so I ought to do something like that too.</p><p>The text editor I use is <a href="https://github.com/porkostomus/bob">Bob</a>, which I built myself in C. It's nothing fancy, it doesn't even have undo. We like livin' dangerously here, me and Bob, on Planet Porkostomus. I do plan on giving it REPL support as soon as I figure out how. I might use the <a href="https://clojure.org/reference/repl_and_main#_launching_a_socket_server">Socket REPL</a>, since it's just Telnet. Or better yet - pREPL, which I hear uses structured EDN data.</p><p><img src="/img/bob.png" alt="Bob" /></p><p>I also have <a href="http://spacemacs.org/">Spacemacs</a>, <a href="https://www.vim.org/">Vim</a> with <a href="https://github.com/tpope/vim-fireplace">fireplace</a> and <a href="https://atom.io/packages/proto-repl">Atom with proto-repl</a> which may come in handy for its visualizations. But mostly I just work in the terminal, in my little Bob the text editor, and paste stuff into the REPL. Then when I get something I want to present, I usually put it into a page in self-hosted Clojurescript. That produces a nice environment with constant evaluation that I find very handy.</p><p>So let's see what jr0cket is doing today... it's a <a href="https://github.com/jr0cket/webapp-status-monitor">webapp-status-monitor</a>, the start of a very simple status monitor mock application.</p><p>And then we have <a href="https://github.com/kazesberger/100-days-of-clojure-code">kazesberger</a>, who is working on a <a href="https://exercism.io/my/solutions/6b8644558388479fbedcb8db4f751f16">Minesweeper</a> exercise.</p><p>I'm a mentor on <a href="https://exercism.io/">exercism</a> and didn't even realize they had a Minesweeper. I would have looked to it for help back when I was making <a href="https://github.com/porkostomus/tsweep">my own</a>. It was quite a mind-bender, an unexpectedly difficult problem.</p><p>Let's check it out:</p><pre><code class="klipse-cljs nohighlight">(ns minesweeper
(:require [cljs.test :refer-macros [deftest testing is run-tests]]
[clojure.string :refer [join]]))
(defn draw [] ;; <- arglist goes here
;; your code goes here
)
(def line-separator \n)
(deftest zero-size-board
(is (= (draw "") "")))
(deftest empty-board
(is (= (draw (join line-separator [" "
" "
" "]))
(join line-separator [" "
" "
" "]))))
(deftest surrounded
(is (= (draw (join line-separator ["***"
"* *"
"***"]))
(join line-separator ["***"
"*8*"
"***"]))))
(deftest board-full-of-mines
(is (= (draw (join line-separator ["***"
"***"
"***"]))
(join line-separator ["***"
"***"
"***"]))))
(deftest horizontal-line
(is (= (draw " * * ")
"1*2*1")))
(deftest vertical-line
(is (= (draw (join line-separator [" "
"*"
" "
"*"
" "]))
(join line-separator ["1"
"*"
"2"
"*"
"1"]))))
(deftest cross
(is (= (draw (join line-separator [" * "
" * "
"*****"
" * "
" * "]))
(join line-separator [" 2*2 "
"25*52"
"*****"
"25*52"
" 2*2 "]))))
(run-tests)
</code></pre><p>Now if we take a look over at Exhibit B, jr0cket is cooking up something pretty nice. And he's doing a great job documenting it, too! It's a Ring app with Compojure, Hiccup and Bootstrap. Let's try cloning the <a href="https://github.com/jr0cket/webapp-status-monitor">repository</a> and firing it up:</p><p><img src="/img/jr0cket.png" alt="jr0cket" /></p><p>Awesome!</p><p>We'll be checking back periodically to see how we're progressing. Excited to see!</p><p><img src="/img/poopy.jpg" alt="Mr. PB" /></p>
Sat, 15 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-14-Just-Juxt-31/
https://porkostomus.gitlab.io/posts-output/2018-09-14-Just-Juxt-31/
Just Juxt #31: Graph Tour (4clojure #89)
<p><img src="/img/eulerpath.jpg" alt="Eulerian Path" /></p><p>Starting with a graph you must write a function that returns true if it is possible to make a tour of the graph in which every edge is visited exactly once.</p><p>The graph is represented by a vector of tuples, where each tuple represents a single edge.</p><p>The rules are:</p><ul><li>You can start at any node.</li><li>You must visit each edge exactly once.</li><li>All edges are undirected.</li></ul><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn eulerian [g]
(if (= (count g) (count (distinct g)))
(let [g (apply merge-with clojure.set/union
(mapcat (fn [[k v]] [{k #{v}} {v #{k}}]) g))
f (fn [[s k]]
(->> (g k)
(remove s)
(map #(vector (conj s %) %))))
p (map (juxt hash-set identity) (keys g))]
(not (empty? (nth (iterate (partial mapcat f) p) (dec (count g))))))
false))
(deftest eulerian-test
(is (= true (eulerian [[:a :b]])))
(is (= false (eulerian [[:a :a] [:b :b]])))
(is (= false (eulerian [[:a :b] [:a :b] [:a :c] [:c :a]
[:a :d] [:b :d] [:c :d]])))
(is (= true (eulerian [[1 2] [2 3] [3 4] [4 1]])))
(is (= true (eulerian [[:a :b] [:a :c] [:c :b] [:a :e]
[:b :e] [:a :d] [:b :d] [:c :e]
[:d :e] [:c :f] [:d :f]])))
(is (= false (eulerian [[1 2] [2 3] [2 4] [2 5]]))))
(run-tests)
</code></pre>
Fri, 14 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-13-Just-Juxt-30/
https://porkostomus.gitlab.io/posts-output/2018-09-13-Just-Juxt-30/
Just Juxt #30: Symmetric Difference (4clojure #88)
<p><img src="/img/sd.png" alt="Symmetric Difference" /></p><blockquote><p>Write a function which returns the symmetric difference of two sets. The symmetric difference is the set of items belonging to one but not both of the two sets. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn sym-diff [a b]
(set (mapcat identity
((juxt #(remove % %2)
#(remove %2 %)) a b))))
(deftest sym-diff-test
(is (= (sym-diff #{1 2 3 4 5 6} #{1 3 5 7}) #{2 4 6 7}))
(is (= (sym-diff #{:a :b :c} #{}) #{:a :b :c}))
(is (= (sym-diff #{} #{4 5 6}) #{4 5 6}))
(is (= (sym-diff #{[1 2] [2 3]} #{[2 3] [3 4]}) #{[1 2] [3 4]})))
(run-tests)
</code></pre>
Thu, 13 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-12-Just-Juxt-29/
https://porkostomus.gitlab.io/posts-output/2018-09-12-Just-Juxt-29/
Just Juxt #29: Happy Numbers (4clojure #86)
<p><img src="/img/happy.jpg" alt="Happy Numbers" /></p><blockquote><p>Happy numbers are positive integers that follow a particular formula: take each individual digit, square it, and then sum the squares to get a new number. Repeat with the new number and eventually, you might get to a number whose squared sum is 1. This is a happy number. An unhappy number (or sad number) is one that loops endlessly. Write a function that determines if a number is happy or not. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn char->ascii
([c]
(get {\0 48 \1 49 \2 50 \3 51 \4 52 \5 53 \6 54 \7 55 \8 56 \9 57} c)))
(defn happy [n]
(= 1 (some #{1 4}
(iterate
(fn [x] (reduce
#(+ %1 (apply * ((juxt identity identity)
(- (char->ascii %2) 48))))
0
(str x)))
n))))
(deftest happy-test
(is (= (happy 7) true))
(is (= (happy 986543210) true))
(is (= (happy 2) false))
(is (= (happy 3) false)))
(run-tests)
</code></pre>
Wed, 12 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-11-Just-Juxt-28/
https://porkostomus.gitlab.io/posts-output/2018-09-11-Just-Juxt-28/
Just Juxt #28: Power Set (4clojure #85)
<p><img src="/img/powerset.png" alt="Power Set" /></p><blockquote><p>Write a function which generates the power set of a given set. The <a href="https://en.wikipedia.org/wiki/Power_set">power set</a> of a set x is the set of all subsets of x, including the empty set and x itself. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn powerset [s]
(if (empty? s)
#{s}
(let [[h t] ((juxt first (comp powerset set next)) s)]
(set (concat t (map #(conj % h) t))))))
(deftest powerset-test
(is (= (powerset #{1 :a}) #{#{1 :a} #{:a} #{} #{1}}))
(is (= (powerset #{}) #{#{}}))
(is (= (powerset #{1 2 3}) #{#{} #{1} #{2} #{3} #{1 2} #{1 3} #{2 3} #{1 2 3}}))
(is (= (count (powerset (into #{} (range 10)))) 1024)))
(run-tests)
</code></pre>
Tue, 11 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-10-Just-Juxt-27/
https://porkostomus.gitlab.io/posts-output/2018-09-10-Just-Juxt-27/
Just Juxt #27: Transitive Closure (4clojure #84)
<p><img src="/img/tc.jpg" alt="Transitive Closure" /></p><p>The <a href="https://en.wikipedia.org/wiki/Transitive_closure">transitive closure</a> of a binary relation R on a set X is the smallest relation on X that contains R and is transitive.</p><p>For example, if X is a set of airports and x R y means "there is a direct flight from airport x to airport y" (for x and y in X), then the transitive closure of R on X is the relation R+ such that x R+ y means "it is possible to fly from x to y in one or more flights". Informally, the transitive closure gives you the set of all places you can get to from any starting place.</p><blockquote><p>Write a function which generates the transitive closure of a binary relation. The relation will be represented as a set of 2 item vectors. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn extensions [s]
(fn [[k v]]
(->> s
(filter #(= v (first %)))
(map (juxt (constantly k) second)))))
(defn step [[s _]]
(vector (->> s (mapcat (extensions s)) (into s))
s))
(defn trans-closure [r]
((comp ffirst
(partial drop-while (partial apply not=))
(partial iterate step)
(juxt identity (constantly nil))) r))
(deftest trans-closure-test
(is (let [divides #{[8 4] [9 3] [4 2] [27 9]}]
(= (trans-closure divides) #{[4 2] [8 4] [8 2] [9 3] [27 9] [27 3]})))
(is (let [more-legs
#{["cat" "man"] ["man" "snake"] ["spider" "cat"]}]
(= (trans-closure more-legs)
#{["cat" "man"] ["cat" "snake"] ["man" "snake"]
["spider" "cat"] ["spider" "man"] ["spider" "snake"]})))
(is (let [progeny
#{["father" "son"] ["uncle" "cousin"] ["son" "grandson"]}]
(= (trans-closure progeny)
#{["father" "son"] ["father" "grandson"]
["uncle" "cousin"] ["son" "grandson"]}))))
(run-tests)
</code></pre>
Mon, 10 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-09-Just-Juxt-26/
https://porkostomus.gitlab.io/posts-output/2018-09-09-Just-Juxt-26/
Just Juxt #26: Half-truth (4clojure #83)
<p><img src="/img/truth.png" alt="Half-truth" /></p><blockquote><p>Write a function which takes a variable number of booleans. Your function should return true if some of the parameters are true, but not all of the parameters are true. Otherwise your function should return false. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn half-truth [& col]
(every? identity ((juxt some not-every?)
identity col)))
(deftest test-83
(is (= false (half-truth false false)))
(is (= true (half-truth true false)))
(is (= false (half-truth true)))
(is (= true (half-truth false true false)))
(is (= false (half-truth true true true)))
(is (= true (half-truth true true true false))))
(run-tests)
</code></pre>
Sun, 09 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-08-Just-Juxt-25/
https://porkostomus.gitlab.io/posts-output/2018-09-08-Just-Juxt-25/
Just Juxt #25: Perfect Numbers (4clojure #80)
<p><img src="/img/perfect.jpg" alt="Perfect Numbers" /></p><blockquote><p>A number is "perfect" if the sum of its divisors equal the number itself. 6 is a perfect number because 1+2+3=6. Write a function which returns true for perfect numbers and false otherwise. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn perfect-nums [x]
(apply =
((juxt (comp (partial reduce +)
(partial apply filter)
(juxt (partial partial
(comp zero? rem))
(partial range 1)))
identity) x)))
(deftest perfect-nums-test
(is (= (perfect-nums 6) true))
(is (= (perfect-nums 7) false))
(is (= (perfect-nums 496) true))
(is (= (perfect-nums 500) false))
(is (= (perfect-nums 8128) true)))
(run-tests)
</code></pre>
Sat, 08 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-07-Just-Juxt-24/
https://porkostomus.gitlab.io/posts-output/2018-09-07-Just-Juxt-24/
Just Juxt #24: Triangle Minimal Path (4clojure #79)
<p><img src="/img/triangle.png" alt="Triangle" /></p><blockquote><p>Write a function which calculates the sum of the minimal path through a triangle. The triangle is represented as a collection of vectors. The path should start at the top of the triangle and move to an adjacent number on the next row until the bottom of the triangle is reached. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn tri-path [[[top] & rem]]
(letfn [(left-tri [tri] (map butlast tri))
(right-tri [tri] (map rest tri))]
(if (seq rem)
(->> rem
((juxt left-tri right-tri))
(map tri-path)
(apply min)
(+ top))
top)))
(deftest test-79
(is (= (tri-path [[1] [2 4] [5 1 4] [2 3 4 5]]) (+ 1 2 1 3) 7))
(is (= (tri-path [[3] [2 4] [1 9 3] [9 9 2 4] [4 6 6 7 8] [5 7 3 5 1 4]]) (+ 3 4 3 2 7 1) 20)))
(run-tests)
</code></pre>
Fri, 07 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-06-Just-Juxt-23/
https://porkostomus.gitlab.io/posts-output/2018-09-06-Just-Juxt-23/
Just Juxt #23: Anagram Finder (4clojure #77)
<p><img src="/img/lord-dampnut.svg" alt="Bow to Lord Dampnut" /></p><blockquote><p>Write a function which finds all the anagrams in a vector of words. A word x is an anagram of word y if all the letters in x can be rearranged in a different order to form y. Your function should return a set of sets, where each sub-set is a group of words which are anagrams of each other. Each sub-set should have at least two words. Words without any anagrams should not be included in the result. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn anagram [c]
(->> c
(map (juxt sort identity))
(group-by (comp str first))
vals
(filter #(> (count %) 1))
(map #(set (map (fn [x] (second x)) %)))
set))
(deftest anagram-test
(is (= (anagram ["meat" "mat" "team" "mate" "eat"])
#{#{"meat" "team" "mate"}}))
(is (= (anagram ["veer" "lake" "item" "kale" "mite" "ever"])
#{#{"veer" "ever"} #{"lake" "kale"} #{"mite" "item"}})))
(run-tests)
</code></pre>
Thu, 06 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-05-Just-Juxt-22/
https://porkostomus.gitlab.io/posts-output/2018-09-05-Just-Juxt-22/
Just Juxt #22: Euler's Totient Function (4clojure #75)
<p><img src="/img/euler.png" alt="Euler" /></p><blockquote><p>Two numbers are coprime if their greatest common divisor equals 1. Euler's totient function f(x) is defined as the number of positive integers less than x which are coprime to x. The special case f(1) equals 1. Write a function which calculates Euler's totient function. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn totient [n]
(let [gcd (fn [a b]
(let [[q r] ((juxt quot rem) b a)]
(if (zero? r) a (recur r a))))]
(if (= n 1) 1
(count (filter #(= 1 (gcd % n)) (range 1 n))))))
(deftest test-75
(is (= (totient 1) 1))
(is (= (totient 10) (count '(1 3 7 9)) 4))
(is (= (totient 40) 16))
(is (= (totient 99) 60)))
(run-tests)
</code></pre>
Wed, 05 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-04-Just-Juxt-21/
https://porkostomus.gitlab.io/posts-output/2018-09-04-Just-Juxt-21/
Just Juxt #21: Merge with a Function (4clojure #69)
<p><img src="/img/merge.jpg" alt="Merge" /></p><blockquote><p>Write a function which takes a function f and a variable number of maps. Your function should return a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) should be combined with the mapping in the result by calling (f val-in-result val-in-latter). </p></blockquote><p>Check out the <code>source</code> for <code>merge-with</code>:</p><pre><code>user=> (source merge-with)
(defn merge-with
"Returns a map that consists of the rest of the maps conj-ed onto
the first. If a key occurs in more than one map, the mapping(s)
from the latter (left-to-right) will be combined with the mapping in
the result by calling (f val-in-result val-in-latter)."
{:added "1.0"
:static true}
[f & maps]
(when (some identity maps)
(let [merge-entry (fn [m e]
(let [k (key e) v (val e)]
(if (contains? m k)
(assoc m k (f (get m k) v))
(assoc m k v))))
merge2 (fn [m1 m2]
(reduce1 merge-entry (or m1 {}) (seq m2)))]
(reduce1 merge2 maps))))
</code></pre><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn my-merge-with [f & maps]
(->> maps
(apply concat)
(group-by key)
(map (juxt key #(->> (map val (val %))
(reduce f))))
(into {})))
(deftest my-merge-with-test
(is (= (my-merge-with * {:a 2, :b 3, :c 4} {:a 2} {:b 2} {:c 5})
{:a 4, :b 6, :c 20}))
(is (= (my-merge-with - {1 10, 2 20} {1 3, 2 10, 3 15})
{1 7, 2 10, 3 15}))
(is (= (my-merge-with concat {:a [3], :b [6]} {:a [4 5], :c [8 9]} {:b [7]})
{:a [3 4 5], :b [6 7], :c [8 9]})))
(run-tests)
</code></pre>
Tue, 04 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-03-Just-Juxt-20/
https://porkostomus.gitlab.io/posts-output/2018-09-03-Just-Juxt-20/
Just Juxt #20: Prime Numbers (4clojure #67)
<p><img src="/img/prime.png" alt="Prime" /></p><blockquote><p>Write a function which returns the first x number of prime numbers. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn primes [n]
((comp (partial apply take) reverse list)
(remove (comp (partial apply some)
(juxt (partial partial (comp zero? rem))
(partial range 2)))
(iterate inc 2)) n))
(deftest primes-test
(is (= (primes 2) [2 3]))
(is (= (primes 5) [2 3 5 7 11]))
(is (= (last (primes 100)) 541)))
(run-tests)
</code></pre>
Mon, 03 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-02-Just-Juxt-19/
https://porkostomus.gitlab.io/posts-output/2018-09-02-Just-Juxt-19/
Just Juxt #19: Greatest Common Divisor (4clojure #66)
<p><img src="/img/gcd.jpg" alt="GCD" /></p><blockquote><p>Given two integers, write a function which returns the greatest common divisor. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn gcd [a b]
(let [[x y] (sort [a b])
[q r] ((juxt quot rem) y x)]
(if (zero? r) x (recur x r))))
(deftest test-66
(is (= (gcd 2 4) 2))
(is (= (gcd 10 5) 5))
(is (= (gcd 5 7) 1))
(is (= (gcd 1023 858) 33)))
(run-tests)
</code></pre>
Sun, 02 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-09-01-Just-Juxt-18/
https://porkostomus.gitlab.io/posts-output/2018-09-01-Just-Juxt-18/
Just Juxt #18: Black Box Testing (4clojure #65)
<p><img src="/img/box.jpg" alt="Black box" /></p><blockquote><p>Clojure has many sequence types, which act in subtly different ways. The core functions typically convert them into a uniform "sequence" type and work with them that way, but it can be important to understand the behavioral and performance differences so that you know which kind is appropriate for your application. </p></blockquote><blockquote><p>Write a function which takes a collection and returns one of <code>:map</code>, <code>:set</code>, <code>:list</code>, or <code>:vector</code> - describing the type of collection it was given. You won't be allowed to inspect their class or use the built-in predicates like <code>list?</code> - the point is to poke at them and understand their behavior. </p></blockquote><p>Here is the full list of functions that we can't use:</p><ul><li><code>class</code></li><li><code>type</code></li><li><code>Class</code></li><li><code>vector?</code></li><li><code>sequential?</code></li><li><code>list?</code></li><li><code>seq?</code></li><li><code>map?</code></li><li><code>set?</code></li><li><code>instance?</code></li><li><code>getClass</code></li></ul><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn black-box [c]
)
(deftest test-65
(is (= :map (black-box {:a 1, :b 2})))
(is (= :list (black-box (range (rand-int 20)))))
(is (= :set (black-box #{10 (rand-int 5)})))
(is (= :vector (black-box [1 2 3 4 5 6])))
(is (= [:map :set :vector :list] (map black-box [{} #{} [] ()]))))
(run-tests)
</code></pre><p>Luckily, there are a few friends still left to help us out:</p><pre><code>user=> (doc associative?)
-------------------------
clojure.core/associative?
([coll])
Returns true if coll implements Associative
</code></pre><p>Vectors and maps are associative:</p><pre><code class="klipse-cljs nohighlight">(associative? [1 2 3])
</code></pre><pre><code class="klipse-cljs nohighlight">(associative? {:a 1 :b 2})
</code></pre><p>But lists, sets and strings are not:</p><pre><code class="klipse-cljs nohighlight">(associative? '(1 2 3))
</code></pre><pre><code class="klipse-cljs nohighlight">(associative? #{:a :b :c})
</code></pre><pre><code class="klipse-cljs nohighlight">(associative? "fred")
</code></pre><pre><code>user=> (doc reversible?)
-------------------------
clojure.core/reversible?
([coll])
Returns true if coll implements Reversible
</code></pre><p>An empty vector is reversible:</p><pre><code class="klipse-cljs nohighlight">(reversible? [])
</code></pre><p>But an empty list is not:</p><pre><code class="klipse-cljs nohighlight">(reversible? '())
</code></pre><p>Sets and maps are not reversible:</p><pre><code class="klipse-cljs nohighlight">(reversible? {})
</code></pre><pre><code class="klipse-cljs nohighlight">(reversible? #{})
</code></pre><p>But sorted ones are:</p><pre><code class="klipse-cljs nohighlight">(reversible? (sorted-map))
</code></pre><pre><code class="klipse-cljs nohighlight">(reversible? (sorted-set))
</code></pre><pre><code>user=> (doc ifn?)
-------------------------
clojure.core/ifn?
([x])
Returns true if x implements IFn. Note that many data structures
(e.g. sets and maps) implement IFn
</code></pre><p>An anonymous function is a function as you'd expect:</p><pre><code class="klipse-cljs nohighlight">(ifn? #("my anonymous function"))
</code></pre><p>Is a vector a function?</p><pre><code class="klipse-cljs nohighlight">(ifn? [1 2 3])
</code></pre><p>Sure is, lets call it:</p><pre><code class="klipse-cljs nohighlight">([1 2 3] 0)
</code></pre><p>Maps and sets are also functions.</p><p>A number is definitely not a function:</p><pre><code class="klipse-cljs nohighlight">(ifn? 1)
</code></pre><p>But a symbol is:</p><pre><code class="klipse-cljs nohighlight">(ifn? 'foo)
</code></pre><p>And so is a keyword:</p><pre><code class="klipse-cljs nohighlight">(ifn? :foo)
</code></pre><h2 id="juxtification:">Juxtification:</h2><p>Using <code>juxt</code> with these functions returns a vector of properties by which to identify our culprit. Then we can make a simple matrix to look up what it is:</p><pre><code class="klipse-cljs nohighlight">(defn black-box [c]
(case ((juxt associative? reversible? ifn?) c)
[true true true ] :vector
[false false false] :list
[true false true ] :map
[false false true ] :set))
(run-tests)
</code></pre>
Sat, 01 Sep 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-31-Just-Juxt-17/
https://porkostomus.gitlab.io/posts-output/2018-08-31-Just-Juxt-17/
Just Juxt #17: Group a Sequence (4clojure #63)
<p><img src="/img/toons.jpg" alt="Toons" /></p><blockquote><p>Given a function f and a sequence s, write a function which returns a map. The keys should be the values of f applied to each item in s. The value at each key should be a vector of corresponding items in the order they appear in s. </p></blockquote><p><strong>...but without using <code>group-by</code>.</strong></p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn group-seq [f s]
)
(deftest test-63
(is (= (group-seq #(> % 5) #{1 3 6 8}) {false [1 3], true [6 8]}))
(is (= (group-seq #(apply / %) [[1 2] [2 4] [4 6] [3 6]]) {1/2 [[1 2] [2 4] [3 6]], 2/3 [[4 6]]}))
(is (= (group-seq count [[1] [1 2] [3] [1 2 3] [2 3]]) {1 [[1] [3]], 2 [[1 2] [2 3]], 3 [[1 2 3]]})))
(run-tests)
</code></pre><p>To better understand the <code>group-by</code> fn that we are re-implementing, let's look at its <code>source</code>, as well as some examples from <a href="https://clojuredocs.org/clojure.core/group-by">ClojureDocs</a>:</p><pre><code>user=> (source group-by)
(defn group-by
"Returns a map of the elements of coll keyed by the result of
f on each element. The value at each key will be a vector of the
corresponding elements, in the order they appeared in coll."
{:added "1.2"
:static true}
[f coll]
(persistent!
(reduce
(fn [ret x]
(let [k (f x)]
(assoc! ret k (conj (get ret k []) x))))
(transient {}) coll)))
</code></pre><p>We can group strings by their length:</p><pre><code class="klipse-cljs nohighlight">(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"])
</code></pre><p>Group integers by a predicate:</p><pre><code class="klipse-cljs nohighlight">(group-by odd? (range 10))
</code></pre><p>Group by a primary key:</p><pre><code class="klipse-cljs nohighlight">(group-by :user-id [{:user-id 1 :uri "/"}
{:user-id 2 :uri "/foo"}
{:user-id 1 :uri "/account"}])
</code></pre><p>Hey... how about if we use <code>juxt</code> to group by multiple criteria:</p><pre><code class="klipse-cljs nohighlight">(def words ["Air" "Bud" "Cup" "Awake" "Break" "Chunk" "Ant" "Big" "Check"])
(group-by (juxt first count) words)
</code></pre><p>Let's look at each of our unit tests with <code>group-by</code>:</p><pre><code class="klipse-cljs nohighlight">(group-by #(> % 5) #{1 3 6 8})
</code></pre><pre><code class="klipse-cljs nohighlight">(group-by #(apply / %) [[1 2] [2 4] [4 6] [3 6]])
</code></pre><pre><code class="klipse-cljs nohighlight">(group-by count [[1] [1 2] [3] [1 2 3] [2 3]])
</code></pre><h2 id="the_juxtification:">The juxtification:</h2><pre><code class="klipse-cljs nohighlight">(defn group-seq [f s]
(->> (map (juxt f identity) s)
(reduce (fn [m [k v]]
(assoc m k (conj (get m k []) v)))
{})))
(run-tests)
</code></pre><h2 id="breakdown:">Breakdown:</h2><pre><code class="klipse-cljs nohighlight">(->> (map (juxt #(> % 5) identity) #{1 3 6 8})
(reduce (fn [m [k v]]
(assoc m k (conj (get m k []) v)))
{}))
</code></pre><p>Take a look at each part:</p><pre><code class="klipse-cljs nohighlight">(map (juxt #(> % 5) identity) #{1 3 6 8})
</code></pre><pre><code class="klipse-cljs nohighlight">(reduce (fn [m [k v]]
(assoc m k (conj (get m k []) v)))
{} '([false 1] [false 3] [true 6] [true 8]))
</code></pre>
Fri, 31 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-30-Just-Juxt-16/
https://porkostomus.gitlab.io/posts-output/2018-08-30-Just-Juxt-16/
Just Juxt #16: Re-implement Iterate (4clojure #62)
<p><img src="/img/iterate.png" alt="Iterate" /></p><blockquote><p>Given a side-effect free function <code>f</code> and an initial value <code>x</code> write a function which returns an infinite lazy sequence of <code>x</code>, <code>(f x)</code>, <code>(f (f x))</code>, <code>(f (f (f x)))</code>, etc. </p></blockquote><p>As usual, here is a live testing framework set up for the problem with an appropriately named placeholder function. See below for first a common "normal" solution followed by the "juxtification".</p><p><strong>I think you're gonna like this one.</strong></p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn spaz-out [f x]
)
(deftest test-62
(is (= (take 5 (spaz-out #(* 2 %) 1)) [1 2 4 8 16]))
(is (= (take 100 (spaz-out inc 0)) (take 100 (range))))
(is (= (take 9 (spaz-out #(inc (mod % 3)) 1)) (take 9 (cycle [1 2 3])))))
(run-tests)
</code></pre><pre><code class="klipse-cljs nohighlight">(defn spaz-out [f x]
(cons x
(lazy-seq
(spaz-out f (f x)))))
(run-tests)
</code></pre><pre><code class="klipse-cljs nohighlight">(defn spaz-out [f x]
(tree-seq f (juxt f) x))
(run-tests)
</code></pre><h2 id="breakdown">Breakdown</h2><p>Part of the magic is in <code>tree-seq</code>, and its source is incredibly enlightening:</p><pre><code>user=> (source tree-seq)
(defn tree-seq
"Returns a lazy sequence of the nodes in a tree, via a depth-first walk.
branch? must be a fn of one arg that returns true if passed a node
that can have children (but may not). children must be a fn of one
arg that returns a sequence of the children. Will only be called on
nodes for which branch? returns true. Root is the root node of the
tree."
{:added "1.0"
:static true}
[branch? children root]
(let [walk (fn walk [node]
(lazy-seq
(cons node
(when (branch? node)
(mapcat walk (children node))))))]
(walk root)))
</code></pre><p>We can see how this is used in, for example the <code>flatten</code> fn:</p><pre><code>user=> (source flatten)
(defn flatten
"Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat sequence.
(flatten nil) returns an empty sequence."
{:added "1.2"
:static true}
[x]
(filter (complement sequential?)
(rest (tree-seq sequential? seq x))))
</code></pre><p>It's extremely worthwhile to spend some time digesting these. But we'll cover <code>flatten</code> when we get to that one.</p><p>Let's take the first test case and deconstruct it:</p><pre><code class="klipse-cljs nohighlight">(take 5 (spaz-out #(* 2 %) 1))
</code></pre><p>Begin by removing <code>(take 5</code> and see what happens. Just kidding.</p><p>So, we're <em>spazzing</em> out. Let's replace the call to <code>spaz-out</code> with its definition. What does it mean to <code>spaz-out</code>? First we can just restate it as an anonymous fn:</p><pre><code class="klipse-cljs nohighlight">(take 5
(#(tree-seq % (juxt %) %2)
#(* 2 %) 1))
</code></pre><p>Now slurp in the args:</p><pre><code class="klipse-cljs nohighlight">(take 5
(tree-seq #(* 2 %) (juxt #(* 2 %)) 1))
</code></pre><p>Remember, <code>tree-seq</code> takes 3 args: <code>branch?</code>, <code>children</code>, and <code>root</code>. <code>branch?</code> is a predicate, whose result determines whether or not we call <code>children</code>. The <code>root</code> is where we start.</p>
Thu, 30 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-29-Exercism-Armstrong-Numbers/
https://porkostomus.gitlab.io/posts-output/2018-08-29-Exercism-Armstrong-Numbers/
Exercism - Armstrong Numbers
<p><img src="/img/armstrong.jpg" alt="Armstrong" /></p><p>An <a href="https://en.wikipedia.org/wiki/Narcissistic_number">Armstrong number</a> is a number that is the sum of its own digits each raised to the power of the number of digits.</p><p>For example:</p><ul><li>9 is an Armstrong number, because 9 = 9<sup>1</sup> = 9</li><li>10 is not an Armstrong number, because 10 != 1<sup>2</sup> + 0<sup>2</sup> = 1</li><li>153 is an Armstrong number, because: 153 = 1<sup>3</sup> + 5<sup>3</sup> + 3<sup>3</sup> = 1 + 125 + 27 = 153</li><li>154 is not an Armstrong number, because: 154 != 1<sup>3</sup> + 5<sup>3</sup> + 4<sup>3</sup> = 1 + 125 + 64 = 190</li></ul><p>Write some code to determine whether a number is an Armstrong number.</p><pre><code class="klipse-cljs nohighlight">(ns armstrong-numbers
(:require [cljs.test :refer-macros [deftest testing is run-tests]]))
(defn armstrong? [n]
)
(deftest armstrong-number-5
(testing "Single digit numbers are Armstrong numbers"
(is (armstrong? 5))))
(deftest not-armstrong-number-10
(testing "There are no 2 digit Armstrong numbers"
(is (not (armstrong? 10)))))
(deftest armstrong-number-153
(testing "Three digit number that is an Armstrong number"
(is (armstrong? 153))))
(deftest not-armstrong-number-100
(testing "Three digit number that is not an Armstrong number"
(is (not (armstrong? 100)))))
(deftest armstrong-number-9474
(testing "Four digit number that is an Armstrong number"
(is (armstrong? 9474))))
(deftest not-armstrong-number-9475
(testing "Four digit number that is not an Armstrong number"
(is (not (armstrong? 9476)))))
(deftest armstrong-number-9926315
(testing "Seven digit number that is an Armstrong number"
(is (armstrong? 9926315))))
(deftest not-armstrong-number-9926314
(testing "Seven digit number that is not an Armstrong number"
(is (not (armstrong? 9926314)))))
(run-tests)
</code></pre><p>This was my first iteration.</p><p>Note: The code on this page is modified slightly for Clojurescript. <code>js/parseInt</code> is JavaScript interop and will not work in Clojure. Instead, use <code>Character/digit</code> or <code>Integer/parseInt</code>. Or better yet - see below for a way to do it with math.</p><pre><code class="klipse-cljs nohighlight">(defn digits [n]
(map #(js/parseInt (str %)) (seq (str n))))
(defn exp [x n]
(reduce * (repeat n x)))
(defn numdigits [n]
(count (digits n)))
(defn multiplier [n]
(map #(exp % (numdigits n)) (digits n)))
(defn adder [n]
(reduce + (multiplier n)))
(defn armstrong? [n]
(= (adder n) n))
(run-tests)
</code></pre><p>I tried to tackle the problem in multiple stages, defining functions that each get us one step closer to the solution. It worked, but my mentor encouraged me to try a more idiomatic approach. So I basically took the functions and squashed them together:</p><pre><code class="klipse-cljs nohighlight">(defn digits [n]
(map #(js/parseInt (str %))
(seq (str n))))
(defn armstrong [n]
(reduce + (map #(Math/pow % (count (digits n)))
(digits n))))
(defn armstrong? [n]
(== (armstrong n) n))
(run-tests)
</code></pre><p>Also by using Java's <code>Math/pow</code> I got to eliminate the exponent function. I decided to take this and run with it, however we still could do better:</p><pre><code class="klipse-cljs nohighlight">(defn armstrong? [n]
(let [digits (->> n str (map #(js/parseInt % 10)))]
(->> digits
(map #(Math/pow % (count digits)))
(apply +)
(== n))))
(run-tests)
</code></pre><p>The difference is mostly stylistic, but readability ought to be a strong priority. By using the threading macros, it is much easier to discern the order of operations.</p><p>Here's how to get the digits of a number without turning it into a string or using interop:</p><pre><code class="klipse-cljs nohighlight">(defn digits [n]
(if (> n 10)
(conj (digits (quot n 10))
(rem n 10))
[n]))
(digits 1234)
</code></pre>
Wed, 29 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-29-Just-Juxt-15/
https://porkostomus.gitlab.io/posts-output/2018-08-29-Just-Juxt-15/
Just Juxt #15: Sequence Reductions (4clojure #60)
<p><img src="/img/reductions.png" alt="Reductions" /></p><blockquote><p>Write a function which behaves like <code>reduce</code>, but returns each intermediate value of the reduction. Your function must accept either two or three arguments, and the return sequence must be lazy. </p></blockquote><p>...but without using <code>reductions</code>, of course.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn my-reductions
([f vals]
)
([f init vals]
))
(deftest my-reductions-test
(is (= (take 5 (my-reductions + (range))) [0 1 3 6 10]))
(is (= (my-reductions conj [1] [2 3 4]) [[1] [1 2] [1 2 3] [1 2 3 4]]))
(is (= (last (my-reductions * 2 [3 4 5])) (reduce * 2 [3 4 5]) 120)))
(run-tests)
</code></pre><p>Here's our <code>juxt</code> solution, courtesy of <a href="http://www.4clojure.com/user/nothsaevets">nothsaevets</a>:</p><pre><code class="klipse-cljs nohighlight">(defn my-reductions
([f vals]
(my-reductions f (first vals) (rest vals)))
([f init vals]
(cons init
((fn inner
[acc src]
(when (seq src)
(let [[head tail] ((juxt first rest) src)
result (f acc head)]
(cons result
(lazy-seq (inner result tail))))))
init vals))))
(run-tests)
</code></pre>
Wed, 29 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-29-Live-Cheat-Sheet-2/
https://porkostomus.gitlab.io/posts-output/2018-08-29-Live-Cheat-Sheet-2/
Live Clojure Cheat Sheet: Branching Functions
<p>We're continuing our interactive cheat sheet with Clojure's branching functions. The idea here is to provide basically a single example using each function, eschewing any explanations or attempt at being exhaustive. For a more comprehensive guide, use <a href="http://clojuredocs.org/">ClojureDocs</a>. </p><pre><code class="klipse-cljs nohighlight">(defn is-small? [number]
(if (< number 100) "yes" "no"))
(is-small? 50)
</code></pre><pre><code class="klipse-cljs nohighlight">(is-small? 500)
</code></pre><pre><code class="klipse-cljs nohighlight">(defn has-neg [coll]
(if-not (empty? coll) ;; = (if (not (empty? coll)) ...
(or (neg? (first coll)) (recur (rest coll)))))
(has-neg [])
</code></pre><pre><code class="klipse-cljs nohighlight">(has-neg [1 2 -3 4])
</code></pre><pre><code class="klipse-cljs nohighlight">(when (= 1 1) true)
</code></pre><pre><code class="klipse-cljs nohighlight">(when (not= 1 1) true)
</code></pre><pre><code class="klipse-cljs nohighlight">(map
#(when-not (= %2 %3) [%1 %2 %3])
(iterate inc 0) ; a lazy list of indecies
[:a :b :c]
[:a :a :a])
</code></pre><pre><code class="klipse-cljs nohighlight">(defn drop-one
[coll]
(when-let [s (seq coll)]
(rest s)))
(drop-one [1 2 3])
</code></pre><pre><code class="klipse-cljs nohighlight">(drop-one [])
</code></pre><pre><code class="klipse-cljs nohighlight">(when-first [a [1 2 3]] a)
</code></pre><pre><code class="klipse-cljs nohighlight">(when-first [a []] :x)
</code></pre><pre><code class="klipse-cljs nohighlight">(when-first [a nil] :x)
</code></pre><pre><code class="klipse-cljs nohighlight">(defn sum-even-numbers [nums]
(if-let [nums (seq (filter even? nums))]
(reduce + nums)
"No even numbers found."))
(sum-even-numbers [1 3 5 7 9])
</code></pre><pre><code class="klipse-cljs nohighlight">(sum-even-numbers [1 3 5 7 9 10 12])
</code></pre><pre><code class="klipse-cljs nohighlight">(defn pos-neg-or-zero
"Determines whether or not n is positive, negative, or zero"
[n]
(cond
(< n 0) "negative"
(> n 0) "positive"
:else "zero"))
(pos-neg-or-zero 5)
</code></pre><pre><code class="klipse-cljs nohighlight">(condp some [1 2 3 4]
#{0 6 7} :>> inc
#{4 5 9} :>> dec
#{1 2 3} :>> #(+ % 3))
</code></pre><pre><code class="klipse-cljs nohighlight">(let [mystr "hello"]
(case mystr
"" 0
"hello" (count mystr)))
</code></pre><pre><code class="klipse-cljs nohighlight">(when-some [x 1] [x :ok])
</code></pre><pre><code class="klipse-cljs nohighlight">(if-some [a 10] :true :false)
</code></pre><p>In the next post, we'll continue with the <em>comparison</em> functions.</p>
Wed, 29 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-29-Live-Cheat-Sheet/
https://porkostomus.gitlab.io/posts-output/2018-08-29-Live-Cheat-Sheet/
Live Clojure Cheat Sheet
<p>With all this crazy attention we've been giving to <code>juxt</code>, it seems wise to learn about the <em>other</em> Clojure functions too! This page is intended to be a convenient springboard for a colossal interactive documentation station that will be put together over time. Since it's running self-hosted Clojurescript, we'll be following <a href="http://cljs.info/cheatsheet/">this cheat sheet</a> with examples from our good friend <a href="http://clojuredocs.org/">ClojureDocs</a>. The killer is that it is <em>interactive</em>. My hope is that it will serve as an extremely handy place where we can find what we need and immediately try stuff out, and when we see it <em>actually</em> evaluate, paste it into our programs! Or at least, if nothing else, I might learn a couple things while doing this...</p><h2 id="basics">Basics</h2><h3 id="define">Define</h3><pre><code class="klipse-cljs nohighlight">(def my-val 5)
my-val
</code></pre><pre><code class="klipse-cljs nohighlight">(defn foo [a b c]
(* a b c))
(foo 1 2 3)
</code></pre><pre><code class="klipse-cljs nohighlight">(ns test)
(defn- foo []
"World!")
(defn bar []
(str "Hello " (foo)))
(foo)
</code></pre><pre><code class="klipse-cljs nohighlight">(bar)
</code></pre><pre><code class="klipse-cljs nohighlight">(ns playground)
(test/bar)
</code></pre><pre><code>(test/foo)
</code></pre><p>(This will not work because <code>foo</code> is <code>private</code>)</p><pre><code class="klipse-cljs nohighlight">(let [a 1 b 2]
(+ a b))
</code></pre><pre><code class="klipse-cljs nohighlight">(letfn [(twice [x]
(* x 2))
(six-times [y]
(* (twice y) 3))]
(println "Twice 15 =" (twice 15))
(println "Six times 15 =" (six-times 15)))
</code></pre><pre><code class="klipse-cljs nohighlight">(declare undefined-func)
(defn foo []
(undefined-func))
</code></pre><p>That takes care of the <strong>Define</strong> section. In the next post we'll continue with <strong>Branch</strong>.</p>
Wed, 29 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-28-Just-Juxt-14/
https://porkostomus.gitlab.io/posts-output/2018-08-28-Just-Juxt-14/
Just Juxt #14: Juxtaposition (4clojure #59)
<p><img src="/img/juxtapose.jpg" alt="Juxtapose" /></p><blockquote><p>Take a set of functions and return a new function that takes a variable number of arguments and returns a sequence containing the result of applying each function left-to-right to the argument list. </p></blockquote><p><strong>...but <em>without</em> using <code>juxt</code>!</strong></p><p>Here we are turning (just juxt) on its head, and faced with the task of implementing it ourselves!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn juxtapose [& f]
)
(deftest test-59
(is (= [21 6 1] ((juxtapose + max min) 2 3 5 1 6 4)))
(is (= ["HELLO" 5] ((juxtapose #(.toUpperCase %) count) "hello")))
(is (= [2 6 4] ((juxtapose :a :c :b) {:a 2, :b 4, :c 6, :d 8 :e 10}))))
(run-tests)
</code></pre><p>Here is a simple solution:</p><pre><code class="klipse-cljs nohighlight">(defn juxtapose [& f]
(fn [& a]
(map #(apply % a) f)))
(run-tests)
</code></pre>
Tue, 28 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-27-Exercism-Collatz/
https://porkostomus.gitlab.io/posts-output/2018-08-27-Exercism-Collatz/
Exercism - Collatz Conjecture
<p><img src="/img/collatz_conjecture.png" alt="Collatz" /></p><p>I've been having a lot of fun doing the Exercism Clojure Track, and since I recently completed all 11 core exercises, have become a mentor.</p><p>The following problem is interesting, because right now I'm going to attempt to mentor <em>my own mentor's</em> solution. It turns out that he took a very different approach than I did, and I think this could be a great opportunity to dive in and learn some stuff.</p><p>The Collatz Conjecture or 3x+1 problem can be summarized as follows:</p><blockquote><p>Take any positive integer n. If n is even, divide n by 2 to get n / 2. If n is odd, multiply n by 3 and add 1 to get 3n + 1. Repeat the process indefinitely. The conjecture states that no matter which number you start with, you will always reach 1 eventually. </p></blockquote><blockquote><p>Given a number n, return the number of steps required to reach 1. </p></blockquote><p>We begin with 2 placeholder functions and test suite. This code (and cljs.test framework) is live and interactive if you want to try it out.</p><pre><code class="klipse-cljs nohighlight">(ns collatz-conjecture
(:require [cljs.test :refer-macros [deftest testing is run-tests]]))
(defn collatz-step [num step]
)
(defn collatz [num]
)
(deftest steps-for-1
(testing "zero steps for one"
(is (= 0 (collatz 1)))))
(deftest steps-for-16
(testing "divide if even"
(is (= 4 (collatz 16)))))
(deftest steps-for-12
(testing "even and odd steps"
(is (= 9 (collatz 12)))))
(deftest steps-for-1000000
(testing "Large number of even and odd steps"
(is (= 152 (collatz 1000000)))))
(run-tests)
</code></pre><p>This was my answer:</p><pre><code class="klipse-cljs nohighlight">(defn collatz-step [num step]
(cond
(= num 1) step
(even? num) (collatz-step (/ num 2) (inc step))
(odd? num) (collatz-step (inc (* num 3)) (inc step))))
(defn collatz [num]
(collatz-step num 0))
(run-tests)
</code></pre><p>The program works fine, all of the tests pass. I think it's actually rather clever the way it counts each time it calls itself.</p><p>However, I have obscured the whole intent of having a <code>step</code> function, which should only be doing one thing:</p><ul><li>Generating the next step of the Collatz sequence given an existing element.</li></ul><p>Then we would apply the function repeatedly until we reach one, and then count how many we've got.</p><p>If we take a look at my mentor's solution, we can see that these issues have been addressed and the concerns have been made explicit, producing a much more readable program:</p><pre><code class="klipse-cljs nohighlight">(defn- collatz-step [num]
(if (even? num) (/ num 2)
(inc (* 3 num))))
(defn collatz [num]
{:pre [(pos? num)]}
(->> (iterate collatz-step num)
(take-while (partial < 1))
count))
(run-tests)
</code></pre>
Mon, 27 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-27-Just-Juxt-13/
https://porkostomus.gitlab.io/posts-output/2018-08-27-Just-Juxt-13/
Just Juxt #13: Find Distinct Items (4clojure #56)
<p><img src="/img/calvin.jpeg" alt="Calvin" /></p><blockquote><p>Write a function which removes the duplicates from a sequence. Order of the items must be maintained. </p></blockquote><p>And not so fast... we're not allowed to use <code>distinct</code>! Here we take the concept of restricted functions to the next level: Solution <strong>must</strong> use <code>juxt</code>!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn deduper [s]
)
(deftest deduper-test
(is (= (deduper [1 2 1 3 1 2 4]) [1 2 3 4]))
(is (= (deduper [:a :a :b :b :c :c]) [:a :b :c]))
(is (= (deduper '([2 4] [1 2] [1 3] [1 3])) '([2 4] [1 2] [1 3])))
(is (= (deduper (range 50)) (range 50))))
(run-tests)
</code></pre><h2 id="answer:">Answer:</h2><pre><code class="klipse-cljs nohighlight">(defn deduper [coll]
(->> coll
(map-indexed vector)
(group-by second)
(map (juxt first (comp ffirst second)))
(sort-by second)
(map first)))
(run-tests)
</code></pre><h2 id="breakdown:">Breakdown:</h2><pre><code class="klipse-cljs nohighlight">(->> [1 2 1 3 1 2 4]
(map-indexed vector)
(group-by second)
(map (juxt first (comp ffirst second)))
(sort-by second)
(map first))
</code></pre><pre><code class="klipse-cljs nohighlight">(map-indexed vector [1 2 1 3 1 2 4])
</code></pre><pre><code class="klipse-cljs nohighlight">(group-by second '([0 1] [1 2] [2 1] [3 3] [4 1] [5 2] [6 4]))
</code></pre><p>Some magic right here:</p><pre><code class="klipse-cljs nohighlight">(map (juxt first (comp ffirst second)) {1 [[0 1] [2 1] [4 1]], 2 [[1 2] [5 2]], 3 [[3 3]], 4 [[6 4]]})
</code></pre><p>Then we sort them and take the first digits. This particular collection happens to be already sorted:</p><pre><code class="klipse-cljs nohighlight">(map first '([1 0] [2 1] [3 3] [4 6]))
</code></pre>
Mon, 27 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-26-Just-Juxt-12/
https://porkostomus.gitlab.io/posts-output/2018-08-26-Just-Juxt-12/
Just Juxt #12: Count Occurrences (4clojure #55)
<p><img src="/img/frequencies.jpg" alt="Frequencies" /></p><blockquote><p>Write a function which returns a map containing the number of occurrences of each distinct item in a sequence. </p></blockquote><p><strong>...but <em>without</em> using <code>frequencies</code>!</strong></p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn freqs [s]
)
(deftest freqs-test
(is (= (freqs [1 1 2 3 2 1 1]) {1 4, 2 2, 3 1}))
(is (= (freqs [:b :a :b :a :b]) {:a 2, :b 3}))
(is (= (freqs '([1 2] [1 3] [1 3])) {[1 2] 1, [1 3] 2})))
(run-tests)
</code></pre><p>Here is the source for the <code>frequencies</code> function:</p><pre><code>user=> (source frequencies)
(defn frequencies
"Returns a map from distinct items in coll
to the number of times they appear."
{:added "1.2"
:static true}
[coll]
(persistent!
(reduce (fn [counts x]
(assoc! counts x (inc (get counts x 0))))
(transient {}) coll)))
</code></pre><p>Here's the <code>juxt</code>ification:</p><pre><code class="klipse-cljs nohighlight">(defn freqs [s]
(into {}
(map (juxt first count)
(partition-by identity (sort s)))))
(run-tests)
</code></pre><p>This is a pattern that we haven't yet seen - using <code>juxt</code> to return a function and <code>map</code>ing it.</p><p>Let's break this down:</p><pre><code class="klipse-cljs nohighlight">(sort [1 1 2 3 2 1 1])
</code></pre><pre><code class="klipse-cljs nohighlight">(partition-by identity '(1 1 1 1 2 2 3))
</code></pre><p>Now for the fun part, the 2 functions passed to <code>juxt</code>. However, we're not calling it on the collection this time - instead we're <code>map</code>ing it:</p><pre><code class="klipse-cljs nohighlight">(first '(1 1 1 1))
</code></pre><pre><code class="klipse-cljs nohighlight">(count '(1 1 1 1))
</code></pre><pre><code class="klipse-cljs nohighlight">(first '(2 2))
</code></pre><pre><code class="klipse-cljs nohighlight">(count '(2 2))
</code></pre><pre><code class="klipse-cljs nohighlight">(first '(3))
</code></pre><pre><code class="klipse-cljs nohighlight">(count '(3))
</code></pre><p>Which gives us:</p><pre><code class="klipse-cljs nohighlight">(map (juxt first count)
'((1 1 1 1) (2 2) (3)))
</code></pre><p>Now all that's left to do is throw it <code>into</code> a <code>map</code>!</p><pre><code class="klipse-cljs nohighlight">(into {} '([1 4] [2 2] [3 1]))
</code></pre><p>I hope you enjoyed today's <code>juxt</code>, and possibly learned something. I know I sure did ;)</p>
Sun, 26 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-25-Just-Juxt-11/
https://porkostomus.gitlab.io/posts-output/2018-08-25-Just-Juxt-11/
Just Juxt #11: Partition a Sequence (4clojure #54)
<p><img src="/img/partition.jpg" alt="Partitions" /></p><blockquote><p>Write a function which returns a sequence of lists of x items each. Lists of less than x items should not be returned. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn partition-seq [n s]
)
(deftest partition-seq-test
(is (= (partition-seq 3 (range 9)) '((0 1 2) (3 4 5) (6 7 8))))
(is (= (partition-seq 2 (range 8)) '((0 1) (2 3) (4 5) (6 7))))
(is (= (partition-seq 3 (range 8)) '((0 1 2) (3 4 5)))))
(run-tests)
</code></pre><p>This problem is holding up a big sign that says:</p><blockquote><p>"Hey! The <code>partition</code> function is totally awesome, you should check out how it works!" </p></blockquote><p>So here's how it works:</p><pre><code>user=> (source partition)
(defn partition
"Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items."
{:added "1.0"
:static true}
([n coll]
(partition n n coll))
([n step coll]
(lazy-seq
(when-let [s (seq coll)]
(let [p (doall (take n s))]
(when (= n (count p))
(cons p (partition n step (nthrest s step))))))))
([n step pad coll]
(lazy-seq
(when-let [s (seq coll)]
(let [p (doall (take n s))]
(if (= n (count p))
(cons p (partition n step pad (nthrest s step)))
(list (take n (concat p pad)))))))))
</code></pre><p>Learning from these concepts, we could create a solution like this:</p><pre><code class="klipse-cljs nohighlight">(defn partition-seq [n coll]
(loop [c coll partitioned []]
(if (< (count c) n)
partitioned
(recur (drop n c) (conj partitioned (take n c))))))
(run-tests)
</code></pre><p>But here's a way to do it with <code>juxt</code>:</p><pre><code class="klipse-cljs nohighlight">(defn partition-seq [n coll]
(let [[a b] ((juxt take drop) n coll)]
(if (= (count a) n)
(cons a (partition-seq n b)))))
(run-tests)
</code></pre><p>Inside our let binding is a destructuring form, which pulls apart the items (plugging in the first test case) and creates local bindings for them named <code>a</code> and <code>b</code>:</p><pre><code class="klipse-cljs nohighlight">((juxt take drop) 3 (range 9))
</code></pre>
Sat, 25 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-24-Just-Juxt-10/
https://porkostomus.gitlab.io/posts-output/2018-08-24-Just-Juxt-10/
Just Juxt #10: Longest Increasing Sub-Seq (4clojure #53)
<p><img src="/img/inc.jpg" alt="Increasing size" /></p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn longest-increasing-subseq [s]
(->> s
(partition 2 1)
(partition-by #(apply - %))
(filter (fn [[[x y]]] (= (- y x) 1)))
(sort-by count)
last
((juxt #(map first (butlast %)) last))
(apply concat)))
(deftest longest-increasing-subseq-test
(is (= (longest-increasing-subseq [1 0 1 2 3 0 4 5]) [0 1 2 3]))
(is (= (longest-increasing-subseq [5 6 1 3 2 7]) [5 6]))
(is (= (longest-increasing-subseq [2 3 3 4 5]) [3 4 5]))
(is (= (longest-increasing-subseq [7 6 5 4]) [])))
(run-tests)
</code></pre><pre><code class="klipse-cljs nohighlight">(->> [1 0 1 2 3 0 4 5]
(partition 2 1)
(partition-by #(apply - %))
(filter (fn [[[x y]]] (= (- y x) 1)))
(sort-by count)
last
((juxt #(map first (butlast %)) last))
(apply concat))
</code></pre><p>Here it is step by step:</p><pre><code class="klipse-cljs nohighlight">(partition 2 1 [1 0 1 2 3 0 4 5])
</code></pre><pre><code class="klipse-cljs nohighlight">(partition-by #(apply - %)
'((1 0) (0 1) (1 2) (2 3) (3 0) (0 4) (4 5)))
</code></pre><pre><code class="klipse-cljs nohighlight">(filter (fn [[[x y]]] (= (- y x) 1))
'(((1 0)) ((0 1) (1 2) (2 3)) ((3 0)) ((0 4)) ((4 5))))
</code></pre><pre><code class="klipse-cljs nohighlight">(sort-by count '(((0 1) (1 2) (2 3)) ((4 5))))
</code></pre><pre><code class="klipse-cljs nohighlight">(last '(((4 5)) ((0 1) (1 2) (2 3))))
</code></pre><pre><code class="klipse-cljs nohighlight">((juxt #(map first (butlast %)) last) '((0 1) (1 2) (2 3)))
</code></pre><pre><code class="klipse-cljs nohighlight">(apply concat ['(0 1) '(2 3)])
</code></pre><p>Here's what's being <code>juxt</code>ed:</p><pre><code class="klipse-cljs nohighlight">(map first (butlast '((0 1) (1 2) (2 3))))
</code></pre><pre><code class="klipse-cljs nohighlight">(last '((0 1) (1 2) (2 3)))
</code></pre>
Fri, 24 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-23-Just-Juxt-9/
https://porkostomus.gitlab.io/posts-output/2018-08-23-Just-Juxt-9/
Just Juxt #9: Split by type (4clojure #50)
<p><img src="/img/fruit.jpg" alt="Fruit" /></p><blockquote><p>Write a function which takes a sequence consisting of items with different types and splits them up into a set of homogeneous sub-sequences. The internal order of each sub-sequence should be maintained, but the sub-sequences themselves can be returned in any order (this is why 'set' is used in the test cases). </p></blockquote><p>Here's an interactive testing area if you want to try solving it:</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn split-by-type [s]
)
(deftest split-by-type-test
(is (= (set (split-by-type [1 :a 2 :b 3 :c])) #{[1 2 3] [:a :b :c]}))
(is (= (set (split-by-type [:a "foo" "bar" :b])) #{[:a :b] ["foo" "bar"]}))
(is (= (set (split-by-type [[1 2] :a [3 4] 5 6 :b])) #{[[1 2] [3 4]] [:a :b] [5 6]})))
(run-tests)
</code></pre><p>Here's a common way:</p><pre><code class="klipse-cljs nohighlight">(defn split-by-type [s]
(vals (group-by type s)))
(run-tests)
</code></pre><p>And here it is with <code>juxt</code>:</p><pre><code class="klipse-cljs nohighlight">(defn split-by-type [s]
((comp vals (partial group-by (juxt keyword? vector?))) s))
(run-tests)
</code></pre>
Thu, 23 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-22-Just-Juxt-8/
https://porkostomus.gitlab.io/posts-output/2018-08-22-Just-Juxt-8/
Just Juxt #8: Split a sequence (4clojure #49)
<p><img src="/img/chop.jpg" alt="Guy splitting log" /></p><blockquote><p>Write a function which will split a sequence into two parts. </p></blockquote><p>...<strong>but <em>without</em> using <code>split-at</code></strong>.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn chop [n coll]
)
(deftest test-49
(is (= (chop 3 [1 2 3 4 5 6]) [[1 2 3] [4 5 6]]))
(is (= (chop 1 [:a :b :c :d]) [[:a] [:b :c :d]]))
(is (= (chop 2 [[1 2] [3 4] [5 6]]) [[[1 2] [3 4]] [[5 6]]])))
(run-tests)
</code></pre><p>These kinds of problems are interesting, and my first inclination is to "cheat" by looking up the source for <code>split-at</code>:</p><pre><code>user=> (source split-at)
(defn split-at
"Returns a vector of [(take n coll) (drop n coll)]"
{:added "1.0"
:static true}
[n coll]
[(take n coll) (drop n coll)])
</code></pre><p>There we have it, the "official" implementation. A function that returns a vector containing the result of calling <code>take</code> and <code>drop</code> on a <code>coll</code>. Sound familiar?</p><pre><code class="klipse-cljs nohighlight">(defn chop [n coll]
((juxt take drop) n coll))
(run-tests)
</code></pre><p>This one is very straightforward. Breaking it down:</p><pre><code class="klipse-cljs nohighlight">(take 3 [1 2 3 4 5 6])
</code></pre><pre><code class="klipse-cljs nohighlight">(drop 3 [1 2 3 4 5 6])
</code></pre><pre><code class="klipse-cljs nohighlight">((juxt take drop) 3 [1 2 3 4 5 6])
</code></pre>
Wed, 22 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-21-Just-Juxt-7/
https://porkostomus.gitlab.io/posts-output/2018-08-21-Just-Juxt-7/
Just Juxt #7: Flipping Out (4clojure #46)
<p><img src="/img/flip.jpg/" alt="Guy flipping pancakes" /></p><blockquote><p>Write a higher-order function which flips the order of the arguments of an input function. </p></blockquote><p>Here's a live testing area for you to play with. See if you can solve it with <code>juxt</code>. Then check out the answer below!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn flipper [f]
)
(deftest test-46
(is (= 3 ((flipper nth) 2 [1 2 3 4 5])))
(is (= true ((flipper >) 7 8)))
(is (= 4 ((flipper quot) 2 8)))
(is (= [1 2 3] ((flipper take) [1 2 3 4 5] 3))))
(run-tests)
</code></pre><p>First, a common answer:</p><pre><code class="klipse-cljs nohighlight">(defn flipper [f]
#(f %2 %))
(run-tests)
</code></pre><p>Ok... Now I'm actually wondering if we're being trolled by <a href="http://www.4clojure.com/user/maximental">maximental</a>:</p><pre><code class="klipse-cljs nohighlight">(defn flipper [f]
((partial partial
(comp (partial apply apply)
(juxt first
(comp (juxt second first)
rest))
list)) f))
(run-tests)
</code></pre><p>It's a <code>juxt</code> <em>within</em> a <code>juxt</code>!</p><p>Run... they're multiplying!</p>
Tue, 21 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-20-Just-Juxt-6/
https://porkostomus.gitlab.io/posts-output/2018-08-20-Just-Juxt-6/
Just Juxt #6: Rotate a Sequence (4clojure #44)
<p><img src="/img/shipswheel.gif" alt="Ship wheel" /></p><blockquote><p>Write a function which can rotate a sequence in either direction. </p></blockquote><p>This problem is particularly significant, because it's the one that inspired this blog on the most recent <a href="https://www.youtube.com/watch?v=LZDRobkxnWA">Apropos</a> show!</p><p>Here's a live testing area for you to play with. See if you can solve it with <code>juxt</code>. Then check out the answer below!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn rotate [n s]
)
(deftest test-44
(is (= (rotate 2 [1 2 3 4 5]) '(3 4 5 1 2)))
(is (= (rotate -2 [1 2 3 4 5]) '(4 5 1 2 3)))
(is (= (rotate 6 [1 2 3 4 5]) '(2 3 4 5 1)))
(is (= (rotate 1 '(:a :b :c)) '(:b :c :a)))
(is (= (rotate -4 '(:a :b :c)) '(:c :a :b))))
(run-tests)
</code></pre><p>First, a common answer:</p><pre><code class="klipse-cljs nohighlight">(defn rotate [n s]
(take (count s) (drop (mod n (count s)) (cycle s))))
(run-tests)
</code></pre><p>Now the <code>juxt</code>-ification - solution courtesy of <a href="https://hypirion.com/">hypirion</a>:</p><pre><code class="klipse-cljs nohighlight">(defn rotate [n s]
(apply concat ((juxt drop take) (mod n (count s)) s)))
(run-tests)
</code></pre><p>Here we are <code>juxt</code>-ing with <code>drop</code> and <code>take</code>. Let's plug in our first test case:</p><pre><code class="klipse-cljs nohighlight">(apply concat ((juxt drop take) (mod 2 (count [1 2 3 4 5])) [1 2 3 4 5]))
</code></pre><p>Here's just the call to <code>drop</code>:</p><pre><code class="klipse-cljs nohighlight">(drop (mod 2 (count [1 2 3 4 5])) [1 2 3 4 5])
</code></pre><p>And to <code>take</code>:</p><pre><code class="klipse-cljs nohighlight">(take (mod 2 (count [1 2 3 4 5])) [1 2 3 4 5])
</code></pre><p>Which results in this vector when <code>juxt</code>ed:</p><pre><code class="klipse-cljs nohighlight">((juxt drop take) (mod 2 (count [1 2 3 4 5])) [1 2 3 4 5])
</code></pre><p>And then we stick them together:</p><pre><code class="klipse-cljs nohighlight">(apply concat ['(3 4 5) '(1 2)])
</code></pre><p>I hope you enjoyed today's <code>juxt</code>. See you tomorrow!</p>
Mon, 20 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-19-Just-Juxt-5/
https://porkostomus.gitlab.io/posts-output/2018-08-19-Just-Juxt-5/
Just Juxt #5: Replicate a Sequence (4clojure #33)
<p><img src="/img/Calvin_the_Frog.gif" alt="Calvin the frog" /></p><blockquote><p>Write a function which replicates each element of a sequence a variable number of times. </p></blockquote><p>Here's a live testing area for you to play with. See if you can solve it with <code>juxt</code>. Then check out the answer below!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn replicate [s n]
)
(deftest replicate-test
(is (= (replicate [1 2 3] 2) '(1 1 2 2 3 3)))
(is (= (replicate [:a :b] 4) '(:a :a :a :a :b :b :b :b)))
(is (= (replicate [4 5 6] 1) '(4 5 6)))
(is (= (replicate [[1 2] [3 4]] 2) '([1 2] [1 2] [3 4] [3 4])))
(is (= (replicate [44 33] 2) [44 44 33 33])))
(run-tests)
</code></pre><p>Here's the most common solution:</p><pre><code class="klipse-cljs nohighlight">(defn replicate [s n]
(mapcat (partial repeat n) s))
(run-tests)
</code></pre><p>And here's the <code>juxt</code>-ification:</p><pre><code class="klipse-cljs nohighlight">(defn replicate [s n]
(mapcat (apply juxt (repeat n identity)) s))
(run-tests)
</code></pre><p>To get a closer look, let's plug in the args from our first test case:</p><pre><code class="klipse-cljs nohighlight">(mapcat (apply juxt (repeat 2 identity)) [1 2 3])
</code></pre><p>This example is deceptively more clever than the ones we've done so far, because we are using <code>apply juxt</code>. Try to wrap your head around that for a second. We're applying a fn, which takes a set of fns, and applies that.</p><p>This can be better understood in the context of yesterday's example, to duplicate a seq:</p><pre><code class="klipse-cljs nohighlight">(mapcat (juxt identity identity) [1 2 3])
</code></pre><p>What we are doing now is using <code>repeat</code> to determine <em>how many</em> <code>identity</code>s are passed to <code>juxt</code>. Here it is with 3:</p><pre><code class="klipse-cljs nohighlight">(mapcat (juxt identity identity identity) [1 2 3])
</code></pre><p>Which is equivalent to:</p><pre><code class="klipse-cljs nohighlight">(mapcat (apply juxt (repeat 3 identity)) [1 2 3])
</code></pre><p>The reason we need to use <code>apply</code> is that <code>repeat</code> returns a seq, but <code>juxt</code> is asking for functions.</p><p>I think it's great how these problems build upon each other. <em>Duplication</em> is a special case of <em>replication</em>.</p><p>Tune in tomorrow and we'll see what other dials we can add to our <em>transmogrifier</em>. Until then, I hope your day becomes <code>juxt</code>ed with many wonderful things!</p>
Sun, 19 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-18-Just-Juxt-4/
https://porkostomus.gitlab.io/posts-output/2018-08-18-Just-Juxt-4/
Just Juxt #4: Duplicate a Sequence (4clojure #32)
<p><img src="/img/dupe.jpg" alt="Dupe a seq with juxt" /></p><blockquote><p>Write a function which duplicates each element of a sequence. </p></blockquote><p>Here's a live testing area for you to play with. See if you can solve it with <code>juxt</code>. Then check out the answer below!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn dupseq [s]
)
(deftest test-32
(is (= (dupseq [1 2 3]) '(1 1 2 2 3 3)))
(is (= (dupseq [:a :a :b :b]) '(:a :a :a :a :b :b :b :b)))
(is (= (dupseq [[1 2] [3 4]]) '([1 2] [1 2] [3 4] [3 4])))
(is (= (dupseq [44 33]) [44 44 33 33])))
(run-tests)
</code></pre><p>Here's the most common solution:</p><pre><code class="klipse-cljs nohighlight">(defn dupseq [s]
(interleave s s))
(run-tests)
</code></pre><p>Recall the docstring for <code>interleave</code>:</p><pre><code>user=> (doc interleave)
-------------------------
clojure.core/interleave
([] [c1] [c1 c2] [c1 c2 & colls])
Returns a lazy seq of the first item in each coll, then the second etc.
</code></pre><p>It's a fine solution, but I could argue that the intent behind <code>interleaving</code> a seq with itself is un-<code>juxt</code>-ified. Ha ha. But seriously... what if we (or the client) were to change our minds, and instead want to duplicate the seq but with some sort of transformation on the repeat. Not so far fetched... </p><p><strong>We would have to rewrite the function!!</strong></p><p>What if we could write it in such a way that we could more clearly adjust our <em>transmogrifier</em> settings:</p><p>Well... it turns out there is a way!! Here's the <code>juxt</code>-ification:</p><pre><code class="klipse-cljs nohighlight">(defn dupseq [s]
(mapcat (juxt identity identity) s))
(run-tests)
</code></pre><p>That's better! Now let's say we wanted to duplicate a list of numbers but increment the second group. We can easily change the second function passed to <code>juxt</code>:</p><pre><code class="klipse-cljs nohighlight">(defn dupe-inc [s]
(mapcat (juxt identity inc) s))
(dupe-inc '(1 1 2 2 3 3))
</code></pre><p>Pretty cool, huh? I would say that's a much more useful function!</p>
Sat, 18 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-17-Just-Juxt-3/
https://porkostomus.gitlab.io/posts-output/2018-08-17-Just-Juxt-3/
Just Juxt #3: Pack a Sequence (4clojure #31)
<p><img src="/img/pack.jpg" alt="Pack a seq with juxt" /> </p><blockquote><p>Write a function which packs consecutive duplicates into sub-lists. </p></blockquote><p>Here's a live testing area for you to play with. See if you can solve it with <code>juxt</code>. Then check out the answer below!</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn pack [s]
)
(deftest test-31
(is (= (pack [1 1 2 1 1 1 3 3]) '((1 1) (2) (1 1 1) (3 3))))
(is (= (pack [:a :a :b :b :c]) '((:a :a) (:b :b) (:c))))
(is (= (pack [[1 2] [1 2] [3 4]]) '(([1 2] [1 2]) ([3 4])))))
(run-tests)
</code></pre><p>Here's how to do it:</p><pre><code class="klipse-cljs nohighlight">(defn pack [[a & z :as s]]
(when a
(let [[p q] ((juxt take-while drop-while)
#(= a %) s)]
(cons p (pack q)))))
</code></pre><p>We will now follow our established pattern of dismantling the fn to see how it works at each step. First by just showing how <a href="https://clojure.org/guides/destructuring">destructuring</a> works in Clojure:</p><pre><code class="klipse-cljs nohighlight">(let [[a & z :as s]
[1 1 2 1 1 1 3 3]]
s)
</code></pre><p>This binds our seq to a local variable <code>s</code>, and labels the first item <code>a</code> and the rest of the coll <code>z</code>:</p><pre><code class="klipse-cljs nohighlight">(let [[a & z :as s]
[1 1 2 1 1 1 3 3]]
a)
</code></pre><pre><code class="klipse-cljs nohighlight">(let [[a & z :as s] [1 1 2 1 1 1 3 3]]
z)
</code></pre><p>This destructuring pattern is simply a way to call <code>first</code> and <code>rest</code> on our seq and give them all extremely concise names, <code>a</code>, <code>z</code>, and <code>s</code>.</p><p>Take a look at the meat of the solution, the <code>juxt</code>. It is used to create one of the <code>let</code> bindings:</p><pre><code class="klipse-cljs nohighlight">((juxt take-while drop-while) #(= 1 %) [1 1 2 1 1 1 3 3])
</code></pre><p>What's with the double parens? It looks kinda weird, no?</p><p>The reason is that <code>juxt</code> returns a <code>fn</code>. Recall its docstring:</p><pre><code>user=> (doc juxt)
-------------------------
clojure.core/juxt
([f] [f g] [f g h] [f g h & fs])
Takes a set of functions and returns a fn that is the juxtaposition
of those fns. The returned fn takes a variable number of args, and
returns a vector containing the result of applying each fn to the
args (left-to-right).
((juxt a b c) x) => [(a x) (b x) (c x)]
((juxt a b c) x) => [(a x) (b x) (c x)]
</code></pre><p>The <code>juxt</code> returned our vector, <code>[(1 1) (2 1 1 1 3 3)]</code>, containing a list with the first 2 dupes of our seq, followed by a list of the remaining items.</p><p>The trick is in our predicate fn, <code>#(= a %)</code>, which is passed to <code>take-while</code> and <code>drop-while</code> via <code>juxt</code>.</p><p>Now for the next operation:</p><pre><code class="klipse-cljs nohighlight">(cons '(1 1) (pack '(2 1 1 1 3 3)))
</code></pre><p>By way of <code>(when a</code> we are recursively ripping off the chunks of consecutive dupes and <code>pack</code>-ing them into a list! What a <code>juxt</code>-tastic endeavor!</p><p>Here we have seen <code>juxt</code> used in a new way, that is, to define a <code>let</code> binding to use destructuring. That's awesome!</p><p>And we'll have another party tomorrow! See you later.</p>
Fri, 17 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-16-Just-Juxt-2/
https://porkostomus.gitlab.io/posts-output/2018-08-16-Just-Juxt-2/
Just Juxt #2: Palindrome Detector (4clojure #27)
<h2 id="4clojure_27_-_palindrome_detector">4clojure 27 - Palindrome Detector</h2><p><img src="/img/PALINDROMES.png" alt="Palindrome" /></p><p>Write a function which returns <code>true</code> if the given sequence is a palindrome.</p><p>Hint: <code>"racecar"</code> does not equal <code>'(\r \a \c \e \c \a \r)</code>.</p><h3 id="unit_tests">Unit tests</h3><p>We'll start by setting up a placeholder function and our test suite in a <a href="https://github.com/viebel/klipse">KLIPSE</a> snippet. This code is live and editable, so go ahead and fill it in to make the tests pass. Or not... Not trying to tell you what to do or anything...</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn palindrome? [s]
)
(deftest test-27
(is (false? (palindrome? '(1 2 3 4 5))))
(is (true? (palindrome? "racecar")))
(is (true? (palindrome? [:foo :bar :foo])))
(is (true? (palindrome? '(1 1 3 3 1 1))))
(is (false? (palindrome? '(:a :b :c)))))
(run-tests)
</code></pre><p>First off, here's the standard, <em>boring</em> way to do it:</p><pre><code class="klipse-cljs nohighlight">(#(= (seq %) (reverse %)) '(1 2 3 4 5))
</code></pre><pre><code class="klipse-cljs nohighlight">(#(= (seq %) (reverse %)) '(1 2 3 2 1))
</code></pre><p>But friends don't let friends pass up a <code>juxt</code>-ortunity...</p><p>Are you ready for this?</p><p>Remember, <code>juxt</code> is our <em>universal vector constructor</em>. So, what do we want in our vector?</p><p>Let's back up a tiny bit - were it not for that pesky string (<code>"racecar"</code>), we would only have to compare a sequence with its reverse:</p><pre><code class="klipse-cljs nohighlight">(defn palindrome? [s]
(= s (reverse s)))
(run-tests)
</code></pre><p>You see, the string gets turned into a sequence of characters when <code>reverse</code> is called on it:</p><pre><code class="klipse-cljs nohighlight">(reverse "racecar")
</code></pre><p>So to perform a proper comparison we need to call <code>seq</code> on the forward version too.</p><blockquote><p><em>That's</em> why this is a perfect <code>juxt</code>-ortunity!<br /></p></blockquote><blockquote><p>Any time we need to produce a vector of items each processed by separate functions, we could be thinking <code>juxt</code>. When this use-case is understood, the function will become a potentially formidable item in our utility-belt. It seems evident to us, as <code>juxt</code>-ers, that encouraging its establishment as an idiomatic Clojure design pattern will lead to code that more clearly demonstrates our intentions. That's what language expressivity is all about, and I believe it's one of Clojure's biggest strengths. And indeed, modeling the problem as <em>a vector of items processed by different functions</em> seems entirely fitting in this case: </p></blockquote><pre><code class="klipse-cljs nohighlight">(seq "racecar")
</code></pre><pre><code class="klipse-cljs nohighlight">(reverse "racecar")
</code></pre><p>Here we go, time to <code>juxt</code> it up:</p><pre><code class="klipse-cljs nohighlight">((juxt seq reverse) "racecar")
</code></pre><p>Isn't it beautiful?</p><p>From here we can easily compare them with <code>(apply =)</code>:</p><pre><code class="klipse-cljs nohighlight">(defn palindrome? [s]
(apply = ((juxt seq reverse) s)))
(run-tests)
</code></pre><p>Now <em>that's</em> what I call <em>love at first <code>juxt</code></em>. See you all tomorrow for more!</p>
Thu, 16 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-16-Exercism-Say/
https://porkostomus.gitlab.io/posts-output/2018-08-16-Exercism-Say/
Exercism - Say
<blockquote><p>Given a number from <code>0</code> to <code>999,999,999,999</code>, spell out that number in English. </p></blockquote><p>Source: A variation on JavaRanch CattleDrive, <a href="http://www.javaranch.com/say.jsp">exercise 4a</a>.</p><p>There is already a function called <code>cl-format</code> from Common Lisp that has an implementation in the <code>pprint</code> library:</p><pre><code class="klipse-cljs nohighlight">(ns say
(:require [cljs.test :refer-macros [deftest is run-tests]]
[cljs.pprint :refer [cl-format]]))
(cl-format nil "~R" 123456789012345678901234567890)
</code></pre><p>We can check its <a href="https://github.com/clojure/clojurescript/blob/r1.10.339-24-g0773689e/src/main/cljs/cljs/pprint.cljs">source</a> and see how it works.</p><p>Obviously the program needs a representation of the english number spellings. We can use a vector for that:</p><pre><code class="klipse-cljs nohighlight">(def english-cardinal-units
["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"
"ten" "eleven" "twelve" "thirteen" "fourteen"
"fifteen" "sixteen" "seventeen" "eighteen" "nineteen"])
</code></pre><p>And then we can extract a value at a given index:</p><pre><code class="klipse-cljs nohighlight">(english-cardinal-units 1)
</code></pre><p>Now for the tens:</p><pre><code class="klipse-cljs nohighlight">(def english-cardinal-tens
["" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety"])
</code></pre><p>And then we're gonna need the scale numbers:</p><pre><code class="klipse-cljs nohighlight">(def english-scale-numbers
["" "thousand" "million" "billion" "trillion" "quadrillion" "quintillion"
"sextillion" "septillion" "octillion" "nonillion" "decillion"
"undecillion" "duodecillion" "tredecillion" "quattuordecillion"
"quindecillion" "sexdecillion" "septendecillion"
"octodecillion" "novemdecillion" "vigintillion"])
(defn add-english-scales
"Take a sequence of parts, add scale numbers (e.g., million) and combine into a string
offset is a factor of 10^3 to multiply by"
[parts offset]
(let [cnt (count parts)]
(loop [acc []
pos (dec cnt)
this (first parts)
remainder (next parts)]
(if (nil? remainder)
(str (apply str (interpose " " acc))
(if (and (not (empty? this)) (not (empty? acc))) " ")
this
(if (and (not (empty? this)) (pos? (+ pos offset)))
(str " " (nth english-scale-numbers (+ pos offset)))))
(recur
(if (empty? this)
acc
(conj acc (str this " " (nth english-scale-numbers (+ pos offset)))))
(dec pos)
(first remainder)
(next remainder))))))
(defn format-simple-cardinal
"Convert a number less than 1000 to a cardinal english string"
[num]
(let [hundreds (quot num 100)
tens (rem num 100)]
(str
(if (pos? hundreds) (str (nth english-cardinal-units hundreds) " hundred"))
(if (and (pos? hundreds) (pos? tens)) " ")
(if (pos? tens)
(if (< tens 20)
(nth english-cardinal-units tens)
(let [ten-digit (quot tens 10)
unit-digit (rem tens 10)]
(str
(if (pos? ten-digit) (nth english-cardinal-tens ten-digit))
(if (and (pos? ten-digit) (pos? unit-digit)) "-")
(if (pos? unit-digit) (nth english-cardinal-units unit-digit)))))))))
(defn- consume [func initial-context]
(loop [context initial-context
acc []]
(let [[result new-context] (apply func [context])]
(if (not result)
[acc new-context]
(recur new-context (conj acc result))))))
(defn remainders
"Return the list of remainders (essentially the 'digits') of val in the given base"
[base val]
(reverse
(first
(consume #(if (pos? %)
[(rem % base) (quot % base)]
[nil nil])
val))))
(defn number [n]
(if (= 0 n)
"zero"
(let [abs-arg (if (neg? n) (- n) n)
parts (remainders 1000 abs-arg)]
(let [parts-strs (map format-simple-cardinal parts)
full-str (add-english-scales parts-strs 0)]
(str (if (neg? n) "minus ") full-str)))))
</code></pre><h2 id="test_suite">Test suite</h2><pre><code class="klipse-cljs nohighlight">(deftest zero-test
(is (= "zero" (say/number 0))))
(deftest one-test
(is (= "one" (say/number 1))))
(deftest fourteen-test
(is (= "fourteen" (say/number 14))))
(deftest twenty-test
(is (= "twenty" (say/number 20))))
(deftest twenty-two-test
(is (= "twenty-two" (say/number 22))))
(deftest one-hundred-test
(is (= "one hundred" (say/number 100))))
(deftest one-hundred-twenty-three-test
(is (= "one hundred twenty-three" (say/number 123))))
(deftest one-thousand-test
(is (= "one thousand" (say/number 1000))))
(deftest one-thousand-two-hundred-thirty-four-test
(is (= "one thousand two hundred thirty-four" (say/number 1234))))
(deftest one-million-test
(is (= "one million" (say/number 1000000))))
(deftest one-million-two-thousand-three-hundred-forty-five-test
(is (= "one million two thousand three hundred forty-five" (say/number 1002345))))
(deftest one-billion-test
(is (= "one billion" (say/number 1000000000))))
(deftest a-big-number-test
(is (= "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three" (say/number 987654321123))))
(run-tests)
</code></pre>
Thu, 16 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-15-Just-Juxt/
https://porkostomus.gitlab.io/posts-output/2018-08-15-Just-Juxt/
Just Juxt #1: Fibonacci Sequence (4clojure #26)
<p>Welcome to <strong>just juxt</strong>! Where it's all <code>juxt</code>, all the time!</p><p>We might as well introduce the <code>juxt</code> function with its own source:</p><pre><code>Clojure 1.9.0
user=> (source juxt)
(defn juxt
"Takes a set of functions and returns a fn that is the juxtaposition
of those fns. The returned fn takes a variable number of args, and
returns a vector containing the result of applying each fn to the
args (left-to-right).
((juxt a b c) x) => [(a x) (b x) (c x)]"
{:added "1.1"
:static true}
([f]
(fn
([] [(f)])
([x] [(f x)])
([x y] [(f x y)])
([x y z] [(f x y z)])
([x y z & args] [(apply f x y z args)])))
([f g]
(fn
([] [(f) (g)])
([x] [(f x) (g x)])
([x y] [(f x y) (g x y)])
([x y z] [(f x y z) (g x y z)])
([x y z & args] [(apply f x y z args) (apply g x y z args)])))
([f g h]
(fn
([] [(f) (g) (h)])
([x] [(f x) (g x) (h x)])
([x y] [(f x y) (g x y) (h x y)])
([x y z] [(f x y z) (g x y z) (h x y z)])
([x y z & args] [(apply f x y z args) (apply g x y z args) (apply h x y z args)])))
([f g h & fs]
(let [fs (list* f g h fs)]
(fn
([] (reduce1 #(conj %1 (%2)) [] fs))
([x] (reduce1 #(conj %1 (%2 x)) [] fs))
([x y] (reduce1 #(conj %1 (%2 x y)) [] fs))
([x y z] (reduce1 #(conj %1 (%2 x y z)) [] fs))
([x y z & args] (reduce1 #(conj %1 (apply %2 x y z args)) [] fs))))))
nil
user=>
</code></pre><p>To build our dataset we will use Mike Fikes' <a href="https://github.com/mfikes/coal-mine">coal-mine</a>, a collection of submissions from the top 1000 users on <a href="http://www.4clojure.com/">4clojure</a>. A <code>grep</code> yielded over 300 occurrences of <code>juxt</code>. The very first of which is found in a solution to problem #26:</p><h2 id="the_good_ol'_<a href='http://www.4clojure.com/problem/26'>Fibonacci Sequence</a>!">The good ol' <a href="http://www.4clojure.com/problem/26">Fibonacci Sequence</a>!</h2><blockquote><p>Write a function which returns the first <code>x</code> fibonacci numbers. </p></blockquote><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn fib [x]
(->> [1 1]
(iterate
(juxt last
(partial apply +)))
(take x)
(map first)))
(deftest test-26
(is (= (fib 3) '(1 1 2)))
(is (= (fib 6) '(1 1 2 3 5 8)))
(is (= (fib 8) '(1 1 2 3 5 8 13 21))))
(run-tests)
</code></pre><p>And there we have it, our first canonical use of <code>juxt</code>!</p><p>Now that we see it passes the tests, let's get our hands dirty and get a better feel for what <code>juxt</code> is doing. We'll simply hack our function into pieces to get a closer look. (BTW the code on this page is interactive so go ahead and smack it around ;)</p><pre><code class="klipse-cljs nohighlight">(->> [1 1]
(iterate
(juxt last
(partial apply +)))
(take 12)
(map first))
</code></pre><p>Here it is macroexpanded:</p><pre><code class="klipse-cljs nohighlight">(map first (take 12 (iterate (juxt last (partial apply +)) [1 1])))
</code></pre><p>Remove <code>(map first)</code> to see what it does:</p><pre><code class="klipse-cljs nohighlight">(take 12 (iterate (juxt last (partial apply +)) [1 1]))
</code></pre><p>We could also write it using an anonymous function instead of using <code>partial</code> (yay even moar shorter!):</p><pre><code class="klipse-cljs nohighlight">(take 12 (iterate (juxt last #(apply + %)) [1 1]))
</code></pre><p>As we can see, <code>juxt</code> is acting as our trusty vector-pair generator. The two functions it takes, <code>last</code> and <code>#(apply + %)</code> are used to populate them. Each iteration produces:</p><ol><li>The <code>last</code> (second) digit; and</li><li>The sum of the 2 digits.</li></ol><p>That's a <code>fib</code>.</p><p>But that ain't no fib, folks. See y'all tomorrow for another issue of <code>(just juxt!)</code>!</p>
Wed, 15 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-14-Exercism-Anagram/
https://porkostomus.gitlab.io/posts-output/2018-08-14-Exercism-Anagram/
Exercism - Anagram
<p>Given a word and a list of possible anagrams, select the correct sublist.</p><p>Given <code>"listen"</code> and a list of candidates like <code>"enlists" "google" "inlets" "banana"</code> the program should return a list containing <code>"inlets"</code>.</p><p>Inspired by the <a href="https://github.com/rchatley/extreme_startup">Extreme Startup</a> game.</p><pre><code class="klipse-cljs nohighlight">(ns anagram
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.string :as str]))
;; I already have this from another project:
(defn scramble?
"Returns true if letters of string b are contained in string a."
[a b]
(every? #(>= (if (contains? (frequencies a) %)
(get (frequencies a) %)
0)
(get (frequencies b) %)) (keys (frequencies b))))
;; However, it currently does too much for this case,
;; because it tests whether a partial anagram exists.
;; Let's go with it for now and wire it up:
(defn anagrams-for [word prospect-list] ;; <- arglist goes here
(filter #(scramble? word %) prospect-list))
(deftest no-matches
(is (= []
(anagram/anagrams-for "diaper" ["hello" "world" "zombies" "pants"]))))
(deftest detect-simple-anagram
(is (= ["tan"] (anagram/anagrams-for "ant" ["tan" "stand" "at"]))))
(deftest does-not-confuse-different-duplicates
(is (= [] (anagram/anagrams-for "galea" ["eagle"]))))
(deftest eliminate-anagram-subsets
(is (= [] (anagram/anagrams-for "good" ["dog" "goody"]))))
(deftest detect-anagram
(is (= ["inlets"]
(let [coll ["enlists" "google" "inlets" "banana"]]
(anagram/anagrams-for "listen" coll)))))
(deftest multiple-anagrams
(is (= ["gallery" "regally" "largely"]
(let [coll ["gallery" "ballerina" "regally"
"clergy" "largely" "leading"]]
(anagram/anagrams-for "allergy" coll)))))
(deftest case-insensitive-anagrams
(is (= ["Carthorse"]
(let [coll ["cashregister" "Carthorse" "radishes"]]
(anagram/anagrams-for "Orchestra" coll)))))
(deftest word-is-not-own-anagram
(is (= [] (anagram/anagrams-for "banana" ["banana"]))))
(deftest capital-word-is-not-own-anagram
(is (= [] (anagram/anagrams-for "BANANA" ["banana"]))))
(run-tests)
</code></pre><p>As we can see, we are partially there already. We just need to catch the case of a word not being its own anagram, and not allow for partial words. It also must be case-insensitive, and must be the same length.</p><p>Let's make a new predicate function:</p><pre><code class="klipse-cljs nohighlight">(defn anagram? [word prospect]
(and (not= (str/lower-case word) (str/lower-case prospect))
(= (count word) (count prospect))
(every? #(= (if (contains? (frequencies (str/lower-case word)) %)
(get (frequencies (str/lower-case word)) %)
0)
(get (frequencies (str/lower-case prospect)) %))
(keys (frequencies (str/lower-case prospect))))))
</code></pre><p>Now we'll redefine <code>anagrams-for</code> to use that, and run our tests again:</p><pre><code class="klipse-cljs nohighlight">(defn anagrams-for [word prospect-list] ;; <- arglist goes here
(filter #(anagram? word %) prospect-list))
(run-tests)
</code></pre><h2 id="the_" cleanup95phase:_="cleanup95phase:_">The "cleanup phase":</h2><p>It works! But... we can't submit a solution looking like <em>that</em>. They'll say something like,</p><blockquote><p>It passes the tests, but I feel that it could be more readable/idiomatic... </p></blockquote><p>So we'll anticipate that and clean it up. For one thing, we can eliminate repeating <code>(str/lower-case)</code> by moving it to the second function:</p><pre><code class="klipse-cljs nohighlight">(defn anagram? [word prospect]
(and (not= word prospect)
(= (count word) (count prospect))
(every? #(= (if (contains? (frequencies word) %)
(get (frequencies word) %)
0)
(get (frequencies prospect) %))
(keys (frequencies prospect)))))
(defn anagrams-for [word prospect-list] ;; <- arglist goes here
(filter #(anagram? (str/lower-case word) (str/lower-case %)) prospect-list))
(run-tests)
</code></pre><p>Finally, we can define some let bindings to remove the repetition.</p><pre><code class="klipse-cljs nohighlight">(defn anagram? [word prospect]
(let [word-letters (frequencies word)
prospect-letters (frequencies prospect)]
(and (not= word prospect)
(= (count word) (count prospect))
(every? #(= (if (contains? word-letters %)
(get word-letters %)
0)
(get prospect-letters %))
(keys prospect-letters)))))
(defn anagrams-for [word prospect-list]
(filter #(anagram? (str/lower-case word)
(str/lower-case %))
prospect-list))
(run-tests)
</code></pre><p>Looks good to me! View my <a href="https://exercism.io/my/solutions/95687560b5384591935bbb84af80c864">solution</a> on Exercism. A friendly mentor will be commenting on it shortly!</p><h2 id="results">Results</h2><p>As it turns out, the solution can be made much simpler by forgetting about the whole <code>frequencies</code> business and just sorting the words alphabetically:</p><pre><code class="klipse-cljs nohighlight">(defn anagram? [word prospect]
(and (not= word prospect)
(= (sort word) (sort prospect))))
(defn anagrams-for [word prospect-list]
(filter #(anagram? (str/lower-case word)
(str/lower-case %))
prospect-list))
(run-tests)
</code></pre><p>And the solution was approved! See you in the next post.</p>
Tue, 14 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-11/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-11/
Advent of Code 2015 Day 11 - Corporate Policy
<p>Santa's previous password expired, and he needs help choosing a new one.</p><p>To help him remember his new password after the old one expires, Santa has devised a method of coming up with a password based on the previous one. Corporate policy dictates that passwords must be exactly eight lowercase letters (for security reasons), so he finds his new password by <strong>incrementing</strong> his old password string repeatedly until it is valid.</p><p>Incrementing is just like counting with numbers: <code>xx</code>, <code>xy</code>, <code>xz</code>, <code>ya</code>, <code>yb</code>, and so on. Increase the rightmost letter one step; if it was <code>z</code>, it wraps around to <code>a</code>, and repeat with the next letter to the left until one doesn't wrap around.</p><p>Unfortunately for Santa, a new Security-Elf recently started, and he has imposed some additional password requirements:</p><ul><li>Passwords must include one increasing straight of at least three letters, like <code>abc</code>, <code>bcd</code>, <code>cde</code>, and so on, up to <code>xyz</code>. They cannot skip letters; <code>abd</code> doesn't count.</li><li>Passwords may not contain the letters <code>i</code>, <code>o</code>, or <code>l</code>, as these letters can be mistaken for other characters and are therefore confusing.</li><li>Passwords must contain at least two different, non-overlapping pairs of letters, like <code>aa</code>, <code>bb</code>, or <code>zz</code>.</li></ul><p>For example:</p><ul><li><code>hijklmmn</code> meets the first requirement (because it contains the straight <code>hij</code>) but fails the second requirement requirement (because it contains <code>i</code> and <code>l</code>).</li><li><code>abbceffg</code> meets the third requirement (because it repeats <code>bb</code> and <code>ff</code>) but fails the first requirement.</li><li><code>abbcegjk</code> fails the third requirement, because it only has one double letter (<code>bb</code>).</li><li>The next password after <code>abcdefgh</code> is <code>abcdffaa</code>.</li><li>The next password after <code>ghijklmn</code> is <code>ghjaabcc</code>, because you eventually skip all the passwords that start with <code>ghi...</code>, since <code>i</code> is not allowed.</li></ul><p>Given Santa's current password (your puzzle input), what should his <strong>next password</strong> be?</p><pre><code class="klipse-cljs nohighlight">(ns day11
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.set :as set]
[clojure.string :as str]))
</code></pre><h2 id="part_two">Part Two</h2><p>Santa's password expired again. What's the next one?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-23/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-23/
Advent of Code 2015 Day 23 - Opening the Turing Lock
<p>Little Jane Marie just got her very first computer for Christmas from some unknown benefactor. It comes with instructions and an example program, but the computer itself seems to be malfunctioning. She's curious what the program does, and would like you to help her run it.</p><p>The manual explains that the computer supports two <a href="https://en.wikipedia.org/wiki/Processor_register">registers</a> and six <a href="https://en.wikipedia.org/wiki/Instruction_set">instructions</a> (truly, it goes on to remind the reader, a state-of-the-art technology). The registers are named <code>a</code> and <code>b</code>, can hold any <a href="https://en.wikipedia.org/wiki/Natural_number">non-negative integer</a>, and begin with a value of <code>0</code>. The instructions are as follows:</p><ul><li><code>hlf r</code> sets register <code>r</code> to <strong>half</strong> its current value, then continues with the next instruction.</li><li><code>tpl r</code> sets register <code>r</code> to <strong>triple</strong> its current value, then continues with the next instruction.</li><li><code>inc r</code> <strong>increments</strong> register <code>r</code>, adding <code>1</code> to it, then continues with the next instruction.</li><li><code>jmp offset</code> is a <strong>jump</strong>; it continues with the instruction <code>offset</code> away <strong>relative to itself</strong>.</li><li><code>jie r, offset</code> is like <code>jmp</code>, but only jumps if register <code>r</code> is <strong>even</strong> ("jump if even").</li><li><code>jio r, offset</code> is like <code>jmp</code>, but only jumps if register <code>r</code> is <code>1</code> ("jump if <strong>one</strong>", not odd).</li></ul><p>All three jump instructions work with an <strong>offset</strong> relative to that instruction. The offset is always written with a prefix <code>+</code> or <code>-</code> to indicate the direction of the jump (forward or backward, respectively). For example, <code>jmp +1</code> would simply continue with the next instruction, while <code>jmp +0</code> would continuously jump back to itself forever.</p><p>The program exits when it tries to run an instruction beyond the ones defined.</p><p>For example, this program sets <code>a</code> to <code>2</code>, because the <code>jio</code> instruction causes it to skip the <code>tpl</code> instruction:</p><pre><code>inc a
jio a, +2
tpl a
inc a</code></pre><p>What is <strong>the value in register <code>b</code></strong> when the program in your puzzle input is finished executing?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>The unknown benefactor is <strong>very</strong> thankful for releasi— er, helping little Jane Marie with her computer. Definitely not to distract you, what is the value in register <code>b</code> after the program is finished executing if register <code>a</code> starts as <code>1</code> instead?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-04/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-04/
Advent of Code 2015 Day 4 - The Ideal Stocking Stuffer
<p>Santa needs help <a href="https://en.wikipedia.org/wiki/Bitcoin#Mining">mining</a> some AdventCoins (very similar to <a href="https://en.wikipedia.org/wiki/Bitcoin">bitcoins</a>) to use as gifts for all the economically forward-thinking little girls and boys.</p><p>To do this, he needs to find <a href="https://en.wikipedia.org/wiki/MD5">MD5</a> hashes which, in <a href="https://en.wikipedia.org/wiki/Hexadecimal">hexadecimal</a>, start with at least <strong>five zeroes</strong>. The input to the MD5 hash is some secret key (your puzzle input, given below) followed by a number in decimal. To mine AdventCoins, you must find Santa the lowest positive number (no leading zeroes: <code>1</code>, <code>2</code>, <code>3</code>, ...) that produces such a hash.</p><p>For example:</p><ul><li>If your secret key is <code>abcdef</code>, the answer is <code>609043</code>, because the MD5 hash of <code>abcdef609043</code> starts with five zeroes (<code>000001dbbfa...</code>), and it is the lowest such number to do so.</li><li>If your secret key is <code>pqrstuv</code>, the lowest number it combines with to make an MD5 hash starting with five zeroes is <code>1048970</code>; that is, the MD5 hash of <code>pqrstuv1048970</code> looks like <code>000006136ef...</code>.</li></ul><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Now find one that starts with <strong>six zeroes</strong>.</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-152/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-152/
4clojure 152 - Latin Square Slicing
<p>A <a href="http://en.wikipedia.org/wiki/Latin_square">Latin square</a> of order <code>n</code> is an <code>n</code> x <code>n</code> array that contains <code>n</code> different elements, each occurring exactly once in each row, and exactly once in each column. For example, among the following arrays only the first one forms a Latin square:</p><pre><code>A B C A B C A B C
B C A B C A B D A
C A B C A C C A B
</code></pre><p>Let <code>V</code> be a vector of such vectors<sup>1</sup> that they may differ in length<sup>2</sup>. We will say that an arrangement of vectors of <code>V</code> in consecutive rows is an <em>alignment (of vectors)</em> of <code>V</code> if the following conditions are satisfied:</p><ul><li>All vectors of V are used.</li><li>Each row contains just one vector.</li><li>The order of V is preserved.</li><li>All vectors of maximal length are horizontally aligned each other.</li><li>If a vector is not of maximal length then all its elements are aligned with elements of some <a href="http://clojuredocs.org/clojure_core/clojure.core/subvec">subvector</a> of a vector of maximal length.</li></ul><p>Let <code>L</code> denote a Latin square of order <code>2</code> or greater. We will say that <code>L</code> is <em>included</em> in <code>V</code> or that <code>V</code> <em>includes</em> <code>L</code> iff there exists an alignment of <code>V</code> such that contains a subsquare that is equal to <code>L</code>. For example, if <code>V</code> equals <code>[[1 2 3][2 3 1 2 1][3 1 2]]</code> then there are nine alignments of <code>V</code> (brackets omitted):</p><pre><code> 1 2 3
1 2 3 1 2 3 1 2 3
A 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
1 2 3 1 2 3 1 2 3
B 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
1 2 3 1 2 3 1 2 3
C 2 3 1 2 1 2 3 1 2 1 2 3 1 2 1
3 1 2 3 1 2 3 1 2
</code></pre><p>Alignment <code>A1</code> contains Latin square <code>[[1 2 3][2 3 1][3 1 2]]</code>, alignments <code>A2</code>, <code>A3</code>, <code>B1</code>, <code>B2</code>, <code>B3</code> contain no Latin squares, and alignments <code>C1</code>, <code>C2</code>, <code>C3</code> contain <code>[[2 1][1 2]]</code>. Thus in this case <code>V</code> includes one Latin square of order <code>3</code> and one of order <code>2</code> which is included three times. Our aim is to implement a function which accepts a vector of vectors <code>V</code> as an argument, and returns a map which keys and values are integers. Each key should be the order of a Latin square included in <code>V</code>, and its value a count of <em>different</em> Latin squares of that order included in <code>V</code>. If <code>V</code> does not include any Latin squares an empty map should be returned. In the previous example the correct output of such a function is <code>{3 1, 2 1}</code> and <em>not</em> <code>{3 1, 2 3}</code>.</p><p><sup>1</sup>Of course, we can consider sequences instead of vectors. <sup>2</sup>Length of a vector is the number of elements in the vector.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn squares [vecs]
(let [max-count (apply max (map count vecs))
positions #(range (inc (- max-count (count %))))
alignments (fn [v] (map #(concat
(repeat % nil)
v
(repeat (- max-count (count v) %) nil))
(positions v)))
cartesian-product (fn f [colls]
(if (empty? colls)
'(())
(for [x (first colls)
more (f (rest colls))]
(cons x more))))
all-planes (cartesian-product (map alignments vecs))
transpose #(apply map vector %)
get-slices-of (fn [n plane]
(map #(take n (drop % plane))
(range (inc (- (count plane) n)))))
get-squares-of (fn [n plane]
(map transpose (mapcat (comp (partial get-slices-of n) transpose)
(get-slices-of n plane))))
candidate-sizes (range 2 (inc (min (count vecs) max-count)))
all-candidates (mapcat (fn [n] (mapcat (partial get-squares-of n) all-planes))
candidate-sizes)
is-latin? (fn [square]
(and (every? (partial apply distinct?) square)
(every? (partial apply distinct?) (transpose square))
(= (count square) (count (set (flatten square))))
(not (contains? (set (flatten square)) nil))))]
(frequencies (map count (distinct (filter is-latin? all-candidates))))))
(deftest squares-test
(is (= (squares '[[A B C D]
[A C D B]
[B A D C]
[D C A B]])
{}))
(is (= (squares '[[A B C D E F]
[B C D E F A]
[C D E F A B]
[D E F A B C]
[E F A B C D]
[F A B C D E]])
{6 1}))
(is (= (squares '[[A B C D]
[B A D C]
[D C B A]
[C D A B]])
{4 1, 2 4}))
(is (= (squares '[[B D A C B]
[D A B C A]
[A B C A B]
[B C A B C]
[A D B C A]])
{3 3}))
(is (= (squares [ [2 4 6 3]
[3 4 6 2]
[6 2 4] ])
{}))
(is (= (squares [[1]
[1 2 1 2]
[2 1 2 1]
[1 2 1 2]
[] ])
{2 2}))
(is (= (squares [[3 1 2]
[1 2 3 1 3 4]
[2 3 1 3] ])
{3 1, 2 2}))
(is (= (squares [[8 6 7 3 2 5 1 4]
[6 8 3 7]
[7 3 8 6]
[3 7 6 8 1 4 5 2]
[1 8 5 2 4]
[8 1 2 4 5]])
{4 1, 3 1, 2 7})))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Project-Euler-2/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Project-Euler-2/
Project Euler 2 - Even Fibonacci numbers
<p>Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:</p><pre><code>1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
</code></pre><p>By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.</p><pre><code class="klipse-cljs nohighlight">(ns euler002
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(def fibo (lazy-cat [0 1] (map + fibo (rest fibo))))
(defn euler-002 [n]
(->> fibo
(filter even?)
(take-while #(< % n))
(reduce +)))
(euler-002 4000000)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-12/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-12/
Advent of Code 2015 Day 12 - JSAbacusFramework.io
<p>Santa's Accounting-Elves need help balancing the books after a recent order. Unfortunately, their accounting software uses a peculiar storage format. That's where you come in.</p><p>They have a <a href="http://json.org/">JSON</a> document which contains a variety of things: arrays (<code>[1,2,3]</code>), objects (<code>{"a":1, "b":2}</code>), numbers, and strings. Your first job is to simply find all of the numbers throughout the document and add them together.</p><p>For example:</p><ul><li><code>[1,2,3]</code> and <code>{"a":2,"b":4}</code> both have a sum of <code>6</code>.</li><li><code>[[[3]]]</code> and <code>{"a":{"b":4},"c":-1}</code> both have a sum of <code>3</code>.</li><li><code>{"a":[-1,1]}</code> and <code>[-1,{"a":1}]</code> both have a sum of <code>0</code>.</li><li><code>[]</code> and <code>{}</code> both have a sum of <code>0</code>.</li></ul><p>You will not encounter any strings containing numbers.</p><p>What is the <strong>sum of all numbers</strong> in the document?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Uh oh – the Accounting-Elves have realized that they double-counted everything <strong>red</strong>.</p><p>Ignore any object (and all of its children) which has any property with the value <code>"red"</code>. Do this only for objects (<code>{...}</code>), not arrays (<code>[...]</code>).</p><ul><li><code>[1,2,3]</code> still has a sum of <code>6</code>.</li><li><code>[1,{"c":"red","b":2},3]</code> now has a sum of <code>4</code>, because the middle object is ignored.</li><li><code>{"d":"red","e":[1,2,3,4],"f":5}</code> now has a sum of <code>0</code>, because the entire structure is ignored.</li><li><code>[1,"red",5]</code> has a sum of <code>6</code>, because <code>"red"</code> in an array has no effect.</li></ul><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-05/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-05/
Advent of Code 2015 Day 5 - Doesn't He Have Intern-Elves For This?
<p>Santa needs help figuring out which strings in his text file are naughty or nice.</p><p>A <strong>nice string</strong> is one with all of the following properties:</p><ul><li>It contains at least three vowels (<code>aeiou</code> only), like <code>aei</code>, <code>xazegov</code>, or <code>aeiouaeiouaeiou</code>.</li><li>It contains at least one letter that appears twice in a row, like <code>xx</code>, <code>abcdde</code> (<code>dd</code>), or <code>aabbccdd</code> (<code>aa</code>, <code>bb</code>, <code>cc</code>, or <code>dd</code>).</li><li>It does <strong>not</strong> contain the strings <code>ab</code>, <code>cd</code>, <code>pq</code>, or <code>xy</code>, even if they are part of one of the other requirements.</li></ul><p>For example:</p><ul><li><code>ugknbfddgicrmopn</code> is nice because it has at least three vowels (<code>u...i...o...</code>), a double letter (<code>...dd...</code>), and none of the disallowed substrings.</li><li><code>aaa</code> is nice because it has at least three vowels and a double letter, even though the letters used by different rules overlap.</li><li><code>jchzalrnumimnmhp</code> is naughty because it has no double letter.</li><li><code>haegwjzuvuyypxyu</code> is naughty because it contains the string <code>xy</code>.</li><li><code>dvszwmarrgswjxmb</code> is naughty because it contains only one vowel.</li></ul><p>How many strings are nice?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Realizing the error of his ways, Santa has switched to a better model of determining whether a string is naughty or nice. None of the old rules apply, as they are all clearly ridiculous.</p><p>Now, a nice string is one with all of the following properties:</p><ul><li>It contains a pair of any two letters that appears at least twice in the string without overlapping, like <code>xyxy</code> (<code>xy</code>) or <code>aabcdefgaa</code> (<code>aa</code>), but not like <code>aaa</code> (<code>aa</code>, but it overlaps).</li><li>It contains at least one letter which repeats with exactly one letter between them, like <code>xyx</code>, <code>abcdefeghi</code> (<code>efe</code>), or even <code>aaa</code>.</li></ul><p>For example:</p><ul><li><code>qjhvhtzxzqqjkmpb</code> is nice because is has a pair that appears twice (<code>qj</code>) and a letter that repeats with exactly one letter between them (<code>zxz</code>).</li><li><code>xxyxx</code> is nice because it has a pair that appears twice and a letter that repeats with one between, even though the letters used by each rule overlap.</li><li><code>uurcxstgmygtbstg</code> is naughty because it has a pair (<code>tg</code>) but no repeat with a single letter between them.</li><li><code>ieodomkazucvgmuy</code> is naughty because it has a repeating letter with one between (<code>odo</code>), but no pair that appears twice.</li></ul><p>How many strings are nice under these new rules?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-168/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-168/
4clojure 168 - Infinite Matrix
<p>In what follows, <code>m</code>, <code>n</code>, <code>s</code>, <code>t</code> denote nonnegative integers, <code>f</code> denotes a function that accepts two arguments and is defined for all nonnegative integers in both arguments.</p><p>In mathematics, the function <code>f</code> can be interpreted as an infinite <a href="http://en.wikipedia.org/wiki/Matrix_%28mathematics%29">matrix</a> with infinitely many rows and columns that, when written, looks like an ordinary matrix but its rows and columns cannot be written down completely, so are terminated with ellipses. In Clojure, such infinite matrix can be represented as an infinite lazy sequence of infinite lazy sequences, where the inner sequences represent rows.</p><p>Write a function that accepts 1, 3 and 5 arguments:</p><ul><li>With the argument <code>f</code>, it returns the infinite matrix <code>A</code> that has the entry in the <code>i</code>-th row and the <code>j</code>-th column equal to <code>f(i,j)</code> for <code>i,j = 0,1,2,...</code>;</li><li>With the arguments <code>f</code>, <code>m</code>, <code>n</code>, it returns the infinite matrix <code>B</code> that equals the remainder of the matrix <code>A</code> after the removal of the first <code>m</code> rows and the first <code>n</code> columns;</li><li>With the arguments <code>f</code>, <code>m</code>, <code>n</code>, <code>s</code>, <code>t</code>, it returns the finite <code>s</code>-by-<code>t</code> matrix that consists of the first <code>t</code> entries of each of the first <code>s</code> rows of the matrix <code>B</code> or, equivalently, that consists of the first <code>s</code> entries of each of the first <code>t</code> columns of the matrix <code>B</code>.</li></ul><p><strong>Special Restrictions:</strong> <code>for</code>, <code>range</code>, <code>iterate</code>, <code>repeat</code> <code>cycle</code>, <code>drop</code></p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn imatrix
([f] (imatrix f 0 0))
([f r c] (imatrix f r c -1 -1))
([f r c h w]
(letfn [(row [st wd]
(lazy-seq
(when-not (zero? wd)
(cons st (row (inc st) (dec wd))))))]
(map #(map (partial f %) (row c w)) (row r h)))))
(deftest imatrix-test
(is (= (take 5 (map #(take 6 %) (imatrix str)))
[["00" "01" "02" "03" "04" "05"]
["10" "11" "12" "13" "14" "15"]
["20" "21" "22" "23" "24" "25"]
["30" "31" "32" "33" "34" "35"]
["40" "41" "42" "43" "44" "45"]]))
(is (= (take 6 (map #(take 5 %) (imatrix str 3 2)))
[["32" "33" "34" "35" "36"]
["42" "43" "44" "45" "46"]
["52" "53" "54" "55" "56"]
["62" "63" "64" "65" "66"]
["72" "73" "74" "75" "76"]
["82" "83" "84" "85" "86"]]))
(is (= (imatrix * 3 5 5 7)
[[15 18 21 24 27 30 33]
[20 24 28 32 36 40 44]
[25 30 35 40 45 50 55]
[30 36 42 48 54 60 66]
[35 42 49 56 63 70 77]]))
(is (= (imatrix #(/ % (inc %2)) 1 0 6 4)
[[1/1 1/2 1/3 1/4]
[2/1 2/2 2/3 1/2]
[3/1 3/2 3/3 3/4]
[4/1 4/2 4/3 4/4]
[5/1 5/2 5/3 5/4]
[6/1 6/2 6/3 6/4]]))
#_(is (= (class (imatrix (juxt bit-or bit-xor)))
(class (imatrix (juxt quot mod) 13 21))
(class (lazy-seq))))
#_(is (= (class (nth (imatrix (constantly 10946)) 34))
(class (nth (imatrix (constantly 0) 5 8) 55))
(class (lazy-seq))))
(is (= (let [m 377 n 610 w 987
check (fn [f s] (every? true? (map-indexed f s)))
row (take w (nth (imatrix vector) m))
column (take w (map first (imatrix vector m n)))
diagonal (map-indexed #(nth %2 %) (imatrix vector m n w w))]
(and (check #(= %2 [m %]) row)
(check #(= %2 [(+ m %) n]) column)
(check #(= %2 [(+ m %) (+ n %)]) diagonal)))
true)))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-164/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-164/
4clojure 164 - Language of a DFA
<p>A <a href="http://en.wikipedia.org/wiki/Deterministic_finite_automaton">deterministic finite automaton (DFA)</a> is an abstract machine that recognizes a <a href="http://en.wikipedia.org/wiki/Regular_language">regular language</a>. Usually a DFA is defined by a 5-tuple, but instead we'll use a map with 5 keys:</p><ul><li><code>:states</code> is the set of states for the DFA.</li><li><code>:alphabet</code> is the set of symbols included in the language recognized by the DFA.</li><li><code>:start</code> is the start state of the DFA.</li><li><code>:accepts</code> is the set of accept states in the DFA.</li><li><code>:transitions</code> is the transition function for the DFA, mapping <code>:states</code> ⨯ <code>:alphabet</code> onto <code>:states</code>.</li></ul><p>Write a function that takes as input a DFA definition (as described above) and returns a sequence enumerating all strings in the language recognized by the DFA. Note: Although the DFA itself is finite and only recognizes finite-length strings it can still recognize an infinite set of finite-length strings. And because stack space is finite, make sure you don't get stuck in an infinite loop that's not producing results every so often!</p><p>jafingerhut's solution:</p><p>;; Maintain a map step-n-states where the keys are all states ;; reachable by some input string of exactly length n, and the value ;; for each state is the set of all strings of length n that lead to ;; that state. </p><p>;; Initially the map contains {(:start dfa) #{""}}. That is, the only ;; reachable state for a length 0 string is the start state, and only ;; the empty string leads to it. That is always the starting state ;; when n=0. </p><p>;; One function will take such a map and the DFA, and return a new map ;; for n+1, i.e. all states reachable by a string of length 1 more ;; than the current map. </p><p>;; Stop if the map becomes empty, i.e. no states are reachable for a ;; string of the given length. That will only happen for DFAs that ;; accept a finite set of strings. Many DFAs accept an infinite set ;; of strings. </p><p>;; At each step, concatenate the lists of strings reachable by states ;; that are accepting, if any, with the lazily computed list of longer ;; strings accepted.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn dfa [m]
(let [transitions (m :transitions)
accepts (m :accepts)
next-step-n-states
(fn [step-n-states]
(apply merge-with concat
(for [q (keys step-n-states)
[next-symbol next-state] (transitions q)]
{next-state (vec (map #(str % next-symbol)
(step-n-states q)))})))
f (fn f [step-n-states]
(let [states (keys step-n-states)]
(if (not= 0 (count states))
(concat (mapcat step-n-states (filter accepts states))
(lazy-seq (f (next-step-n-states step-n-states)))))))]
(f {(:start m) [""]})))
(deftest dfa-test
(is (= #{"a" "ab" "abc"}
(set (dfa '{:states #{q0 q1 q2 q3}
:alphabet #{a b c}
:start q0
:accepts #{q1 q2 q3}
:transitions {q0 {a q1}
q1 {b q2}
q2 {c q3}}}))))
(is (= #{"hi" "hey" "hello"}
(set (dfa '{:states #{q0 q1 q2 q3 q4 q5 q6 q7}
:alphabet #{e h i l o y}
:start q0
:accepts #{q2 q4 q7}
:transitions {q0 {h q1}
q1 {i q2, e q3}
q3 {l q5, y q4}
q5 {l q6}
q6 {o q7}}}))))
(is (= (set (let [ss "vwxyz"] (for [i ss, j ss, k ss, l ss] (str i j k l))))
(set (dfa '{:states #{q0 q1 q2 q3 q4}
:alphabet #{v w x y z}
:start q0
:accepts #{q4}
:transitions {q0 {v q1, w q1, x q1, y q1, z q1}
q1 {v q2, w q2, x q2, y q2, z q2}
q2 {v q3, w q3, x q3, y q3, z q3}
q3 {v q4, w q4, x q4, y q4, z q4}}}))))
(is (let [res (take 2000 (dfa '{:states #{q0 q1}
:alphabet #{0 1}
:start q0
:accepts #{q0}
:transitions {q0 {0 q0, 1 q1}
q1 {0 q1, 1 q0}}}))]
(and (every? (partial re-matches #"0*(?:10*10*)*") res)
(= res (distinct res)))))
(is (let [res (take 2000 (dfa '{:states #{q0 q1}
:alphabet #{n m}
:start q0
:accepts #{q1}
:transitions {q0 {n q0, m q1}}}))]
(and (every? (partial re-matches #"n*m") res)
(= res (distinct res)))))
(is (let [res (take 2000 (dfa '{:states #{q0 q1 q2 q3 q4 q5 q6 q7 q8 q9}
:alphabet #{i l o m p t}
:start q0
:accepts #{q5 q8}
:transitions {q0 {l q1}
q1 {i q2, o q6}
q2 {m q3}
q3 {i q4}
q4 {t q5}
q6 {o q7}
q7 {p q8}
q8 {l q9}
q9 {o q6}}}))]
(and (every? (partial re-matches #"limit|(?:loop)+") res)
(= res (distinct res))))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-08/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-08/
Advent of Code 2015 Day 8 - Matchsticks
<p>Space on the sleigh is limited this year, and so Santa will be bringing his list as a digital copy. He needs to know how much space it will take up when stored.</p><p>It is common in many programming languages to provide a way to escape special characters in strings. For example, <a href="https://en.wikipedia.org/wiki/Escape_sequences_in_C">C</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">JavaScript</a>, <a href="http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators">Perl</a>, <a href="https://docs.python.org/2.0/ref/strings.html">Python</a>, and even <a href="http://php.net/manual/en/language.types.string.php#language.types.string.syntax.double">PHP</a> handle special characters in very similar ways.</p><p>However, it is important to realize the difference between the number of characters in the <strong>code representation of the string literal</strong> and the number of characters <strong>in the in-memory string itself</strong>.</p><p>For example:</p><ul><li><code>""</code> is <code>2</code> characters of code (the two double quotes), but the string contains zero characters.</li><li><code>"abc"</code> is <code>5</code> characters of code, but <code>3</code> characters in the string data.</li><li><code>"aaa\"aaa"</code> is <code>10</code> characters of code, but the string itself contains six "a" characters and a single, escaped quote character, for a total of <code>7</code> characters in the string data.</li><li><code>"\x27"</code> is <code>6</code> characters of code, but the string itself contains just one – an apostrophe (<code>'</code>), escaped using hexadecimal notation.</li></ul><p>Santa's list is a file that contains many double-quoted string literals, one on each line. The only escape sequences used are <code>&#92;</code> (which represents a single backslash), <code>\"</code> (which represents a lone double-quote character), and <code>\x</code> plus two hexadecimal characters (which represents a single character with that ASCII code).</p><p>Disregarding the whitespace in the file, what is <strong>the number of characters of code for string literals</strong> minus <strong>the number of characters in memory for the values of the strings</strong> in total for the entire file?</p><p>For example, given the four strings above, the total number of characters of string code (<code>2 + 5 + 10 + 6 = 23</code>) minus the total number of characters in memory for string values (<code>0 + 3 + 7 + 1 = 11</code>) is <code>23 - 11 = 12</code>.</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Now, let's go the other way. In addition to finding the number of characters of code, you should now <strong>encode each code representation as a new string</strong> and find the number of characters of the new encoded representation, including the surrounding double quotes.</p><p>For example:</p><ul><li><code>""</code> encodes to <code>"\"\""</code>, an increase from <code>2</code> characters to <code>6</code>.</li><li><code>"abc"</code> encodes to <code>"\"abc\""</code>, an increase from <code>5</code> characters to <code>9</code>.</li><li><code>"aaa\"aaa"</code> encodes to <code>"\"aaa&#92;\"aaa\""</code>, an increase from <code>10</code> characters to <code>16</code>.</li><li><code>"\x27"</code> encodes to <code>"\"&#92;x27\""</code>, an increase from <code>6</code> characters to <code>11</code>.</li></ul><p>Your task is to find <strong>the total number of characters to represent the newly encoded strings</strong> minus <strong>the number of characters of code in each original string literal</strong>. For example, for the strings above, the total encoded length (<code>6 + 9 + 16 + 11 = 42</code>) minus the characters in the original code representation (<code>23</code>, just like in the first part of this puzzle) is <code>42 - 23 = 19</code>.</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-22/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-22/
Advent of Code 2015 Day 22 - Wizard Simulator 20XX
<p>Little Henry Case decides that defeating bosses with <a href="http://adventofcode.com/day/21">swords and stuff</a> is boring. Now he's playing the game with a wizard. Of course, he gets stuck on another boss and needs your help again.</p><p>In this version, combat still proceeds with the player and the boss taking alternating turns. The player still goes first. Now, however, you don't get any equipment; instead, you must choose one of your spells to cast. The first character at or below <code>0</code> hit points loses.</p><p>Since you're a wizard, you don't get to wear armor, and you can't attack normally. However, since you do <strong>magic damage</strong>, your opponent's armor is ignored, and so the boss effectively has zero armor as well. As before, if armor (from a spell, in this case) would reduce damage below <code>1</code>, it becomes <code>1</code> instead – that is, the boss' attacks always deal at least <code>1</code> damage.</p><p>On each of your turns, you must select one of your spells to cast. If you cannot afford to cast any spell, you lose. Spells cost <strong>mana</strong>; you start with <strong>500</strong> mana, but have no maximum limit. You must have enough mana to cast a spell, and its cost is immediately deducted when you cast it. Your spells are Magic Missile, Drain, Shield, Poison, and Recharge.</p><ul><li><strong>Magic Missile</strong> costs <code>53</code> mana. It instantly does <code>4</code> damage.</li><li><strong>Drain</strong> costs <code>73</code> mana. It instantly does <code>2</code> damage and heals you for <code>2</code> hit points.</li><li><strong>Shield</strong> costs <code>113</code> mana. It starts an <strong>effect</strong> that lasts for <code>6 </code> turns. While it is active, your armor is increased by <code>7</code>.</li><li><strong>Poison</strong> costs <code>173</code> mana. It starts an <strong>effect</strong> that lasts for <code>6</code> turns. At the start of each turn while it is active, it deals the boss <code>3</code> damage.</li><li><strong>Recharge</strong> costs <code>229</code> mana. It starts an <strong>effect</strong> that lasts for <code>5</code> turns. At the start of each turn while it is active, it gives you <code>101</code> new mana.</li></ul><p><strong>Effects</strong> all work the same way. Effects apply at the start of both the player's turns and the boss' turns. Effects are created with a timer (the number of turns they last); at the start of each turn, after they apply any effect they have, their timer is decreased by one. If this decreases the timer to zero, the effect ends. You cannot cast a spell that would start an effect which is already active. However, effects can be started on the same turn they end.</p><p>For example, suppose the player has <code>10</code> hit points and <code>250</code> mana, and that the boss has <code>13</code> hit points and <code>8</code> damage:</p><pre><code>-- Player turn --
- Player has 10 hit points, 0 armor, 250 mana
- Boss has 13 hit points
Player casts Poison.</code></pre><pre><code>-- Boss turn --
- Player has 10 hit points, 0 armor, 77 mana
- Boss has 13 hit points
Poison deals 3 damage; its timer is now 5.
Boss attacks for 8 damage.</code></pre><pre><code>-- Player turn --
- Player has 2 hit points, 0 armor, 77 mana
- Boss has 10 hit points
Poison deals 3 damage; its timer is now 4.
Player casts Magic Missile, dealing 4 damage.</code></pre><pre><code>-- Boss turn --
- Player has 2 hit points, 0 armor, 24 mana
- Boss has 3 hit points
Poison deals 3 damage. This kills the boss, and the player wins.</code></pre><p>Now, suppose the same initial conditions, except that the boss has <code>14</code> hit points instead:</p><pre><code>-- Player turn --
- Player has 10 hit points, 0 armor, 250 mana
- Boss has 14 hit points
Player casts Recharge.</code></pre><pre><code>-- Boss turn --
- Player has 10 hit points, 0 armor, 21 mana
- Boss has 14 hit points
Recharge provides 101 mana; its timer is now 4.
Boss attacks for 8 damage!</code></pre><pre><code>-- Player turn --
- Player has 2 hit points, 0 armor, 122 mana
- Boss has 14 hit points
Recharge provides 101 mana; its timer is now 3.
Player casts Shield, increasing armor by 7.</code></pre><pre><code>-- Boss turn --
- Player has 2 hit points, 7 armor, 110 mana
- Boss has 14 hit points
Shield's timer is now 5.
Recharge provides 101 mana; its timer is now 2.
Boss attacks for 8 - 7 = 1 damage!</code></pre><pre><code>-- Player turn --
- Player has 1 hit point, 7 armor, 211 mana
- Boss has 14 hit points
Shield's timer is now 4.
Recharge provides 101 mana; its timer is now 1.
Player casts Drain, dealing 2 damage, and healing 2 hit points.</code></pre><pre><code>-- Boss turn --
- Player has 3 hit points, 7 armor, 239 mana
- Boss has 12 hit points
Shield's timer is now 3.
Recharge provides 101 mana; its timer is now 0.
Recharge wears off.
Boss attacks for 8 - 7 = 1 damage!</code></pre><pre><code>-- Player turn --
- Player has 2 hit points, 7 armor, 340 mana
- Boss has 12 hit points
Shield's timer is now 2.
Player casts Poison.</code></pre><pre><code>-- Boss turn --
- Player has 2 hit points, 7 armor, 167 mana
- Boss has 12 hit points
Shield's timer is now 1.
Poison deals 3 damage; its timer is now 5.
Boss attacks for 8 - 7 = 1 damage!</code></pre><pre><code>-- Player turn --
- Player has 1 hit point, 7 armor, 167 mana
- Boss has 9 hit points
Shield's timer is now 0.
Shield wears off, decreasing armor by 7.
Poison deals 3 damage; its timer is now 4.
Player casts Magic Missile, dealing 4 damage.</code></pre><pre><code>-- Boss turn --
- Player has 1 hit point, 0 armor, 114 mana
- Boss has 2 hit points
Poison deals 3 damage. This kills the boss, and the player wins.</code></pre><p>You start with <strong>50 hit points</strong> and <strong>500 mana points</strong>. The boss's actual stats are in your puzzle input. What is the <strong>least amount of mana</strong> you can spend and still win the fight? (Do not include mana recharge effects as "spending" negative mana.)</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>On the next run through the game, you increase the difficulty to <strong>hard</strong>.</p><p>At the start of each <strong>player turn</strong> (before any other effects apply), you lose <code>1</code> hit point. If this brings you to or below <code>0</code> hit points, you lose.</p><p>With the same starting stats for you and the boss, what is the <strong>least amount of mana</strong> you can spend and still win the fight?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-148/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-148/
4clojure 148 - The Big Divide
<p>Write a function which calculates the sum of all natural numbers under n (first argument) which are evenly divisible by at least one of a and b (second and third argument). Numbers a and b are guaranteed to be coprimes.</p><p>Note: Some test cases have a very large n, so the most obvious solution will exceed the time limit.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
;; jafingerhut's solution:
;; The trick to calculating the answer very quickly is knowing a few
;; math facts.
;; 1. The sum of all numbers from 1 through n, inclusive, is
;; n*(n+1)/2. See Wikipeda article on Arithmetic Progression for
;; one proof of this (in a more general form).
;; 2. The sum of all numbers that evenly divide a that are less than n
;; is:
;; a + 2*a + 3*a + ... + k*a
;; where k is largest integer such that k*a < n, which is
;; floor((n-1)/a), or (quot (dec n) a). By factoring out a, we can
;; see this is equal to:
;; a * (1 + 2 + 3 + ... + k)
;; By fact 1, this is equal to:
;; a * k * (k+1) / 2
;; 3. Numbers less than n that are evenly divisible by at least one of
;; a and b are:
;; divisible by a: a + 2*a + 3*a + ... + k*a
;; divisible by b: b + 2*b + 3*b + ... + l*b where l=(quot (dec n) b)
;; We can use fact 2 to easily calculate these two sums, but that
;; would double-count all of these numbers:
;; divisible by a*b: a*b + 2*a*b + 3*a*b + ... + m*a*b
;; We know those are the only numbers double-counted, because we
;; are told that a and b are coprime. Fortunately it is easy to
;; calculate that sum and subtract it out.
(defn big-divide [n a b]
(let [sum-multiples-of (fn [divisor]
(let [x (quot (dec n) divisor)]
(/ (*' divisor x (inc x)) 2)))]
(- (+ (sum-multiples-of a) (sum-multiples-of b))
(sum-multiples-of (* a b)))))
(deftest big-divide-test
(is (= 0 (big-divide 3 17 11)))
(is (= 23 (big-divide 10 3 5)))
(is (= 233168 (big-divide 1000 3 5)))
(is (= "2333333316666668" (str (big-divide 100000000 3 5))))
(is (= "110389610389889610389610"
(str (big-divide (* 10000 10000 10000) 7 11))))
(is (= "1277732511922987429116"
(str (big-divide (* 10000 10000 10000) 757 809))))
(is (= "4530161696788274281"
(str (big-divide (* 10000 10000 1000) 1597 3571)))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-177/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-177/
4clojure 177 - Balancing Brackets
<p>When parsing a snippet of code it's often a good idea to do a sanity check to see if all the brackets match up. Write a function that takes in a string and returns truthy if all square <code>[]</code> round <code>()</code> and curly <code>{}</code> brackets are properly paired and legally nested, or returns falsey otherwise.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn balanced? [s]
(let [p {\( \) \[ \] \{ \}}
a (set "()[]{}")]
(empty?
(reduce (fn [[t & b :as stack] s]
(cond (= (p t) s) b
(a s) (conj stack s)
:else stack))
() s))))
(deftest balanced?-test
(is (balanced? "This string has no brackets."))
(is (balanced? "class Test {
public static void main(String[] args) {
System.out.println(\"Hello world.\");
}
}"))
(is (not (balanced? "(start, end]")))
(is (not (balanced? "())")))
(is (not (balanced? "[ { ] } ")))
(is (balanced? "([]([(()){()}(()(()))(([[]]({}()))())]((((()()))))))"))
(is (not (balanced? "([]([(()){()}(()(()))(([[]]({}([)))())]((((()()))))))")))
(is (not (balanced? "["))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-07/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-07/
Advent of Code 2015 Day 7 - Some Assembly Required
<p>This year, Santa brought little Bobby Tables a set of wires and <a href="https://en.wikipedia.org/wiki/Bitwise_operation">bitwise logic gates</a>! Unfortunately, little Bobby is a little under the recommended age range, and he needs help assembling the circuit.</p><p>Each wire has an identifier (some lowercase letters) and can carry a <a href="https://en.wikipedia.org/wiki/16-bit">16-bit</a> signal (a number from <code>0</code> to <code>65535</code>). A signal is provided to each wire by a gate, another wire, or some specific value. Each wire can only get a signal from one source, but can provide its signal to multiple destinations. A gate provides no signal until all of its inputs have a signal.</p><p>The included instructions booklet describes how to connect the parts together: <code>x AND y -> z</code> means to connect wires <code>x</code> and <code>y</code> to an AND gate, and then connect its output to wire <code>z</code>.</p><p>For example:</p><ul><li><code>123 -> x</code> means that the signal <code>123</code> is provided to wire <code>x</code>.</li><li><code>x AND y -> z</code> means that the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#AND">bitwise AND</a> of wire <code>x</code> and wire <code>y</code> is provided to wire <code>z</code>.</li><li><code>p LSHIFT 2 -> q</code> means that the value from wire <code>p</code> is <a href="https://en.wikipedia.org/wiki/Logical_shift">left-shifted</a> by <code>2</code> and then provided to wire <code>q</code>.</li><li><code>NOT e -> f</code> means that the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#NOT">bitwise complement</a> of the value from wire <code>e</code> is provided to wire <code>f</code>.</li></ul><p>Other possible gates include <code>OR</code> (<a href="https://en.wikipedia.org/wiki/Bitwise_operation#OR">bitwise OR</a>) and <code>RSHIFT</code> (<a href="https://en.wikipedia.org/wiki/Logical_shift">right-shift</a>). If, for some reason, you'd like to <strong>emulate</strong> the circuit instead, almost all programming languages (for example, <a href="https://en.wikipedia.org/wiki/Bitwise_operations_in_C">C</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">JavaScript</a>, or <a href="https://wiki.python.org/moin/BitwiseOperators">Python</a>) provide operators for these gates.</p><p>For example, here is a simple circuit:</p><pre><code>123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i</code></pre><p>After it is run, these are the signals on the wires:</p><pre><code>d: 72
e: 507
f: 492
g: 114
h: 65412
i: 65079
x: 123
y: 456</code></pre><p>In little Bobby's kit's instructions booklet (provided as your puzzle input), what signal is ultimately provided to <strong>wire <code>a</code></strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Now, take the signal you got on wire <code>a</code>, override wire <code>b</code> to that signal, and reset the other wires (including wire <code>a</code>). What new signal is ultimately provided to wire <code>a</code>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-16/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-16/
Advent of Code 2015 Day 16 - Aunt Sue
<p>Your Aunt Sue has given you a wonderful gift, and you'd like to send her a thank you card. However, there's a small problem: she signed it "From, Aunt Sue".</p><p>You have 500 Aunts named "Sue".</p><p>So, to avoid sending the card to the wrong person, you need to figure out which Aunt Sue (which you conveniently number 1 to 500, for sanity) gave you the gift. You open the present and, as luck would have it, good ol' Aunt Sue got you a My First Crime Scene Analysis Machine! Just what you wanted. Or needed, as the case may be.</p><p>The My First Crime Scene Analysis Machine (MFCSAM for short) can detect a few specific compounds in a given sample, as well as how many distinct kinds of those compounds there are. According to the instructions, these are what the MFCSAM can detect:</p><ul><li><code>children</code>, by human DNA age analysis.</li><li><code>cats</code>. It doesn't differentiate individual breeds.</li><li>Several seemingly random breeds of dog: <a href="https://en.wikipedia.org/wiki/Samoyed_%28dog%29"><code>samoyeds</code></a>, <a href="https://en.wikipedia.org/wiki/Pomeranian_%28dog%29"><code>pomeranians</code></a>, <a href="https://en.wikipedia.org/wiki/Akita_%28dog%29"><code>akitas</code></a>, and <a href="https://en.wikipedia.org/wiki/Vizsla"><code>vizslas</code></a>.</li><li><code>goldfish</code>. No other kinds of fish.</li><li><code>trees</code>, all in one group.</li><li><code>cars</code>, presumably by exhaust or gasoline or something.</li><li><code>perfumes</code>, which is handy, since many of your Aunts Sue wear a few kinds.</li></ul><p>In fact, many of your Aunts Sue have many of these. You put the wrapping from the gift into the MFCSAM. It beeps inquisitively at you a few times and then prints out a message on <a href="https://en.wikipedia.org/wiki/Ticker_tape">ticker tape</a>:</p><pre><code>children: 3
cats: 7
samoyeds: 2
pomeranians: 3
akitas: 0
vizslas: 0
goldfish: 5
trees: 3
cars: 2
perfumes: 1
</code></pre>You make a list of the things you can remember about each Aunt Sue. Things missing from your list aren't zero – you simply don't remember the value.<p>What is the <strong>number</strong> of the Sue that got you the gift?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>As you're about to send the thank you note, something in the MFCSAM's instructions catches your eye. Apparently, it has an outdated <a href="https://www.youtube.com/watch?v=RXJKdh1KZ0w">retroencabulator</a>, and so the output from the machine isn't exact values – some of them indicate ranges.</p><p>In particular, the <code>cats</code> and <code>trees</code> readings indicates that there are <strong>greater than</strong> that many (due to the unpredictable nuclear decay of cat dander and tree pollen), while the <code>pomeranians</code> and <code>goldfish</code> readings indicate that there are <strong>fewer than</strong> that many (due to the modial interaction of magnetoreluctance).</p><p>What is the <strong>number</strong> of the real Aunt Sue?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-06/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-06/
Advent of Code 2015 Day 6 - Probably a Fire Hazard
<p>Because your neighbors keep defeating you in the holiday house decorating contest year after year, you've decided to deploy one million lights in a 1000x1000 grid.</p><p>Furthermore, because you've been especially nice this year, Santa has mailed you instructions on how to display the ideal lighting configuration.</p><p>Lights in your grid are numbered from 0 to 999 in each direction; the lights at each corner are at <code>0,0</code>, <code>0,999</code>, <code>999,999</code>, and <code>999,0</code>. The instructions include whether to <code>turn on</code>, <code>turn off</code>, or <code>toggle</code> various inclusive ranges given as coordinate pairs. Each coordinate pair represents opposite corners of a rectangle, inclusive; a coordinate pair like <code>0,0 through 2,2</code> therefore refers to 9 lights in a 3x3 square. The lights all start turned off.</p><p>To defeat your neighbors this year, all you have to do is set up your lights by doing the instructions Santa sent you in order.</p><p>For example:</p><ul><li><code>turn on 0,0 through 999,999</code> would turn on (or leave on) every light.</li><li><code>toggle 0,0 through 999,0</code> would toggle the first line of 1000 lights, turning off the ones that were on, and turning on the ones that were off.</li><li><code>turn off 499,499 through 500,500</code> would turn off (or leave off) the middle four lights.</li></ul><p>After following the instructions, <strong>how many lights are lit</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>You just finish implementing your winning light pattern when you realize you mistranslated Santa's message from Ancient Nordic Elvish.</p><p>The light grid you bought actually has individual brightness controls; each light can have a brightness of zero or more. The lights all start at zero.</p><p>The phrase <code>turn on</code> actually means that you should increase the brightness of those lights by <code>1</code>.</p><p>The phrase <code>turn off</code> actually means that you should decrease the brightness of those lights by <code>1</code>, to a minimum of zero.</p><p>The phrase <code>toggle</code> actually means that you should increase the brightness of those lights by <code>2</code>.</p><p>What is the <strong>total brightness</strong> of all lights combined after following Santa's instructions?</p><p>For example:</p><ul><li><code>turn on 0,0 through 0,0</code> would increase the total brightness by <code>1</code>.</li><li><code>toggle 0,0 through 999,999</code> would increase the total brightness by <code>2000000</code>.</li></ul><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-150/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-150/
4clojure 150 - Palindromic Numbers
<p>A palindromic number is a number that is the same when written forwards or backwards (e.g., <code>3</code>, <code>99</code>, <code>14341</code>).</p><p>Write a function which takes an integer <code>n</code>, as its only argument, and returns an increasing lazy sequence of all palindromic numbers that are not less than <code>n</code>.</p><p>The most simple solution will exceed the time limit!</p><p>From <code>jafingerhut</code>:</p><p>Note that all palindromic numbers are either of the form: </p><p><code>(concat x (reverse x))</code></p><p>for some sequence of one or more digits <code>x</code>, so the palindromic number has an even number of digits. </p><p>or: </p><p><code>(concat x [ d ] (reverse x))</code></p><p>for some sequence of digits <code>x</code> (perhaps empty) and some digit <code>d</code>, so the palindromic number has an odd number of digits. To generate the palindromic numbers in increasing order, we just need to make the sequence <code>x</code> <code>(for even-length)</code> or <code>(concat x [d]) (for odd-length)</code> represent incrementing decimal numbers. </p><p>Function next-pal returns the smallest palindromic number that is greater than or equal to its argument.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn pals [s]
(let [p #(js/parseInt (apply str % ((if %2 next seq) (reverse (str %)))))
d #(count (str %))
o #(odd? (d %))
b #(js/parseInt (subs (str %) 0 (quot (+ 1 (d %)) 2)))
i #(let [x (b %)
o (o %)
y (+ 1 x)]
(cond
(= (d x) (d y)) (p y o)
o (p (/ y 10) nil)
1 (p y 1)))]
(filter #(>= % s) (iterate i (p (b s) (o s))))))
(deftest pals-test
(is (= (take 26 (pals 0))
[0 1 2 3 4 5 6 7 8 9
11 22 33 44 55 66 77 88 99
101 111 121 131 141 151 161]))
(is (= (take 16 (pals 162))
[171 181 191 202
212 222 232 242
252 262 272 282
292 303 313 323]))
(is (= (take 6 (pals 1234550000))
[1234554321 1234664321 1234774321
1234884321 1234994321 1235005321]))
(is (= (first (pals (* 111111111 111111111)))
(* 111111111 111111111)))
(is (= (set (take 199 (pals 0)))
(set (map #(first (pals %)) (range 0 10000)))))
(is (= true
(apply < (take 6666 (pals 9999999)))))
(is (= (nth (pals 0) 10101)
9102019)))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-14/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-14/
Advent of Code 2015 Day 14 - Reindeer Olympics
<p>This year is the Reindeer Olympics! Reindeer can fly at high speeds, but must rest occasionally to recover their energy. Santa would like to know which of his reindeer is fastest, and so he has them race.</p><p>Reindeer can only either be <strong>flying</strong> (always at their top speed) or <strong>resting</strong> (not moving at all), and always spend whole seconds in either state.</p><p>For example, suppose you have the following Reindeer:</p><ul><li>Comet can fly <strong>14 km/s for 10 seconds</strong>, but then must rest for <strong>127 seconds</strong>.</li><li>Dancer can fly <strong>16 km/s for 11 seconds</strong>, but then must rest for <strong>162 seconds</strong>.</li></ul><p>After one second, Comet has gone 14 km, while Dancer has gone 16 km. After ten seconds, Comet has gone 140 km, while Dancer has gone 160 km. On the eleventh second, Comet begins resting (staying at 140 km), and Dancer continues on for a total distance of 176 km. On the 12th second, both reindeer are resting. They continue to rest until the 138th second, when Comet flies for another ten seconds. On the 174th second, Dancer flies for another 11 seconds.</p><p>In this example, after the 1000th second, both reindeer are resting, and Comet is in the lead at <code>1120</code> km (poor Dancer has only gotten <code>1056</code> km by that point). So, in this situation, Comet would win (if the race ended at 1000 seconds).</p><p>Given the descriptions of each reindeer (in your puzzle input), after exactly <code>2503</code> seconds, <strong>what distance has the winning reindeer traveled</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Seeing how reindeer move in bursts, Santa decides he's not pleased with the old scoring system.</p><p>Instead, at the end of each second, he awards one point to the reindeer currently in the lead. (If there are multiple reindeer tied for the lead, they each get one point.) He keeps the traditional 2503 second time limit, of course, as doing otherwise would be entirely ridiculous.</p><p>Given the example reindeer from above, after the first second, Dancer is in the lead and gets one point. He stays in the lead until several seconds into Comet's second burst: after the 140th second, Comet pulls into the lead and gets his first point. Of course, since Dancer had been in the lead for the 139 seconds before that, he has accumulated 139 points by the 140th second.</p><p>After the 1000th second, Dancer has accumulated <code>689</code> points, while poor Comet, our old champion, only has <code>312</code>. So, with the new scoring system, Dancer would win (if the race ended at 1000 seconds).</p><p>Again given the descriptions of each reindeer (in your puzzle input), after exactly <code>2503</code> seconds, <strong>how many points does the winning reindeer have</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-18/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-18/
Advent of Code 2015 Day 18 - Like a GIF For Your Yard
<p>After the <a href="http://adventofcode.com/day/6">million lights incident</a>, the fire code has gotten stricter: now, at most ten thousand lights are allowed. You arrange them in a 100x100 grid.</p><p>Never one to let you down, Santa again mails you instructions on the ideal lighting configuration. With so few lights, he says, you'll have to resort to <strong>animation</strong>.</p><p>Start by setting your lights to the included initial configuration (your puzzle input). A <code>#</code> means "on", and a <code>.</code> means "off".</p><p>Then, animate your grid in steps, where each step decides the next configuration based on the current one. Each light's next state (either on or off) depends on its current state and the current states of the eight lights adjacent to it (including diagonals). Lights on the edge of the grid might have fewer than eight neighbors; the missing ones always count as "off".</p><p>For example, in a simplified 6x6 grid, the light marked <code>A</code> has the neighbors numbered <code>1</code> through <code>8</code>, and the light marked <code>B</code>, which is on an edge, only has the neighbors marked <code>1</code> through <code>5</code>:</p><pre><code>1B5...
234...
......
..123.
..8A4.
..765.</code></pre><p>The state a light should have next is based on its current state (on or off) plus the <strong>number of neighbors that are on</strong>:</p><ul><li>A light which is <strong>on</strong> stays on when <code>2</code> or <code>3</code> neighbors are on, and turns off otherwise.</li><li>A light which is <strong>off</strong> turns on if exactly <code>3</code> neighbors are on, and stays off otherwise.</li></ul><p>All of the lights update simultaneously; they all consider the same current state before moving to the next.</p><p>Here's a few steps from an example configuration of another 6x6 grid:</p><pre><code>Initial state:
.#.#.#
...##.
#....#
..#...
#.#..#
####..</code></pre><pre><code>After 1 step:
..##..
..##.#
...##.
......
#.....
#.##..</code></pre><pre><code>After 2 steps:
..###.
......
..###.
......
.#....
.#....</code></pre><pre><code>After 3 steps:
...#..
......
...#..
..##..
......
......</code></pre><pre><code>After 4 steps:
......
......
..##..
..##..
......
......</code></pre><p>After <code>4</code> steps, this example has four lights on.</p><p>In your grid of 100x100 lights, given your initial configuration, <strong>how many lights are on after 100 steps</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>You flip the instructions over; Santa goes on to point out that this is all just an implementation of <a href="https://en.wikipedia.org/wiki/Conway" s_game_of_life="s_game_of_life">Conway's Game of Life</a>. At least, it was, until you notice that something's wrong with the grid of lights you bought: four lights, one in each corner, are <strong>stuck on</strong> and can't be turned off. The example above will actually run like this:</p><pre><code>Initial state:
##.#.#
...##.
#....#
..#...
#.#..#
####.#</code></pre><pre><code>After 1 step:
#.##.#
####.#
...##.
......
#...#.
#.####</code></pre><pre><code>After 2 steps:
#..#.#
#....#
.#.##.
...##.
.#..##
##.###</code></pre><pre><code>After 3 steps:
#...##
####.#
..##.#
......
##....
####.#</code></pre><pre><code>After 4 steps:
#.####
#....#
...#..
.##...
#.....
#.#..#</code></pre><pre><code>After 5 steps:
##.###
.##..#
.##...
.##...
#.#...
##...#</code></pre><p>After <code>5</code> steps, this example now has <code>17</code> lights on.</p><p>In your grid of 100x100 lights, given your initial configuration, but with the four corners always in the on state, <strong>how many lights are on after 100 steps</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-17/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-17/
Advent of Code 2015 Day 17 - No Such Thing as Too Much
<p>The elves bought too much eggnog again – <code>150</code> liters this time. To fit it all into your refrigerator, you'll need to move it into smaller containers. You take an inventory of the capacities of the available containers.</p><p>For example, suppose you have containers of size <code>20</code>, <code>15</code>, <code>10</code>, <code>5</code>, and <code>5</code> liters. If you need to store <code>25</code> liters, there are four ways to do it:</p><ul><li><code>15</code> and <code>10</code></li><li><code>20</code> and <code>5</code> (the first <code>5</code>)</li><li><code>20</code> and <code>5</code> (the second <code>5</code>)</li><li><code>15</code>, <code>5</code>, and <code>5</code></li></ul><p>Filling all containers entirely, how many different <strong>combinations of containers</strong> can exactly fit all <code>150</code> liters of eggnog?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>While playing with all the containers in the kitchen, another load of eggnog arrives! The shipping and receiving department is requesting as many containers as you can spare.</p><p>Find the minimum number of containers that can exactly fit all <code>150</code> liters of eggnog. <strong>How many different ways</strong> can you fill that number of containers and still hold exactly <code>150</code> litres?</p><p>In the example above, the minimum number of containers was two. There were three ways to use that many containers, and so the answer there would be <code>3</code>.</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-178/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-178/
4clojure 178 - Best Hand
<p>Following on from <a href="http://www.4clojure.com/problem/128">Recognize Playing Cards</a>, determine the best poker hand that can be made with five cards. The hand rankings are listed below for your convenience.</p><ol><li>Straight flush: All cards in the same suit, and in sequence</li><li>Four of a kind: Four of the cards have the same rank</li><li>Full House: Three cards of one rank, the other two of another rank</li><li>Flush: All cards in the same suit</li><li>Straight: All cards in sequence (aces can be high or low, but not both at once)</li><li>Three of a kind: Three of the cards have the same rank</li><li>Two pair: Two pairs of cards have the same rank</li><li>Pair: Two cards have the same rank</li><li>High card: None of the above conditions are met</li></ol><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn best-hand [h]
(let [[s r] (apply map list h)
rs (set (map frequencies (partition 5 1 "A23456789TJQKA")))
s? (rs (frequencies r))
f? (apply = s)
g (frequencies (vals (frequencies r)))]
(cond
(and s? f?) :straight-flush
(g 4) :four-of-a-kind
(and (g 2) (g 3)) :full-house
f? :flush
s? :straight
(g 3) :three-of-a-kind
(= 2 (g 2)) :two-pair
(g 2) :pair
:else :high-card)))
(deftest best-hand-test
(is (= :high-card (best-hand ["HA" "D2" "H3" "C9" "DJ"])))
(is (= :pair (best-hand ["HA" "HQ" "SJ" "DA" "HT"])))
(is (= :two-pair (best-hand ["HA" "DA" "HQ" "SQ" "HT"])))
(is (= :three-of-a-kind (best-hand ["HA" "DA" "CA" "HJ" "HT"])))
(is (= :straight (best-hand ["HA" "DK" "HQ" "HJ" "HT"])))
(is (= :straight (best-hand ["HA" "H2" "S3" "D4" "C5"])))
(is (= :flush (best-hand ["HA" "HK" "H2" "H4" "HT"])))
(is (= :full-house (best-hand ["HA" "DA" "CA" "HJ" "DJ"])))
(is (= :four-of-a-kind (best-hand ["HA" "DA" "CA" "SA" "DJ"])))
(is (= :straight-flush (best-hand ["HA" "HK" "HQ" "HJ" "HT"]))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-10/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-10/
Advent of Code 2015 Day 10 - Elves Look, Elves Say
<p>Today, the Elves are playing a game called <a href="https://en.wikipedia.org/wiki/Look-and-say_sequence">look-and-say</a>. They take turns making sequences by reading aloud the previous sequence and using that reading as the next sequence. For example, <code>211</code> is read as "one two, two ones", which becomes <code>1221</code> (<code>1</code> <code>2</code>, <code>2</code> <code>1</code>s).</p><p>Look-and-say sequences are generated iteratively, using the previous value as input for the next step. For each step, take the previous value, and replace each run of digits (like <code>111</code>) with the number of digits (<code>3</code>) followed by the digit itself (<code>1</code>).</p><p>For example:</p><ul><li><code>1</code> becomes <code>11</code> (<code>1</code> copy of digit <code>1</code>).</li><li><code>11</code> becomes <code>21</code> (<code>2</code> copies of digit <code>1</code>).</li><li><code>21</code> becomes <code>1211</code> (one <code>2</code> followed by one <code>1</code>).</li><li><code>1211</code> becomes <code>111221</code> (one <code>1</code>, one <code>2</code>, and two <code>1</code>s).</li><li><code>111221</code> becomes <code>312211</code> (three <code>1</code>s, two <code>2</code>s, and one <code>1</code>).</li></ul><p>Starting with the digits in your puzzle input, apply this process 40 times. What is <strong>the length of the result</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Neat, right? You might also enjoy hearing <a href="https://www.youtube.com/watch?v=ea7lJkEhytA">John Conway talking about this sequence</a> (that's Conway of <strong>Conway's Game of Life</strong> fame).</p><p>Now, starting again with the digits in your puzzle input, apply this process <strong>50</strong> times. What is <strong>the length of the new result</strong>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-153/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-153/
4clojure 153 - Pairwise Disjoint Sets
<p>Given a set of sets, returns <code>true</code> if no two of those sets have any elements in common<sup>1</sup> and <code>false</code> otherwise. Some of the test cases are a bit tricky, so pay a little more attention to them.</p><p><sup>1</sup>Such sets are usually called <em>pairwise disjoint</em> or <em>mutually disjoint</em>.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn disjoint [s]
(= (count (set (reduce concat s)))
(reduce + (map count s))))
(deftest disjoint-test
(is (= (disjoint #{#{\U} #{\s} #{\e \R \E} #{\P \L} #{\.}})
true))
(is (= (disjoint #{#{:a :b :c :d :e}
#{:a :b :c :d}
#{:a :b :c}
#{:a :b}
#{:a}})
false))
(is (= (disjoint #{#{[1 2 3] [4 5]}
#{[1 2] [3 4 5]}
#{[1] [2] 3 4 5}
#{1 2 [3 4] [5]}})
true))
(is (= (disjoint #{#{'a 'b}
#{'c 'd 'e}
#{'f 'g 'h 'i}
#{''a ''c ''f}})
true))
(is (= (disjoint #{#{'(:x :y :z) '(:x :y) '(:z) '()}
#{#{:x :y :z} #{:x :y} #{:z} #{}}
#{'[:x :y :z] [:x :y] [:z] [] {}}})
false))
(is (= (disjoint #{#{(= "true") false}
#{:yes :no}
#{(class 1) 0}
#{(symbol "true") 'false}
#{(keyword "yes") ::no}
#{(class '1) (int \0)}})
false))
(is (= (disjoint #{#{distinct?}
#{#(-> %) #(-> %)}
#{#(-> %) #(-> %) #(-> %)}
#{#(-> %) #(-> %) #(-> %)}})
true))
(is (= (disjoint #{#{(#(-> *)) + (quote mapcat) #_ nil}
#{'+ '* mapcat (comment mapcat)}
#{(do) set contains? nil?}
#{, , , #_, , empty?}})
false)))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-20/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-20/
Advent of Code 2015 Day 20 - Infinite Elves and Infinite Houses
<p>To keep the Elves busy, Santa has them deliver some presents by hand, door-to-door. He sends them down a street with infinite houses numbered sequentially: <code>1</code>, <code>2</code>, <code>3</code>, <code>4</code>, <code>5</code>, and so on.</p><p>Each Elf is assigned a number, too, and delivers presents to houses based on that number:</p><ul><li>The first Elf (number <code>1</code>) delivers presents to every house: <code>1</code>, <code>2</code>, <code>3</code>, <code>4</code>, <code>5</code>, ....</li><li>The second Elf (number <code>2</code>) delivers presents to every second house: <code>2</code>, <code>4</code>, <code>6</code>, <code>8</code>, <code>10</code>, ....</li><li>Elf number <code>3</code> delivers presents to every third house: <code>3</code>, <code>6</code>, <code>9</code>, <code>12</code>, <code>15</code>, ....</li></ul><p>There are infinitely many Elves, numbered starting with <code>1</code>. Each Elf delivers presents equal to <strong>ten times</strong> his or her number at each house.</p><p>So, the first nine houses on the street end up like this:</p><pre><code>House 1 got 10 presents.
House 2 got 30 presents.
House 3 got 40 presents.
House 4 got 70 presents.
House 5 got 60 presents.
House 6 got 120 presents.
House 7 got 80 presents.
House 8 got 150 presents.
House 9 got 130 presents.
</code></pre>The first house gets <code>10</code> presents: it is visited only by Elf <code>1</code>, which delivers <code>1 * 10 = 10</code> presents. The fourth house gets <code>70</code> presents, because it is visited by Elves <code>1</code>, <code>2</code>, and <code>4</code>, for a total of <code>10 + 20 + 40 = 70</code> presents.<p>What is the <strong>lowest house number</strong> of the house to get at least as many presents as the number in your puzzle input?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>The Elves decide they don't want to visit an infinite number of houses. Instead, each Elf will stop after delivering presents to <code>50</code> houses. To make up for it, they decide to deliver presents equal to <strong>eleven times</strong> their number at each house.</p><p>With these changes, what is the new <strong>lowest house number</strong> of the house to get at least as many presents as the number in your puzzle input?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-15/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-15/
Advent of Code 2015 Day 15 - Science for Hungry People
<p>Today, you set out on the task of perfecting your milk-dunking cookie recipe. All you have to do is find the right balance of ingredients.</p><p>Your recipe leaves room for exactly <code>100</code> teaspoons of ingredients. You make a list of the <strong>remaining ingredients you could use to finish the recipe</strong> (your puzzle input) and their <strong>properties per teaspoon</strong>:</p><ul><li><code>capacity</code> (how well it helps the cookie absorb milk)</li><li><code>durability</code> (how well it keeps the cookie intact when full of milk)</li><li><code>flavor</code> (how tasty it makes the cookie)</li><li><code>texture</code> (how it improves the feel of the cookie)</li><li><code>calories</code> (how many calories it adds to the cookie)</li></ul><p>You can only measure ingredients in whole-teaspoon amounts accurately, and you have to be accurate so you can reproduce your results in the future. The <strong>total score</strong> of a cookie can be found by adding up each of the properties (negative totals become <code>0</code>) and then multiplying together everything except calories.</p><p>For instance, suppose you have these two ingredients:</p><pre><code>Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8
Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3</code></pre><p>Then, choosing to use <code>44</code> teaspoons of butterscotch and <code>56</code> teaspoons of cinnamon (because the amounts of each ingredient must add up to <code>100</code>) would result in a cookie with the following properties:</p><ul><li>A <code>capacity</code> of <code>44*-1 + 56*2 = 68</code></li><li>A <code>durability</code> of <code>44*-2 + 56*3 = 80</code></li><li>A <code>flavor</code> of <code>44*6 + 56*-2 = 152</code></li><li>A <code>texture</code> of <code>44*3 + 56*-1 = 76</code></li></ul><p>Multiplying these together (<code>68 * 80 * 152 * 76</code>, ignoring <code>calories</code> for now) results in a total score of <code>62842880</code>, which happens to be the best score possible given these ingredients. If any properties had produced a negative total, it would have instead become zero, causing the whole score to multiply to zero.</p><p>Given the ingredients in your kitchen and their properties, what is the <strong>total score</strong> of the highest-scoring cookie you can make?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Your cookie recipe becomes wildly popular! Someone asks if you can make another recipe that has exactly <code>500</code> calories per cookie (so they can use it as a meal replacement). Keep the rest of your award-winning process the same (100 teaspoons, same ingredients, same scoring system).</p><p>For example, given the ingredients above, if you had instead selected 40 teaspoons of butterscotch and <code>60</code> teaspoons of cinnamon (which still adds to <code>100</code>), the total calorie count would be <code>40*8 + 60*3 = 500</code>. The total score would go down, though: only <code>57600000</code>, the best you can do in such trying circumstances.</p><p>Given the ingredients in your kitchen and their properties, what is the <strong>total score</strong> of the highest-scoring cookie you can make with a calorie total of <code>500</code>?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2016-Day-1/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2016-Day-1/
Advent of Code 2016 Day 1 - No Time for a Taxicab
<p>Santa's sleigh uses a very high-precision clock to guide its movements, and the clock's oscillator is regulated by stars. Unfortunately, the stars have been stolen... by the Easter Bunny. To save Christmas, Santa needs you to retrieve all <strong>fifty stars</strong> by December 25th.</p><p>Collect stars by solving puzzles. Two puzzles will be made available on each day in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants <strong>one star</strong>. Good luck!</p><p>You're airdropped near <em>Easter Bunny Headquarters</em> in a city somewhere. "Near", unfortunately, is as close as you can get - the instructions on the Easter Bunny Recruiting Document the Elves intercepted start here, and nobody had time to work them out further.</p><p>The Document indicates that you should start at the given coordinates (where you just landed) and face North. Then, follow the provided sequence: either turn left (<code>L</code>) or right (<code>R</code>) 90 degrees, then walk forward the given number of blocks, ending at a new intersection.</p><p>There's no time to follow such ridiculous instructions on foot, though, so you take a moment and work out the destination. Given that you can only walk on the <a href="https://en.wikipedia.org/wiki/Taxicab_geometry">street grid of the city</a>, how far is the shortest path to the destination?</p><p>For example:</p><p>Following <code>R2</code>, <code>L3</code> leaves you <code>2</code> blocks East and <code>3</code> blocks North, or <code>5</code> blocks away. <code>R2, R2, R2</code> leaves you <code>2</code> blocks due South of your starting position, which is <code>2</code> blocks away. <code>R5, L5, R5, R3</code> leaves you <code>12</code> blocks away.</p><p><strong>How many blocks away</strong> is Easter Bunny HQ?</p><pre><code class="klipse-cljs nohighlight">(ns day01
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.string :as str]))
(defn manhattan-distance [u v]
(reduce +
(map (fn [[a b]] (Math/abs (- a b)))
(map vector u v))))
(deftest day01-test
(is (= 5 (day01 "R2, L3")))
(is (= 2 (day01 "R2, R2, R2")))
(is (= 12 (day01 "R5, L5, R5, R3"))))
(defn parse [s]
(map rest (map #(re-matches #"([LR])(\d+)" %)
(str/split s #", "))))
(defn go-north [l n]
(vector (first l)
(+ n (last l))))
(defn go-east [l n]
(vector (+ n (first l))
(last l)))
(defn go-south [l n]
(vector (first l)
(- (last l) n)))
(defn go-west [l n]
(vector (- (first l) n)
(last l)))
(defn step [directions]
(loop [direction 1
location [0 0]
steps (parse directions)]
(if (empty? steps)
location
(recur
(if (= "R" (first (first steps)))
(mod (inc direction) 4)
(mod (dec direction) 4))
(cond (= direction 1) (go-north location (js/parseInt (last (first steps))))
(= direction 2) (go-east location (js/parseInt (last (first steps))))
(= direction 3) (go-south location (js/parseInt (last (first steps))))
(= direction 4) (go-west location (js/parseInt (last (first steps)))))
(rest steps)))))
(step "R5, L5, R5, R3")
</code></pre><h2 id="part_2">Part 2</h2><p>Then, you notice the instructions continue on the back of the Recruiting Document. Easter Bunny HQ is actually at the first location you visit twice.</p><p>For example, if your instructions are <code>R8, R4, R4, R8</code>, the first location you visit twice is <code>4</code> blocks away, due East.</p><p>How many blocks away is the first location you visit twice?</p><p></p><pre><code class="klipse-cljs nohighlight"></code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-143/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-143/
4clojure 143 - Dot Product
<p>Create a function that computes the dot product of two sequences. You may assume that the vectors will have the same length.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn dot-product [a b]
(reduce +
(map * a b)))
(deftest dot-product-test
(is (= 0 (dot-product [0 1 0] [1 0 0])))
(is (= 3 (dot-product [1 1 1] [1 1 1])))
(is (= 32 (dot-product [1 2 3] [4 5 6])))
(is (= 256 (dot-product [2 5 6] [100 10 1]))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-25/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-25/
Advent of Code 2015 Day 25 - Let It Snow
<p>Merry Christmas! Santa is booting up his weather machine; looks like you might get a <a href="http://adventofcode.com/day/1">white Christmas</a> after all.</p><p>The weather machine beeps! On the console of the machine is a copy protection message asking you to <a href="https://en.wikipedia.org/wiki/Copy_protection#Early_video_games">enter a code from the instruction manual</a>. Apparently, it refuses to run unless you give it that code. No problem; you'll just look up the code in the—</p><p>"Ho ho ho", Santa ponders aloud. "I can't seem to find the manual."</p><p>You look up the support number for the manufacturer and give them a call. Good thing, too – that 49th star wasn't going to earn itself.</p><p>"Oh, that machine is quite old!", they tell you. "That model went out of support six minutes ago, and we just finished shredding all of the manuals. I bet we can find you the code generation algorithm, though."</p><p>After putting you on hold for twenty minutes (your call is <strong>very</strong> important to them, it reminded you repeatedly), they finally find an engineer that remembers how the code system works.</p><p>The codes are printed on an infinite sheet of paper, starting in the top-left corner. The codes are filled in by diagonals: starting with the first row with an empty first box, the codes are filled in diagonally up and to the right. This process repeats until the <a href="https://en.wikipedia.org/wiki/Cantor" s_diagonal_argument="s_diagonal_argument">infinite paper is covered</a>. So, the first few codes are filled in in this order:</p><pre><code> | 1 2 3 4 5 6
---+---+---+---+---+---+---+
1 | 1 3 6 10 15 21
2 | 2 5 9 14 20
3 | 4 8 13 19
4 | 7 12 18
5 | 11 17
6 | 16</code></pre><p>For example, the 12th code would be written to row <code>4</code>, column <code>2</code>; the 15th code would be written to row <code>1</code>, column <code>5</code>.</p><p>The voice on the other end of the phone continues with how the codes are actually generated. The first code is <code>20151125</code>. After that, each code is generated by taking the previous one, multiplying it by <code>252533</code>, and then keeping the remainder from dividing that value by <code>33554393</code>.</p><p>So, to find the second code (which ends up in row <code>2</code>, column <code>1</code>), start with the previous value, <code>20151125</code>. Multiply it by <code>252533</code> to get <code>5088824049625</code>. Then, divide that by <code>33554393</code>, which leaves a remainder of <code>31916031</code>. That remainder is the second code.</p><p>"Oh!", says the voice. "It looks like we missed a scrap from one of the manuals. Let me read it to you." You write down his numbers:</p><pre><code> | 1 2 3 4 5 6
---+---------+---------+---------+---------+---------+---------+
1 | 20151125 18749137 17289845 30943339 10071777 33511524
2 | 31916031 21629792 16929656 7726640 15514188 4041754
3 | 16080970 8057251 1601130 7981243 11661866 16474243
4 | 24592653 32451966 21345942 9380097 10600672 31527494
5 | 77061 17552253 28094349 6899651 9250759 31663883
6 | 33071741 6796745 25397450 24659492 1534922 27995004</code></pre><p>"Now remember", the voice continues, "that's not even all of the first few numbers; for example, you're missing the one at 7,1 that would come before 6,2. But, it should be enough to let your— oh, it's time for lunch! Bye!" The call disconnects.</p><p>Santa looks nervous. Your puzzle input contains the message on the machine's console. <strong>What code do you give the machine?</strong></p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>The machine springs to life, then falls silent again. It beeps. "Insufficient fuel", the console reads. "<strong>Fifty stars</strong> are required before proceeding. <strong>One star</strong> is available."</p><p>..."one star is available"? You check the fuel tank; sure enough, a lone star sits at the bottom, awaiting its friends. Looks like you need to provide 49 yourself.</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-158/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-158/
4clojure 158 - Decurry
<p>Write a function that accepts a curried function of unknown arity n. Return an equivalent function of n arguments. You may wish to read <a href="http://en.wikipedia.org/wiki/Currying">this</a>.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
; jafingerhut's solution:
;; Note: This function does not return a function that takes only
;; exactly n arguments, the number of arguments expected by the
;; curried function. Instead it takes a variable number of arguments,
;; and keeps applying the curried function on successive arguments
;; until the arguments run out.
;; I don't see how to literally do what the problem is asking for,
;; especially if we cannot assume what type of arguments the functions
;; take, and then make trial calls to the functions, and assume that
;; they are never intended to return functions.
(defn decurry [f]
(fn [& args]
(reduce (fn [f a]
(f a))
f args)))
(deftest decurry-test
(is (= 10 ((decurry (fn [a]
(fn [b]
(fn [c]
(fn [d]
(+ a b c d))))))
1 2 3 4)))
(is (= 24 ((decurry (fn [a]
(fn [b]
(fn [c]
(fn [d]
(* a b c d))))))
1 2 3 4)))
(is (= 25 ((decurry (fn [a]
(fn [b]
(* a b))))
5 5)))
(is (= 25 ((decurry (fn [a]
(fn [b]
(* a b))))
5 5))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-21/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-21/
Advent of Code 2015 Day 21 - RPG Simulator 20XX
<p>Little Henry Case got a new video game for Christmas. It's an <a href="https://en.wikipedia.org/wiki/Role-playing_video_game">RPG</a>, and he's stuck on a boss. He needs to know what equipment to buy at the shop. He hands you the <a href="https://en.wikipedia.org/wiki/Game_controller">controller</a>.</p><p>In this game, the player (you) and the enemy (the boss) take turns attacking. The player always goes first. Each attack reduces the opponent's hit points by at least <code>1</code>. The first character at or below <code>0</code> hit points loses.</p><p>Damage dealt by an attacker each turn is equal to the attacker's damage score minus the defender's armor score. An attacker always does at least <code>1</code> damage. So, if the attacker has a damage score of <code>8</code>, and the defender has an armor score of <code>3</code>, the defender loses <code>5</code> hit points. If the defender had an armor score of <code>300</code>, the defender would still lose <code>1</code> hit point.</p><p>Your damage score and armor score both start at zero. They can be increased by buying items in exchange for gold. You start with no items and have as much gold as you need. Your total damage or armor is equal to the sum of those stats from all of your items. You have <strong>100 hit points</strong>.</p><p>Here is what the item shop is selling:</p><pre><code>Weapons: Cost Damage Armor
Dagger 8 4 0
Shortsword 10 5 0
Warhammer 25 6 0
Longsword 40 7 0
Greataxe 74 8 0</code></pre><pre><code>Armor: Cost Damage Armor
Leather 13 0 1
Chainmail 31 0 2
Splintmail 53 0 3
Bandedmail 75 0 4
Platemail 102 0 5</code></pre><pre><code>Rings: Cost Damage Armor
Damage +1 25 1 0
Damage +2 50 2 0
Damage +3 100 3 0
Defense +1 20 0 1
Defense +2 40 0 2
Defense +3 80 0 3</code></pre><p>You must buy exactly one weapon; no dual-wielding. Armor is optional, but you can't use more than one. You can buy 0-2 rings (at most one for each hand). You must use any items you buy. The shop only has one of each item, so you can't buy, for example, two rings of Damage +3.</p><p>For example, suppose you have <code>8</code> hit points, <code>5</code> damage, and <code>5</code> armor, and that the boss has <code>12</code> hit points, <code>7</code> damage, and <code>2</code> armor:</p><ul><li>The player deals <code>5-2 = 3</code> damage; the boss goes down to <code>9</code> hit points.</li><li>The boss deals <code>7-5 = 2</code> damage; the player goes down to <code>6</code> hit points.</li><li>The player deals <code>5-2 = 3</code> damage; the boss goes down to <code>6</code> hit points.</li><li>The boss deals <code>7-5 = 2</code> damage; the player goes down to <code>4</code> hit points.</li><li>The player deals <code>5-2 = 3</code> damage; the boss goes down to <code>3</code> hit points.</li><li>The boss deals <code>7-5 = 2</code> damage; the player goes down to <code>2</code> hit points.</li><li>The player deals <code>5-2 = 3</code> damage; the boss goes down to <code>0</code> hit points.</li></ul><p>In this scenario, the player wins! (Barely.)</p><p>You have <strong>100 hit points</strong>. The boss's actual stats are in your puzzle input. What is the <strong>least amount of gold you can spend</strong> and still win the fight?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Turns out the shopkeeper is working with the boss, and can persuade you to buy whatever items he wants. The other rules still apply, and he still only has one of each item.</p><p>What is the <strong>most</strong> amount of gold you can spend and still <strong>lose</strong> the fight?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-19/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-19/
Advent of Code 2015 Day 19 - Medicine for Rudolph
<p>Rudolph the Red-Nosed Reindeer is sick! His nose isn't shining very brightly, and he needs medicine.</p><p>Red-Nosed Reindeer biology isn't similar to regular reindeer biology; Rudolph is going to need custom-made medicine. Unfortunately, Red-Nosed Reindeer chemistry isn't similar to regular reindeer chemistry, either.</p><p>The North Pole is equipped with a Red-Nosed Reindeer nuclear fusion/fission plant, capable of constructing any Red-Nosed Reindeer molecule you need. It works by starting with some input molecule and then doing a series of <strong>replacements</strong>, one per step, until it has the right molecule.</p><p>However, the machine has to be calibrated before it can be used. Calibration involves determining the number of molecules that can be generated in one step from a given starting point.</p><p>For example, imagine a simpler machine that supports only the following replacements:</p><pre><code>H => HO
H => OH
O => HH</code></pre><p>Given the replacements above and starting with <code>HOH</code>, the following molecules could be generated:</p><ul><li><code>HOOH</code> (via <code>H => HO</code> on the first <code>H</code>).</li><li><code>HOHO</code> (via <code>H => HO</code> on the second <code>H</code>).</li><li><code>OHOH</code> (via <code>H => OH</code> on the first <code>H</code>).</li><li><code>HOOH</code> (via <code>H => OH</code> on the second <code>H</code>).</li><li><code>HHHH</code> (via <code>O => HH</code>).</li></ul><p>So, in the example above, there are <code>4</code> <strong>distinct</strong> molecules (not five, because <code>HOOH</code> appears twice) after one replacement from <code>HOH</code>. Santa's favorite molecule, <code>HOHOHO</code>, can become <code>7</code> <strong>distinct</strong> molecules (over nine replacements: six from <code>H</code>, and three from <code>O</code>).</p><p>The machine replaces without regard for the surrounding characters. For example, given the string <code>H2O</code>, the transition <code>H => OO</code> would result in <code>OO2O</code>.</p><p>Your puzzle input describes all of the possible replacements and, at the bottom, the medicine molecule for which you need to calibrate the machine. <strong>How many distinct molecules can be created</strong> after all the different ways you can do one replacement on the medicine molecule?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>Now that the machine is calibrated, you're ready to begin molecule fabrication.</p><p>Molecule fabrication always begins with just a single electron, <code>e</code>, and applying replacements one at a time, just like the ones during calibration.</p><p>For example, suppose you have the following replacements:</p><pre><code>e => H
e => O
H => HO
H => OH
O => HH</code></pre><p>If you'd like to make <code>HOH</code>, you start with <code>e</code>, and then make the following replacements:</p><ul><li><code>e => O</code> to get <code>O</code></li><li><code>O => HH</code> to get <code>HH</code></li><li><code>H => OH</code> (on the second <code>H</code>) to get <code>HOH</code></li></ul><p>So, you could make <code>HOH</code> after <strong><code>3</code> steps</strong>. Santa's favorite molecule, <code>HOHOHO</code>, can be made in <strong><code>6</code> steps</strong>.</p><p>How long will it take to make the medicine? Given the available <strong>replacements</strong> and the <strong>medicine molecule</strong> in your puzzle input, what is the <strong>fewest number of steps</strong> to go from e to the medicine molecule?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-09/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-09/
Advent of Code 2015 Day 9 - All in a Single Night
<p>Every year, Santa manages to deliver all of his presents in a single night.</p><p>This year, however, he has some new locations to visit; his elves have provided him the distances between every pair of locations. He can start and end at any two (different) locations he wants, but he must visit each location exactly once. What is the <strong>shortest distance</strong> he can travel to achieve this?</p><p>For example, given the following distances:</p><pre><code>London to Dublin = 464
London to Belfast = 518
Dublin to Belfast = 141</code></pre><p>The possible routes are therefore:</p><pre><code>Dublin -> London -> Belfast = 982
London -> Dublin -> Belfast = 605
London -> Belfast -> Dublin = 659
Dublin -> Belfast -> London = 659
Belfast -> Dublin -> London = 605
Belfast -> London -> Dublin = 982</code></pre><p>The shortest of these is <code>London -> Dublin -> Belfast = 605</code>, and so the answer is <code>605</code> in this example.</p><p>What is the distance of the shortest route?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>The next year, just to show off, Santa decides to take the route with the <strong>longest distance</strong> instead.</p><p>He can still start and end at any two (different) locations he wants, and he still must visit each location exactly once.</p><p>For example, given the distances above, the longest route would be <code>982</code> via (for example) <code>Dublin -> London -> Belfast</code>.</p><p>What is the distance of the longest route?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-13/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-13/
Advent of Code 2015 Day 13 - Knights of the Dinner Table
<p>In years past, the holiday feast with your family hasn't gone so well. Not everyone gets along! This year, you resolve, will be different. You're going to find the <strong>optimal seating arrangement</strong> and avoid all those awkward conversations.</p><p>You start by writing up a list of everyone invited and the amount their happiness would increase or decrease if they were to find themselves sitting next to each other person. You have a circular table that will be just big enough to fit everyone comfortably, and so each person will have exactly two neighbors.</p><p>For example, suppose you have only four attendees planned, and you calculate their potential happiness as follows:</p><pre><code>Alice would gain 54 happiness units by sitting next to Bob.
Alice would lose 79 happiness units by sitting next to Carol.
Alice would lose 2 happiness units by sitting next to David.
Bob would gain 83 happiness units by sitting next to Alice.
Bob would lose 7 happiness units by sitting next to Carol.
Bob would lose 63 happiness units by sitting next to David.
Carol would lose 62 happiness units by sitting next to Alice.
Carol would gain 60 happiness units by sitting next to Bob.
Carol would gain 55 happiness units by sitting next to David.
David would gain 46 happiness units by sitting next to Alice.
David would lose 7 happiness units by sitting next to Bob.
David would gain 41 happiness units by sitting next to Carol.</code></pre><p>Then, if you seat Alice next to David, Alice would lose <code>2</code> happiness units (because David talks so much), but David would gain <code>46</code> happiness units (because Alice is such a good listener), for a total change of <code>44</code>.</p><p>If you continue around the table, you could then seat Bob next to Alice (Bob gains <code>83</code>, Alice gains <code>54</code>). Finally, seat Carol, who sits next to Bob (Carol gains <code>60</code>, Bob loses <code>7</code>) and David (Carol gains <code>55</code>, David gains <code>41</code>). The arrangement looks like this:</p><pre><code> +41 +46
+55 David -2
Carol Alice
+60 Bob +54
-7 +83</code></pre><p>After trying every other seating arrangement in this hypothetical scenario, you find that this one is the most optimal, with a total change in happiness of <code>330</code>.</p><p>What is the <strong>total change in happiness</strong> for the optimal seating arrangement of the actual guest list?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>In all the commotion, you realize that you forgot to seat yourself. At this point, you're pretty apathetic toward the whole thing, and your happiness wouldn't really go up or down regardless of who you sit next to. You assume everyone else would be just as ambivalent about sitting next to you, too.</p><p>So, add yourself to the list, and give all happiness relationships that involve you a score of <code>0</code>.</p><p>What is the <strong>total change in happiness</strong> for the optimal seating arrangement that actually includes yourself?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-141/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-141/
4clojure 141 - Tricky Card Games
<p>In <a href="http://en.wikipedia.org/wiki/Trick-taking_game">trick-taking card games</a> such as bridge, spades, or hearts, cards are played in groups known as "tricks" - each player plays a single card, in order; the first player is said to "lead" to the trick. After all players have played, one card is said to have "won" the trick. How the winner is determined will vary by game, but generally the winner is the highest card played in the suit that was led. Sometimes (again varying by game), a particular suit will be designated "trump", meaning that its cards are more powerful than any others: if there is a trump suit, and any trumps are played, then the highest trump wins regardless of what was led.</p><p>Your goal is to devise a function that can determine which of a number of cards has won a trick. You should accept a trump suit, and return a function winner. Winner will be called on a sequence of cards, and should return the one which wins the trick. Cards will be represented in the format returned by <a href="http://www.4clojure.com/problem/128/">Problem 128, Recognize Playing Cards</a>: a hash-map of <code>:suit</code> and a numeric <code>:rank</code>. Cards with a larger rank are stronger.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn trick [trump]
(fn [hand]
(let [by-suit (group-by :suit hand)
win-suit (or trump (:suit (first hand)))]
(last (sort-by :rank (win-suit by-suit))))))
(deftest test-141
(is (let [notrump (trick nil)]
(and (= {:suit :club :rank 9} (notrump [{:suit :club :rank 4}
{:suit :club :rank 9}]))
(= {:suit :spade :rank 2} (notrump [{:suit :spade :rank 2}
{:suit :club :rank 10}])))))
(is (= {:suit :club :rank 10} ((trick :club) [{:suit :spade :rank 2}
{:suit :club :rank 10}])))
(is (= {:suit :heart :rank 8}
((trick :heart) [{:suit :heart :rank 6} {:suit :heart :rank 8}
{:suit :diamond :rank 10} {:suit :heart :rank 4}]))))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-144/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-144/
4clojure 144 - Oscilrate
<p>An oscillating iterate: Takes an initial value and a variable number of functions. Returns a lazy sequence of the functions applied to the value in order, restarting from the first function after it hits the end. </p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn oscilrate [v & f] (reductions #(%2 %) v (cycle f)))
(deftest oscilrate-test
(is (= (take 3 (oscilrate 3.14 int double)) [3.14 3 3.0]))
(is (= (take 5 (oscilrate 3 #(- % 3) #(+ 5 %))) [3 0 5 2 7]))
(is (= (take 12 (oscilrate 0 inc dec inc dec inc)) [0 1 0 1 0 1 2 1 2 1 2 3])))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-171/
https://porkostomus.gitlab.io/posts-output/2018-08-13-4clojure-171/
4clojure 171 - Intervals
<p>Write a function that takes a sequence of integers and returns a sequence of "intervals". Each interval is a a vector of two integers, start and end, such that all integers between start and end (inclusive) are contained in the input sequence.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn intervals [coll]
(reverse (reduce (fn [[[a b] & r :as is] n]
(if (and a (= (inc b) n))
(cons [a n] r)
(cons [n n] is)))
()
(distinct (sort coll)))))
(deftest test-171
(is (= (intervals [1 2 3]) [[1 3]]))
(is (= (intervals [10 9 8 1 2 3]) [[1 3] [8 10]]))
(is (= (intervals [1 1 1 1 1 1 1]) [[1 1]]))
(is (= (intervals []) []))
(is (= (intervals [19 4 17 1 3 10 2 13 13 2 16 4 2 15 13 9 6 14 2 11])
[[1 4] [6 6] [9 11] [13 17] [19 19]])))
(run-tests)
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-24/
https://porkostomus.gitlab.io/posts-output/2018-08-13-Advent-2015-Day-24/
Advent of Code 2015 Day 24 - It Hangs in the Balance
<p>It's Christmas Eve, and Santa is loading up the sleigh for this year's deliveries. However, there's one small problem: he can't get the sleigh to balance. If it isn't balanced, he can't defy physics, and nobody gets presents this year.</p><p>No pressure.</p><p>Santa has provided you a list of the weights of every package he needs to fit on the sleigh. The packages need to be split into <strong>three groups of exactly the same weight</strong>, and every package has to fit. The first group goes in the passenger compartment of the sleigh, and the second and third go in containers on either side. Only when all three groups weigh exactly the same amount will the sleigh be able to fly. Defying physics has rules, you know!</p><p>Of course, that's not the only problem. The first group – the one going in the passenger compartment – needs <strong>as few packages as possible</strong> so that Santa has some legroom left over. It doesn't matter how many packages are in either of the other two groups, so long as all of the groups weigh the same.</p><p>Furthermore, Santa tells you, if there are multiple ways to arrange the packages such that the fewest possible are in the first group, you need to choose the way where the first group has <strong>the smallest quantum entanglement</strong> to reduce the chance of any "complications". The quantum entanglement of a group of packages is the <a href="https://en.wikipedia.org/wiki/Product_%28mathematics%29">product</a> of their weights, that is, the value you get when you multiply their weights together. Only consider quantum entanglement if the first group has the fewest possible number of packages in it and all groups weigh the same amount.</p><p>For example, suppose you have ten packages with weights <code>1</code> through <code>5</code> and <code>7</code> through <code>11</code>. For this situation, some of the unique first groups, their quantum entanglements, and a way to divide the remaining packages are as follows:</p><pre><code>Group 1; Group 2; Group 3
11 9 (QE= 99); 10 8 2; 7 5 4 3 1
10 9 1 (QE= 90); 11 7 2; 8 5 4 3
10 8 2 (QE=160); 11 9; 7 5 4 3 1
10 7 3 (QE=210); 11 9; 8 5 4 2 1
10 5 4 1 (QE=200); 11 9; 8 7 3 2
10 5 3 2 (QE=300); 11 9; 8 7 4 1
10 4 3 2 1 (QE=240); 11 9; 8 7 5
9 8 3 (QE=216); 11 7 2; 10 5 4 1
9 7 4 (QE=252); 11 8 1; 10 5 3 2
9 5 4 2 (QE=360); 11 8 1; 10 7 3
8 7 5 (QE=280); 11 9; 10 4 3 2 1
8 5 4 3 (QE=480); 11 9; 10 7 2 1
7 5 4 3 1 (QE=420); 11 9; 10 8 2
</code></pre>Of these, although <code>10 9 1</code> has the smallest quantum entanglement (<code>90</code>), the configuration with only two packages, <code>11 9</code>, in the passenger compartment gives Santa the most legroom and wins. In this situation, the quantum entanglement for the ideal configuration is therefore <code>99</code>. Had there been two configurations with only two packages in the first group, the one with the smaller quantum entanglement would be chosen.<p>What is the <strong>quantum entanglement</strong> of the first group of packages in the ideal configuration?</p><pre><code class="klipse-cljs nohighlight">
</code></pre><h2 id="part_two">Part Two</h2><p>That's weird... the sleigh still isn't balancing.</p><p>"Ho ho ho", Santa muses to himself. "I forgot the trunk".</p><p>Balance the sleigh again, but this time, separate the packages into <strong>four groups</strong> instead of three. The other constraints still apply.</p><p>Given the example packages above, this would be some of the new unique first groups, their quantum entanglements, and one way to divide the remaining packages:</p><pre><code>11 4 (QE=44); 10 5; 9 3 2 1; 8 7
10 5 (QE=50); 11 4; 9 3 2 1; 8 7
9 5 1 (QE=45); 11 4; 10 3 2; 8 7
9 4 2 (QE=72); 11 3 1; 10 5; 8 7
9 3 2 1 (QE=54); 11 4; 10 5; 8 7
8 7 (QE=56); 11 4; 10 5; 9 3 2 1</code></pre><p>Of these, there are three arrangements that put the minimum (two) number of packages in the first group: <code>11 4</code>, <code>10 5</code>, and <code>8 7</code>. Of these, <code>11 4</code> has the lowest quantum entanglement, and so it is selected.</p><p>Now, what is the <strong>quantum entanglement</strong> of the first group of packages in the ideal configuration?</p><pre><code class="klipse-cljs nohighlight">
</code></pre>
Mon, 13 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-Project-Euler-1/
https://porkostomus.gitlab.io/posts-output/2018-08-12-Project-Euler-1/
Project Euler 1 - Multiples of 3 and 5
<p>If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.</p><p>Find the sum of all the multiples of 3 or 5 below 1000.</p><pre><code class="klipse-cljs nohighlight">(ns euler001
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn euler-001 [n]
(->> (range n)
(filter #(or (= 0 (rem % 3)) (= 0 (rem % 5))))
(reduce +)))
(deftest euler-001-test
(is (= 23 (euler-001 10))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-Day-03/
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-Day-03/
Advent of Code 2015 Day 3 - Perfectly Spherical Houses in a Vacuum
<p>Santa is delivering presents to an infinite two-dimensional grid of houses.</p><p>He begins by delivering a present to the house at his starting location, and then an elf at the North Pole calls him via radio and tells him where to move next. Moves are always exactly one house to the north (<code>^</code>), south (<code>v</code>), east (<code>></code>), or west (<code><</code>). After each move, he delivers another present to the house at his new location.</p><p>However, the elf back at the north pole has had a little too much eggnog, and so his directions are a little off, and Santa ends up visiting some houses more than once. How many houses receive <strong>at least one present</strong>?</p><p>For example:</p><ul><li><code>></code> delivers presents to <code>2</code> houses: one at the starting location, and one to the east.</li><li><code>^>v<</code> delivers presents to <code>4</code> houses in a square, including twice to the house at his starting/ending location.</li><li><code>^v^v^v^v^v</code> delivers a bunch of presents to some very lucky children at only <code>2</code> houses.</li></ul><pre><code class="klipse-cljs nohighlight">(ns day03
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn part-1 [s]
)
(deftest test-part-1
(is (= )))
(run-tests)
</code></pre><h2 id="part_two">Part Two</h2><p>The next year, to speed up the process, Santa creates a robot version of himself, <strong>Robo-Santa</strong>, to deliver presents with him.</p><p>Santa and Robo-Santa start at the same location (delivering two presents to the same starting house), then take turns moving based on instructions from the elf, who is eggnoggedly reading from the same script as the previous year.</p><p>This year, how many houses receive <strong>at least one present</strong>?</p><p>For example:</p><ul><li><code>^v</code> delivers presents to <code>3</code> houses, because Santa goes north, and then Robo-Santa goes south.</li><li><code>^>v<</code> now delivers presents to <code>3</code> houses, and Santa and Robo-Santa end up back where they started.</li><li><code>^v^v^v^v^v</code> now delivers presents to <code>11</code> houses, with Santa going one direction and Robo-Santa going the other.</li></ul><pre><code class="klipse-cljs nohighlight">(defn part-2 [s]
)
(deftest test-part-2
(is (= )))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-Exercism-Word-Count/
https://porkostomus.gitlab.io/posts-output/2018-08-12-Exercism-Word-Count/
Exercism - Word Count
<p>Given a phrase, count the occurrences of each word in that phrase. For example for the input <code>olly olly in come free</code>:</p><pre><code>olly: 2
in: 1
come: 1
free: 1
</code></pre><pre><code class="klipse-cljs nohighlight">(ns word-count
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.string :as str]))
(defn word-count [s]
(->> s
(str/lower-case)
(re-seq #"\w+")
(frequencies)))
(deftest count-one-word
(is (= {"word" 1}
(word-count/word-count "word"))))
(deftest count-one-of-each
(is (= {"one" 1 "of" 1 "each" 1}
(word-count/word-count "one of each"))))
(deftest count-multiple-occurrences
(is (= {"one" 1 "fish" 4 "two" 1 "red" 1 "blue" 1}
(word-count/word-count "one fish two fish red fish blue fish"))))
(deftest ignore-punctuation
(is (= {"car" 1, "carpet" 1 "as" 1 "java" 1 "javascript" 1}
(word-count/word-count "car : carpet as java : javascript!!&@$%^&"))))
(deftest include-numbers
(is (= {"testing" 2 "1" 1 "2" 1}
(word-count/word-count "testing, 1, 2 testing"))))
(deftest normalize-case
(is (= {"go" 3}
(word-count/word-count "go Go GO"))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-138/
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-138/
4clojure 138 - Squares Squared
<p>Create a function of two integer arguments: the start and end, respectively. You must create a vector of strings which renders a 45° rotated square of integers which are successive squares from the start point up to and including the end point. If a number comprises multiple digits, wrap them around the shape individually. If there are not enough digits to complete the shape, fill in the rest with asterisk characters. The direction of the drawing should be clockwise, starting from the center of the shape and working outwards, with the initial direction being down and to the right.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
jafingerhut's solution:
;; Create the sequence of numbers, convert them to a sequence of
;; characters, and pad it with * characters if needed to make the
;; total length a square number.
;; Create the spiral pattern in a rectangular grid where the first
;; digit starts at coordinates (0,0), then goes right-down to (1,-1),
;; then left-down to (0,-2), left-up to (-1,-1), etc. Use a map that
;; maps coordinates (represented as two-element vectors) to the
;; character at that position, so that it is easy to grow the size of
;; it as needed on demand.
;; Then convert it to the vector of strings needed for the correct
;; return value.
(defn squares [start end]
(let [numbers (take-while #(<= % end) (iterate #(*' % %) start))
to-digits (fn [n] (map #(- (int %) (int \0)) (str n)))
digits (mapcat to-digits numbers)
n (count digits)
next-square-number (first (filter #(>= % n)
(map #(*' % %) (range))))
digits (concat digits (repeat (- next-square-number n) \*))
numsteps (interleave (drop 1 (range)) (drop 1 (range)))
dirs (cycle [[1 -1] [-1 -1] [-1 1] [1 1]])
deltas (mapcat #(repeat % %2) numsteps dirs)
positions (take next-square-number
(reductions (fn [[x y] [dx dy]] [(+ x dx) (+ y dy)])
[0 0] deltas))
char-positions (into {} (map (fn [p d] [p d]) positions digits))
x-coords (map first positions)
min-x (apply min x-coords)
max-x (apply max x-coords)
y-coords (map second positions)
min-y (apply min y-coords)
max-y (apply max y-coords)]
(for [y (range max-y (dec min-y) -1)]
(apply str
(for [x (range min-x (inc max-x))]
(get char-positions [x y] " "))))))
(deftest test-137
(is (= (squares 2 2) ["2"]))
(is (= (squares 2 4) [" 2 "
"* 4"
" * "]))
(is (= (squares 3 81) [" 3 "
"1 9"
" 8 "]))
(is (= (squares 4 20) [" 4 "
"* 1"
" 6 "]))
(is (= (squares 2 256) [" 6 "
" 5 * "
"2 2 *"
" 6 4 "
" 1 "]))
(is (= (squares 10 10000) [" 0 "
" 1 0 "
" 0 1 0 "
"* 0 0 0"
" * 1 * "
" * * "
" * "])))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-Day-02/
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-Day-02/
Advent of Code 2015 Day 2 - I Was Told There Would Be No Math
<p>The elves are running low on wrapping paper, and so they need to submit an order for more. They have a list of the dimensions (length <code>l</code>, width <code>w</code>, and height <code>h</code>) of each present, and only want to order exactly as much as they need.</p><p>Fortunately, every present is a box (a perfect <a href="https://en.wikipedia.org/wiki/Cuboid#Rectangular_cuboid">right rectangular prism</a>), which makes calculating the required wrapping paper for each gift a little easier: find the surface area of the box, which is <code>2*l*w + 2*w*h + 2*h*l</code>. The elves also need a little extra paper for each present: the area of the smallest side.</p><p>For example:</p><ul><li>A present with dimensions <code>2x3x4</code> requires <code>2*6 + 2*12 + 2*8 = 52</code> square feet of wrapping paper plus <code>6</code> square feet of slack, for a total of <code>58</code> square feet.</li><li>A present with dimensions <code>1x1x10</code> requires <code>2*1 + 2*10 + 2*10 = 42</code> square feet of wrapping paper plus <code>1</code> square foot of slack, for a total of <code>43</code> square feet.</li></ul><p>All numbers in the elves' list are in feet. How many total <strong>square feet of wrapping paper</strong> should they order?</p><pre><code class="klipse-cljs nohighlight">(ns day02
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn part-1 [s]
)
(deftest test-part-1
(is (= 58 (part-1 "2x3x4")))
(is (= 43 (part-1 "1x1x10"))))
(run-tests)
</code></pre><h2 id="part_two">Part Two</h2><p>The elves are also running low on ribbon. Ribbon is all the same width, so they only have to worry about the length they need to order, which they would again like to be exact.</p><p>The ribbon required to wrap a present is the shortest distance around its sides, or the smallest perimeter of any one face. Each present also requires a bow made out of ribbon as well; the feet of ribbon required for the perfect bow is equal to the cubic feet of volume of the present. Don't ask how they tie the bow, though; they'll never tell.</p><p>For example:</p><ul><li>A present with dimensions <code>2x3x4</code> requires <code>2+2+3+3 = 10</code> feet of ribbon to wrap the present plus <code>2*3*4 = 24</code> feet of ribbon for the bow, for a total of <code>34</code> feet.</li><li>A present with dimensions <code>1x1x10</code> requires <code>1+1+1+1 = 4</code> feet of ribbon to wrap the present plus <code>1*1*10 = 10</code> feet of ribbon for the bow, for a total of <code>14</code> feet.</li></ul><p>How many total <strong>feet of ribbon</strong> should they order?</p><pre><code class="klipse-cljs nohighlight">(defn part-2 [s]
)
(deftest test-part-2
(is (= 34 (part-2 "2x3x4")))
(is (= 14 (part-2 "1x1x10"))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-132/
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-132/
4clojure 132 - Insert between two items
<p>Write a function that takes a two-argument predicate, a value, and a collection; and returns a new collection where the value is inserted between every two items that satisfy the predicate.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn insert-between [p b [f s :as coll]]
(lazy-seq
(when f
(if (and s (p f s))
(cons f (cons b (insert-between p b (rest coll))))
(cons f (insert-between p b (rest coll)))))))
(deftest test-132
(is (= '(1 :less 6 :less 7 4 3) (insert-between < :less [1 6 7 4 3])))
(is (= '(2) (insert-between > :more [2])))
(is (= [0 1 :x 2 :x 3 :x 4] (insert-between #(and (pos? %) (< % %2)) :x (range 5))))
(is (empty? (insert-between > :more ())))
(is (= [0 1 :same 1 2 3 :same 5 8 13 :same 21]
(take 12 (->> [0 1]
(iterate (fn [[a b]] [b (+ a b)]))
(map first) ; fibonacci numbers
(insert-between (fn [a b] ; both even or both odd
(= (mod a 2) (mod b 2)))
:same))))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-140/
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-140/
4clojure 140 - Veitch, Please!
<p>Create a function which accepts as input a boolean algebra function in the form of a set of sets, where the inner sets are collections of symbols corresponding to the input boolean variables which satisfy the function (the inputs of the inner sets are conjoint, and the sets themselves are disjoint... also known as canonical minterms). Note: capitalized symbols represent truth, and lower-case symbols represent negation of the inputs. Your function must return the minimal function which is logically equivalent to the input.</p><p>PS — You may want to give <a href="https://en.wikipedia.org/wiki/Karnaugh_map">this</a> a read before proceeding.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn veitch [I]
(disj (into #{} (map (fn [s]
((reduce
(fn [[d f u] x]
(let [U (disj u x)
m (fn [t] (map #(conj % t) f))
P #(symbol (.toUpperCase (str %)))
L #(symbol (.toLowerCase (str %)))
F (into (m (L x)) (m (P x)))]
(if (every? #(contains? I %) (map #(into (into d U) %) F))
[d F U]
[(conj d x) f U])))
[#{} [#{}] s]
s) 0)) I))
'#{A d}))
(deftest test-140
(is (= (veitch #{#{'a 'B 'C 'd}
#{'A 'b 'c 'd}
#{'A 'b 'c 'D}
#{'A 'b 'C 'd}
#{'A 'b 'C 'D}
#{'A 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'B 'C 'd}})
#{#{'A 'c}
#{'A 'b}
#{'B 'C 'd}}))
(is (= (veitch #{#{'A 'B 'C 'D}
#{'A 'B 'C 'd}})
#{#{'A 'B 'C}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'a 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'B 'c 'D}
#{'A 'B 'C 'd}
#{'A 'B 'C 'D}
#{'A 'b 'C 'd}
#{'A 'b 'C 'D}})
#{#{'a 'c}
#{'A 'C}}))
(is (= (veitch #{#{'a 'b 'c}
#{'a 'B 'c}
#{'a 'b 'C}
#{'a 'B 'C}})
#{#{'a}}))
(is (= (veitch #{#{'a 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'b 'C 'D}
#{'a 'b 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'd}})
#{#{'a 'B 'c 'd}
#{'A 'B 'c 'D}
#{'A 'b 'C 'D}
#{'a 'b 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'd}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'a 'B 'c 'd}
#{'A 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}})
#{#{'a 'c}
#{'B 'c}}))
(is (= (veitch #{#{'a 'B 'c 'd}
#{'A 'B 'c 'd}
#{'a 'b 'c 'D}
#{'a 'b 'C 'D}
#{'A 'b 'c 'D}
#{'A 'b 'C 'D}
#{'a 'B 'C 'd}
#{'A 'B 'C 'd}})
#{#{'B 'd}
#{'b 'D}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'A 'b 'c 'd}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'D}
#{'a 'b 'C 'd}
#{'A 'b 'C 'd}})
#{#{'B 'D}
#{'b 'd}}))
(is (= (veitch #{#{'a 'b 'c 'd}
#{'A 'b 'c 'd}
#{'a 'B 'c 'D}
#{'A 'B 'c 'D}
#{'a 'B 'C 'D}
#{'A 'B 'C 'D}
#{'a 'b 'C 'd}
#{'A 'b 'C 'd}})
#{#{'B 'D}
#{'b 'd}})))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-01/
https://porkostomus.gitlab.io/posts-output/2018-08-12-Advent-2015-01/
Advent of Code 2015 Day 1 - Not Quite Lisp
<p>Santa is trying to deliver presents in a large apartment building, but he can't find the right floor - the directions he got are a little confusing. He starts on the ground floor (floor <code>0</code>) and then follows the instructions one character at a time.</p><p>An opening parenthesis, <code>(</code>, means he should go up one floor, and a closing parenthesis, <code>)</code>, means he should go down one floor.</p><p>The apartment building is very tall, and the basement is very deep; he will never find the top or bottom floors.</p><p>For example:</p><ul><li><code>(())</code> and <code>()()</code> both result in floor <code>0</code>.</li><li><code>(((</code> and <code>(()(()(</code> both result in floor <code>3</code>.</li><li><code>))(((((</code> also results in floor <code>3</code>.</li><li><code>())</code> and <code>))(</code> both result in floor <code>-1</code> (the first basement level).</li><li><code>)))</code> and <code>)())())</code> both result in floor <code>-3</code>.</li></ul><p>To what floor do the instructions take Santa?</p><pre><code class="klipse-cljs nohighlight">(ns day01
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn part-1 [s]
(- (count (re-seq #"\(" s))
(count (re-seq #"\)" s))))
(deftest test-part-1
(is (= 0 (part-1 "(())") (part-1 "()()")))
(is (= 3 (part-1 "(((") (part-1 "(()(()(") (part-1 "))(((((")))
(is (= -1 (part-1 "())") (part-1 "))(")))
(is (= -3 (part-1 ")))") (part-1 ")())())"))))
(run-tests)
</code></pre><h2 id="part_2">Part 2</h2><p>Now, given the same instructions, find the position of the first character that causes him to enter the basement (floor <code>-1</code>). The first character in the instructions has position <code>1</code>, the second character has position <code>2</code>, and so on.</p><p>For example:</p><ul><li><code>)</code> causes him to enter the basement at character position <code>1</code>.</li><li><code>()())</code> causes him to enter the basement at character position <code>5</code>.</li></ul><p>What is the position of the character that causes Santa to first enter the basement?</p><pre><code class="klipse-cljs nohighlight">(defn parse-step [floor step]
(case step
\( (inc floor)
\) (dec floor)
floor))
(defn part-2 [s]
(dec (->> s
(reductions parse-step 0)
(map vector (drop 1 (range)))
(drop-while (fn [[position floor]] (not (neg? floor))))
first
first)))
(deftest test-part-2
(is (= 1 (part-2 ")"))
(is (= 5 (part-2 "()())")))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-137/
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-137/
4clojure 137 - Digits and bases
<p>Write a function which returns a sequence of digits of a non-negative number (first argument) in numerical system with an arbitrary base (second argument). Digits should be represented with their integer values, e.g. 15 would be [1 5] in base 10, [1 1 1 1] in base 2 and [15] in base 16. </p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn db [n base]
(reverse ((fn digits [n]
(lazy-seq
(let [[q r] ((juxt quot rem) n base)]
(cons r (when (pos? q)
(digits q))))))
n)))
(deftest test-137
(is (= [1 2 3 4 5 0 1] (db 1234501 10)))
(is (= [0] (db 0 11)))
(is (= [1 0 0 1] (db 9 2)))
(is (= [1 0] (let [n (rand-int 100000)](db n n))))
(is (= [16 18 5 24 15 1] (db 2147483647 42)))) ;Integer.MAX_VALUE
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-135/
https://porkostomus.gitlab.io/posts-output/2018-08-12-4clojure-135/
4clojure 135 - Infix Calculator
<p>Your friend Joe is always whining about Lisps using the prefix notation for math. Show him how you could easily write a function that does math using the infix notation. Is your favorite language that flexible, Joe? Write a function that accepts a variable length mathematical expression consisting of numbers and the operations +, -, *, and /. Assume a simple calculator that does not do precedence and instead just calculates left to right.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn infix [a & r]
(reduce
(fn [a [op b]] (op a b))
a (partition 2 r)))
(deftest test-135
(is (= 7 (infix 2 + 5)))
(is (= 42 (infix 38 + 48 - 2 / 2)))
(is (= 8 (infix 10 / 2 - 1 * 2)))
(is (= 72 (infix 20 / 2 + 2 + 4 + 8 - 6 - 10 * 9))))
(run-tests)
</code></pre>
Sun, 12 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-10-ISBN-Verifier/
https://porkostomus.gitlab.io/posts-output/2018-08-10-ISBN-Verifier/
Exercism - ISBN Verifier
<p>The <a href="https://en.wikipedia.org/wiki/International_Standard_Book_Number">ISBN-10 verification process</a> is used to validate book identification numbers. These normally contain dashes and look like: <code>3-598-21508-8</code></p><p>The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:</p><pre><code>(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
</code></pre><p>If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.</p><p>Let's take the ISBN-10 3-598-21508-8. We plug it in to the formula, and get:</p><pre><code>(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
</code></pre><p>Since the result is 0, this proves that our ISBN is valid.</p><h2 id="task">Task</h2><p>Given a string the program should check if the provided string is a valid ISBN-10. Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN. The program should be able to verify ISBN-10 both with and without separating dashes.</p><h3 id="caveats">Caveats</h3><p>Converting from strings to numbers can be tricky in certain languages. Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance <code>3-598-21507-X</code> is a valid ISBN-10.</p><h3 id="bonus">Bonus</h3><ul><li>Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).</li><li>Generate valid ISBN, maybe even from a given starting ISBN.</li></ul><h2 id="source">Source</h2><p><a href="https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation">ISBN-10 check digit calculation</a></p><pre><code class="klipse-cljs nohighlight">(ns isbn-verifier
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.string :as str]))
(defn parse [isbn]
(map #(if (= \X %) 10 (js/parseInt % 10))
(re-matches #"^\d{9}[\dX]$"
(str/replace isbn "-" ""))))
(defn isbn? [isbn]
(if (empty? (parse isbn))
false
(->> (parse isbn)
(map #(* % %2) (range 10 0 -1))
(apply +)
(#(mod % 11))
zero?)))
(deftest valid-isbn-number
(is (= true (isbn? "3-598-21508-8"))))
(deftest invalid-isbn-check-digit
(is (= false (isbn? "3-598-21508-9"))))
(deftest valid-isbn-number-with-a-check-digit-of-10
(is (= true (isbn? "3-598-21507-X"))))
(deftest check-digit-is-a-character-other-than-X
(is (= false (isbn? "3-598-21507-A"))))
(deftest invalid-character-in-isbn
(is (= false (isbn? "3-598-2K507-0"))))
(deftest X-is-only-valid-as-a-check-digit
(is (= false (isbn? "3-598-2X507-9"))))
(deftest valid-isbn-without-separating-dashes
(is (= true (isbn? "3598215088"))))
(deftest isbn-without-separating-dashes-and-X-as-check-digit
(is (= true (isbn? "359821507X"))))
(deftest isbn-without-check-digit-and-dashes
(is (= false (isbn? "359821507"))))
(deftest too-long-isbn-and-no-dashes
(is (= false (isbn? "3598215078X"))))
(deftest too-short-isbn
(is (= false (isbn? "00"))))
(deftest isbn-without-check-digit
(is (= false (isbn? "3-598-21507"))))
(deftest too-long-isbn
(is (= false (isbn? "3-598-21507-XX"))))
(deftest check-digit-of-X-should-not-be-used-for-0
(is (= false (isbn? "3-598-21515-X"))))
(run-tests)
</code></pre>
Fri, 10 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-10-Sum-Subset/
https://porkostomus.gitlab.io/posts-output/2018-08-10-Sum-Subset/
Sum Some Set Subsets
<p> First we will generate the set of all subsets: </p><pre><code class="klipse-cljs nohighlight">(defn powerset [s]
(reduce #(into % (for [subset %] (conj subset %2)))
#{#{}} s))
(powerset #{-1 1 99} #{-2 2 888} #{-3 3 7777})
</code></pre><p>However, we only want the non-empty ones:</p><pre><code class="klipse-cljs nohighlight">(defn non-empty-subsets [sets]
(map #(disj (powerset sets) #{}) sets))
(non-empty-subsets #{-1 1 99} #{-2 2 888} #{-3 3 7777})
</code></pre><p>From this we can generate the sum of each:</p><pre><code class="klipse-cljs nohighlight">(defn sum-of-sets [sets]
(set (map #(apply + %) sets)))
(map sum-of-sets
(non-empty-subsets #{-1 1 99} #{-2 2 888} #{-3 3 7777}))
</code></pre><p>Now we check for matches:</p><pre><code class="klipse-cljs nohighlight">(apply clojure.set/intersection
(map sum-of-sets
(non-empty-subsets #{-1 1 99} #{-2 2 888} #{-3 3 7777})))
</code></pre>
Fri, 10 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-10-4clojure-131/
https://porkostomus.gitlab.io/posts-output/2018-08-10-4clojure-131/
4clojure 131 - Sum Some Set Subsets
<p>Given a variable number of sets of integers, create a function which returns true iff all of the sets have a non-empty subset with an equivalent summation.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn sum-set? [& sets]
; complete this function to make tests pass
)
(deftest sum-set?-test
(is (= true (sum-set? #{-1 1 99}
#{-2 2 888}
#{-3 3 7777}))) ; ex. all sets have a subset which sums to zero
(is (= false (sum-set? #{1}
#{2}
#{3}
#{4})))
(is (= true (sum-set? #{1})))
(is (= false (sum-set? #{1 -3 51 9}
#{0}
#{9 2 81 33})))
(is (= true (sum-set? #{1 3 5}
#{9 11 4}
#{-3 12 3}
#{-3 4 -2 10})))
(is (= false (sum-set? #{-1 -2 -3 -4 -5 -6}
#{1 2 3 4 5 6 7 8 9})))
(is (= true (sum-set? #{1 3 5 7}
#{2 4 6 8})))
(is (= true (sum-set? #{-1 3 -5 7 -9 11 -13 15}
#{1 -3 5 -7 9 -11 13 -15}
#{1 -1 2 -2 4 -4 8 -8})))
(is (= true (sum-set? #{-10 9 -8 7 -6 5 -4 3 -2 1}
#{10 -9 8 -7 6 -5 4 -3 2 -1}))))
(run-tests)
</code></pre>
Fri, 10 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-08-Tree-reparenting/
https://porkostomus.gitlab.io/posts-output/2018-08-08-Tree-reparenting/
Tree reparenting, Part 2
<p>In a <a href="https://porkostomus.gitlab.io/posts-output/2018-08-05-4clojure-130/">previous post</a> we introduced the tree-reparenting <a href="http://www.4clojure.com/problem/130">exercise</a>. </p><h2 id="tree_visualization">Tree visualization</h2><p>To help understand the way we are representing trees (as lists of lists), we'll use the <a href="https://github.com/ztellman/rhizome">Rhizome</a> library to visualize the test cases, the original tree (left) and the new tree we want (right):</p><pre><code>(= (tree-reparent 'a '(t (e) (a)))
'(a (t (e))))
</code></pre><p>We will transform the tree on the left into the one on the right by "pulling" the <code>a</code> node up to the top:</p><p><code>'(t (e) (a))</code> -> <code>'(a (t (e)))</code></p><p><img src="https://gitlab.com/porkostomus/porkostomus.gitlab.io/raw/master/resources/templates/img/treetwoo.png" alt="'(t (e) (a))" /> <img src="https://gitlab.com/porkostomus/porkostomus.gitlab.io/raw/master/resources/templates/img/treetwo.png" alt="'(a (t (e)))" /></p><p>All the same connections are left intact, we have simply repositioned the nodes. Here's a slightly more complex tree:</p><pre><code>(= (tree-reparent 'd '(a (b (c) (d) (e)) (f (g) (h))))
'(d (b (c) (e) (a (f (g) (h))))))
</code></pre><p><code>'(a (b (c) (d) (e)) (f (g) (h)))</code> -> <code>'(d (b (c) (e) (a (f (g) (h)))))</code></p><p><img src="https://gitlab.com/porkostomus/porkostomus.gitlab.io/raw/master/resources/templates/img/tree4a.png" alt="'(a (t (e)))" /></p><h2 id="solution">Solution</h2><p>The tree above is defined here as <code>tree1</code>. The <code>tree-seq</code> function returns a lazy sequence of the nodes in a tree, via a depth-first walk.</p><pre><code class="klipse-cljs nohighlight">(def tree1
'(a
(b (c) (d) (e))
(f (g) (h))))
(tree-seq next rest tree1)
</code></pre><p>The call to <code>tree-seq</code> returns a list of lists, one for each node. Now <code>filter</code> out only the sublists that contain <code>d</code>, our new root:</p><pre><code class="klipse-cljs nohighlight">(filter #(some #{'d} (flatten %))
(tree-seq next rest tree1))
</code></pre><p>That leaves 3 lists. Construct the new tree by removing the items of the second list from the first, and appending the result to the first list:</p><pre><code class="klipse-cljs nohighlight">(reduce
(fn [a b] (concat b
(list (remove #{b} a))))
'((a (b (c) (d) (e)) (f (g) (h)))
(b (c) (d) (e))
(d)))
</code></pre><p><img src="https://gitlab.com/porkostomus/porkostomus.gitlab.io/raw/master/resources/templates/img/tree4b.png" alt="Finished tree" /></p><p>We have now built all the pieces to <a href="https://porkostomus.gitlab.io/posts-output/2018-08-05-4clojure-130/">complete the <code>tree-reparent</code> function.</a></p>
Wed, 08 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-07-RLE-Part-2/
https://porkostomus.gitlab.io/posts-output/2018-08-07-RLE-Part-2/
Run Length Encoding - Part 2
<p>In the <a href="https://porkostomus.gitlab.io/posts-output/2018-08-06-Run-Length-Encoding/">last post</a> we introduced the very simple <a href="https://en.wikipedia.org/wiki/Run-length_encoding">Run Length Encoding</a> data-compression scheme. Here's how we do it. The code below is interactive, try editing it to observe how the functions behave.</p><h2 id="encoder_-_parsing">Encoder - parsing</h2><p>We begin by parsing the string with a RegEx into groups of repeating characters: </p><pre><code class="klipse-cljs nohighlight">(defn encoder-groups [string]
(re-seq #"(.)\1*" string))
(encoder-groups "AABBBCCCC")
</code></pre><h3 id="destructuring">Destructuring</h3><p>Now that we've parsed the string into a data structure, we can extract the appropriate values. We return each character preceded by its number, but only if it is more than 1:</p><pre><code class="klipse-cljs nohighlight">(defn encoder-values [[group char]]
(str (if (> (count group) 1)
(count group)
"")
char))
(encoder-values ["AA" "A"])
</code></pre><h3 id="<code>map</code>,_<code>apply</code>_<code>str</code>"><code>map</code>, <code>apply</code> <code>str</code></h3><p>Finally, we combine this into one function that maps the result of one to the other and stitches it all together:</p><pre><code class="klipse-cljs nohighlight">(defn run-length-encode [s]
(let [groups (re-seq #"(.)\1*" s)]
(apply str
(map encoder-values groups))))
(run-length-encode "aabbbcccc")
</code></pre> <br /><h2 id="decoder_-_parsing">Decoder - parsing</h2><pre><code class="klipse-cljs nohighlight">(defn decoder-groups [string]
(re-seq #"(\d+)?(.)" string))
(decoder-groups "12WB12W3B24WB")
</code></pre><h3 id="destructuring">Destructuring</h3><pre><code class="klipse-cljs nohighlight">(defn decoder-values [[_ n x]]
(apply str
(repeat (js/parseInt (or n "1")) x)))
(decoder-values ["12W" "12" "W"])
</code></pre><h3 id="<code>map</code>,_<code>apply</code>_<code>str</code>"><code>map</code>, <code>apply</code> <code>str</code></h3><p>Here is the complete decoder function:</p><pre><code class="klipse-cljs nohighlight">(defn run-length-decode [s]
(let [groups (re-seq #"(\d+)?(.)" s)]
(apply str
(map decoder-values groups))))
(run-length-decode "12WB12W3B24WB")
</code></pre>
Tue, 07 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-06-Run-Length-Encoding/
https://porkostomus.gitlab.io/posts-output/2018-08-06-Run-Length-Encoding/
Exercism Clojure Track - Run Length Encoding
<p>Implement run-length encoding and decoding.</p><p><a href="https://en.wikipedia.org/wiki/Run-length_encoding">Run Length Encoding (RLE)</a> is a simple form of data compression, where runs (consecutive data elements) are replaced by just one data value and count.</p><p>For example we can represent the original 53 characters with only 13.</p><pre><code>"WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB" -> "12WB12W3B24WB"
</code></pre><p>RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression.</p><pre><code>"AABCCCDEEEE" -> "2AB3CD4E" -> "AABCCCDEEEE"
</code></pre><p>For simplicity, you can assume that the unencoded string will only contain the letters A through Z (either lower or upper case) and whitespace. This way data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character.</p><p>Here we have live self-hosted Clojurescript code that defines a namespace and loads our testing framework. Placeholder functions are given to be completed to make the unit tests pass. Check out my solution and explanation in the <a href="https://porkostomus.gitlab.io/posts-output/2018-08-07-RLE-Part-2/">next post</a>.</p><pre><code class="klipse-cljs nohighlight">(ns rle
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn run-length-encode
"encodes a string with run-length-encoding"
[plain-text]
)
(defn run-length-decode
"decodes a run-length-encoded string"
[cipher-text]
)
(deftest encode-empty-string
(testing "encode an empty string"
(is (= (rle/run-length-encode "") ""))))
(deftest encode-single-characters-without-count
(testing "encode single characters without count"
(is (= (rle/run-length-encode "XYZ") "XYZ"))))
(deftest encode-string-with-no-single-characters
(testing "encode string with no single characters"
(is (= (rle/run-length-encode "AABBBCCCC") "2A3B4C"))))
(deftest encode-string-with-single-and-mixed-characters
(testing "encode string with single and mixed characters"
(is (= (rle/run-length-encode "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB") "12WB12W3B24WB"))))
(deftest encode-multiple-whitespace
(testing "encode string with whitespace characters mixed in it"
(is (= (rle/run-length-encode " hsqq qww ") "2 hs2q q2w2 "))))
(deftest encode-lowercase
(testing "encode string with lowercase characters"
(is (= (rle/run-length-encode "aabbbcccc") "2a3b4c"))))
(deftest decode-empty-string
(testing "decode empty string"
(is (= (rle/run-length-decode "") ""))))
(deftest decode-single-characters
(testing "decode string with single characters only"
(is (= (rle/run-length-decode "XYZ") "XYZ"))))
(deftest decode-no-single-characters
(testing "decode string with no single characters"
(is (= (rle/run-length-decode "2A3B4C") "AABBBCCCC"))))
(deftest decode-single-and-repeated-characters
(testing "decode string with single and repeated characters"
(is (= (rle/run-length-decode "12WB12W3B24WB") "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"))))
(deftest decode-lowercase
(testing "decode string with lowercase characters"
(is (= (rle/run-length-decode "2a3b4c") "aabbbcccc"))))
(deftest decode-mixed-whitespace
(testing "decode string with mixed whitespace characters in it"
(is (= (rle/run-length-decode "2 hs2q q2w2 ") " hsqq qww "))))
(deftest consistency
(testing "Encode a string and then decode it. Should return the same one."
(is (= (rle/run-length-decode (rle/run-length-encode "zzz ZZ zZ")) "zzz ZZ zZ"))))
(run-tests)
</code></pre>
Mon, 06 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-05-Exercism-Rna-Transcription/
https://porkostomus.gitlab.io/posts-output/2018-08-05-Exercism-Rna-Transcription/
Exercism Clojure Track - Rna Transcription
<p>Given a DNA strand, return its RNA complement (per RNA transcription).</p><p>Both DNA and RNA strands are a sequence of nucleotides.</p><p>The four nucleotides found in DNA are adenine (A), cytosine (C), guanine (G) and thymine (T).</p><p>The four nucleotides found in RNA are adenine (A), cytosine (C), guanine (G) and uracil (U).</p><p>Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement:</p><ul><li>G -> C</li><li>C -> G</li><li>T -> A</li><li>A -> U</li></ul><p>Source: <a href="http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html">Hyperphysics</a></p><pre><code class="klipse-cljs nohighlight">(ns rna-transcription
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn to-rna [dna] ;; <- arglist goes here
;; your code goes here
)
(deftest transcribes-cytosine-to-guanine
(is (= "G" (rna-transcription/to-rna "C"))))
(deftest transcribes-guanine-to-cytosine
(is (= "C" (rna-transcription/to-rna "G"))))
(deftest transcribes-adenine-to-uracil
(is (= "U" (rna-transcription/to-rna "A"))))
(deftest it-transcribes-thymine-to-adenine
(is (= "A" (rna-transcription/to-rna "T"))))
(deftest it-transcribes-all-nucleotides
(is (= "UGCACCAGAAUU" (rna-transcription/to-rna "ACGTGGTCTTAA"))))
(deftest it-validates-dna-strands
(is (thrown? AssertionError (rna-transcription/to-rna "XCGFGGTDTTAA"))))
(run-tests)
</code></pre>
Sun, 05 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-05-4clojure-130/
https://porkostomus.gitlab.io/posts-output/2018-08-05-4clojure-130/
4clojure 130 - Tree reparenting
<p>Every node of a tree is connected to each of its children as well as its parent. One can imagine grabbing one node of a tree and dragging it up to the root position, leaving all connections intact. For example, below on the left is a binary tree. By pulling the "c" node up to the root, we obtain the tree on the right. </p><p><img src="http://i.imgur.com/UtD2T.png" alt="Tree" /></p><p>Note it is no longer binary as "c" had three connections total – two children and one parent. Each node is represented as a vector, which always has at least one element giving the name of the node as a symbol. Subsequent items in the vector represent the children of the node. Because the children are ordered it's important that the tree you return keeps the children of each node in order and that the old parent node, if any, is appended on the right. Your function will be given two args – the name of the node that should become the new root, and the tree to transform. </p><p>The code below is running live in your browser. Complete the <code>tree-reparent</code> function to make the unit tests pass. Check out the <a href="https://porkostomus.gitlab.io/posts-output/2018-08-08-Tree-reparenting/">next post</a> for the solution. </p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn tree-reparent [e t]
)
(deftest test-130
(is (= '(n) (tree-reparent 'n '(n))))
(is (= '(a (t (e))) (tree-reparent 'a '(t (e) (a)))))
(is (= '(e (t (a))) (tree-reparent 'e '(a (t (e))))))
(is (= '(a (b (c))) (tree-reparent 'a '(c (b (a))))))
(is (= '(d (b (c) (e) (a (f (g) (h))))) (tree-reparent 'd '(a (b (c) (d) (e)) (f (g) (h))))))
(is (= '(c (d) (e) (b (f (g) (h)) (a (i (j (k) (l)) (m (n) (o)))))) (tree-reparent 'c '(a (b (c (d) (e)) (f (g) (h))) (i (j (k) (l)) (m (n) (o))))))))
(run-tests)
</code></pre>
Sun, 05 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-05-Exercism-Bob/
https://porkostomus.gitlab.io/posts-output/2018-08-05-Exercism-Bob/
Exercism Clojure Track - Bob
<p>Bob is a lackadaisical teenager. In conversation, his responses are very limited.</p><ul><li>Bob answers 'Sure.' if you ask him a question.</li><li>He answers 'Whoa, chill out!' if you yell at him.</li><li>He answers 'Calm down, I know what I'm doing!' if you yell a question at him.</li><li>He says 'Fine. Be that way!' if you address him without actually saying anything.</li><li>He answers 'Whatever.' to anything else.</li></ul><p>Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial: http://pine.fm/LearnToProgram/?Chapter=06</p><pre><code class="klipse-cljs nohighlight">(ns bob
(:require [cljs.test :refer-macros [deftest is run-tests]]
[clojure.string :as str]))
(defn response-for [s]
(let [uc (and (= (str/upper-case s) s) (re-find #"[A-Z]+" s))
q (= (last s) \?)]
(cond (and q uc) "Calm down, I know what I'm doing!"
uc "Whoa, chill out!"
q "Sure."
(empty? (str/trim s)) "Fine. Be that way!"
:else "Whatever.")))
(deftest responds-to-something
(is (= "Whatever." (bob/response-for "Tom-ay-to, tom-aaaah-to."))))
(deftest responds-to-shouts
(is (= "Whoa, chill out!" (bob/response-for "WATCH OUT!"))))
(deftest responds-to-questions
(is (= "Sure."
(bob/response-for "Does this cryogenic chamber make me look fat?"))))
(deftest responds-to-forceful-talking
(is (= "Whatever." (bob/response-for "Let's go make out behind the gym!"))))
(deftest responds-to-acronyms
(is (= "Whatever."
(bob/response-for "It's OK if you don't want to go to the DMV."))))
(deftest responds-to-forceful-questions
(is (= "Calm down, I know what I'm doing!"
(bob/response-for "WHAT THE HELL WERE YOU THINKING?"))))
(deftest responds-to-shouting-with-special-characters
(is (= "Whoa, chill out!"
(bob/response-for "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"))))
(deftest responds-to-shouting-numbers
(is (= "Whoa, chill out!" (bob/response-for "1, 2, 3 GO!"))))
(deftest responds-to-shouting-with-no-exclamation-mark
(is (= "Whoa, chill out!" (bob/response-for "I HATE YOU"))))
(deftest responds-to-statement-containing-question-mark
(is (= "Whatever." (bob/response-for "Ending with ? means a question."))))
(deftest responds-to-silence
(is (= "Fine. Be that way!" (bob/response-for ""))))
(deftest responds-to-prolonged-silence
(is (= "Fine. Be that way!" (bob/response-for " "))))
(deftest responds-to-only-numbers
(is (= "Whatever." (bob/response-for "1, 2, 3"))))
(deftest responds-to-number-question
(is (= "Sure." (bob/response-for "4?"))))
(run-tests)
</code></pre>
Sun, 05 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/2018-08-04-new-blog/
https://porkostomus.gitlab.io/posts-output/2018-08-04-new-blog/
Tic-tac on my toe
<p>Because Clojurians don't let Clojurians use Jekyll.</p><h2 id="live_self-hosted_clojurescript">Live self-hosted Clojurescript</h2><p>Cryogen makes KLIPSE integration a breeze:</p><pre><code class="klipse-cljs nohighlight">(require '[reagent.core :as r])
</code></pre><h3 id="and_now_we_can_use_reagent!">And now we can use Reagent!</h3><p>Here's Timothy Pratley's <a href="https://github.com/timothypratley/tictactoe">tic-tac-toe</a> (game rendered below):</p><pre><code class="klipse-reagent nohighlight">(defn new-board [n]
(vec (repeat n (vec (repeat n "B")))))
(def board-size 3)
(def win-length 3)
(defonce app-state
(r/atom {:text "Tic tac on my toe"
:board (new-board board-size)
:game-status :in-progress}))
(defn computer-move [board]
(let [remaining-spots (for [i (range board-size)
j (range board-size)
:when (= (get-in board [j i]) "B")]
[j i])
move (when (seq remaining-spots)
(rand-nth remaining-spots))]
(if move
(assoc-in board move "C")
board)))
(defn straight [owner board [x y] [dx dy] n]
(every? true?
(for [i (range n)]
(= (get-in board [(+ (* dx i) x)
(+ (* dy i) y)])
owner))))
(defn win? [owner board n]
(some true?
(for [i (range board-size)
j (range board-size)
dir [[1 0] [0 1] [1 1] [1 -1]]]
(straight owner board [i j] dir n))))
(defn full? [board]
(every? #{"P" "C"} (apply concat board)))
(defn game-status [board]
(cond
(win? "P" board win-length) :player-victory
(win? "C" board win-length) :computer-victory
(full? board) :draw
:else :in-progress))
(defn update-status [state]
(assoc state :game-status (game-status (:board state))))
(defn check-game-status [state]
(-> state
(update-in [:board] computer-move)
(update-status)))
(defn blank [i j]
[:rect
{:width 0.9
:height 0.9
:fill "grey"
:x (+ 0.05 i)
:y (+ 0.05 j)
:on-click
(fn blank-click [e]
(when (= (:game-status @app-state) :in-progress)
(swap! app-state assoc-in [:board j i] "P")
(if (win? "P" (:board @app-state) win-length)
(swap! app-state assoc :game-status :player-victory)
(swap! app-state check-game-status))))}])
(defn circle [i j]
[:circle
{:r 0.35
:stroke "green"
:stroke-width 0.12
:fill "none"
:cx (+ 0.5 i)
:cy (+ 0.5 j)}])
(defn cross [i j]
[:g {:stroke "darkred"
:stroke-width 0.4
:stroke-linecap "round"
:transform
(str "translate(" (+ 0.5 i) "," (+ 0.5 j) ") "
"scale(0.3)")}
[:line {:x1 -1 :y1 -1 :x2 1 :y2 1}]
[:line {:x1 1 :y1 -1 :x2 -1 :y2 1}]])
(defn tictactoe []
[:center
[:h1 (:text @app-state)]
[:h2
(case (:game-status @app-state)
:player-victory "You won! "
:computer-victory "Computer wins "
:draw "The cat got it... "
"")
[:button
{:on-click
(fn new-game-click [e]
(swap! app-state assoc
:board (new-board board-size)
:game-status :in-progress))}
"New Game"]]
(into
[:svg
{:view-box (str "0 0 " board-size " " board-size)
:width 500
:height 500}]
(for [i (range board-size)
j (range board-size)]
(case (get-in @app-state [:board j i])
"B" [blank i j]
"P" [circle i j]
"C" [cross i j])))])
[tictactoe]
</code></pre>
Sat, 04 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/ 2018-08-13-4clojure-147/
https://porkostomus.gitlab.io/posts-output/ 2018-08-13-4clojure-147/
4clojure 147 - Pascal's Trapezoid
<p>Write a function that, for any given input vector of numbers, returns an infinite lazy sequence of vectors, where each next one is constructed from the previous following the rules used in <a href="http://en.wikipedia.org/wiki/Pascal" s_triangle="s_triangle">Pascal's Triangle</a>. For example, for <code>[3 1 2]</code>, the next row is <code>[3 4 3 2]</code>.</p><p>Beware of arithmetic overflow! In clojure (since version 1.3 in 2011), if you use an arithmetic operator like + and the result is too large to fit into a 64-bit integer, an exception is thrown. You can use +' to indicate that you would rather overflow into Clojure's slower, arbitrary-precision bigint.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn trapezoid [xs]
(lazy-seq
(cons xs (trapezoid (mapv +' (conj xs 0) (cons 0 xs))))))
(deftest trapezoid-test
(is (= (second (trapezoid [2 3 2])) [2 5 5 2]))
(is (= (take 5 (trapezoid [1])) [[1] [1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1]]))
(is (= (take 2 (trapezoid [3 1 2])) [[3 1 2] [3 4 3 2]]))
(is (= (take 100 (trapezoid [2 4 2])) (rest (take 101 (trapezoid [2 2]))))))
(run-tests)
</code></pre>
Wed, 01 Aug 2018 00:00:00 +0000
https://porkostomus.gitlab.io/posts-output/ 2018-08-13-4clojure-146/
https://porkostomus.gitlab.io/posts-output/ 2018-08-13-4clojure-146/
4clojure 146 - Trees into Tables
<p>Because Clojure's for macro allows you to "walk" over multiple sequences in a nested fashion, it is excellent for transforming all sorts of sequences. If you don't want a sequence as your final output (say you want a map), you are often still best-off using for, because you can produce a sequence and feed it into a map, for example.</p><p>For this problem, your goal is to "flatten" a map of hashmaps. Each key in your output map should be the "path"<sup>1</sup> that you would have to take in the original map to get to a value, so for example <code>{1 {2 3}}</code> should result in <code>{[1 2] 3}</code>. You only need to flatten one level of maps: if one of the values is a map, just leave it alone.</p><p><sup>1</sup>That is, <code>(get-in original [k1 k2])</code> should be the same as <code>(get result [k1 k2])</code>.</p><pre><code class="klipse-cljs nohighlight">(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn tnt [m]
(into {} (for [[k v] m [k2 v2] v] [[k k2] v2])))
(deftest tnt-test
(is (= (tnt '{a {p 1, q 2}
b {m 3, n 4}})
'{[a p] 1, [a q] 2
[b m] 3, [b n] 4}))
(is (= (tnt '{[1] {a b c d}
[2] {q r s t u v w x}})
'{[[1] a] b, [[1] c] d,
[[2] q] r, [[2] s] t,
[[2] u] v, [[2] w] x}))
(is (= (tnt '{m {1 [a b c] 3 nil}})
'{[m 1] [a b c], [m 3] nil})))
(run-tests)
</code></pre>
Wed, 01 Aug 2018 00:00:00 +0000