|
| 1 | +^{:kindly/hide-code true |
| 2 | + :clay {:title "4Clojure puzzles with twotiles" |
| 3 | + :quarto {:author :kloimhardt |
| 4 | + :type :post |
| 5 | + :draft true |
| 6 | + :date "2025-09-25" |
| 7 | + :image "" |
| 8 | + :category :concepts |
| 9 | + :tags [:blockly :graphical-programming]}}} |
| 10 | + |
| 11 | +(ns games.twotiles-4clojure.clj |
| 12 | + (:require [scicloj.kindly.v4.api :as kindly] |
| 13 | + [scicloj.kindly.v4.kind :as kind])) |
| 14 | + |
| 15 | +^:kindly/hide-code |
| 16 | +(def md |
| 17 | + (comp kindly/hide-code kind/md)) |
| 18 | + |
| 19 | +^:kindly/hide-code |
| 20 | +(kind/hiccup |
| 21 | + [:div |
| 22 | + [:script {:src "https://unpkg.com/blockly/blockly_compressed.js"}] |
| 23 | + [:script {:src "https://unpkg.com/blockly/msg/en.js"}] |
| 24 | + [:script {:src "https://kloimhardt.github.io/twotiles/twotiles_core.js"}] |
| 25 | + [:script (str "var parse = scittle.core.eval_string(twotiles.parse_clj);" |
| 26 | + "var addBlocks = (ws, code) =>" |
| 27 | + "Blockly.Xml.appendDomToWorkspace(Blockly.utils.xml.textToDom(parse(code)), ws);")] |
| 28 | + [:script "Blockly.defineBlocksWithJsonArray(twotiles.blocks);"]]) |
| 29 | + |
| 30 | +^:kindly/hide-code |
| 31 | +(defn ws-hiccup [name height] |
| 32 | + [:div |
| 33 | + [:div {:id name, :style {:height height}}] |
| 34 | + [:script (str "var " name " = Blockly.inject('" name "'," |
| 35 | + "{'sounds': false, 'scrollbars':false, 'trashcan':false})")]]) |
| 36 | + |
| 37 | +^:kindly/hide-code |
| 38 | +(def create-ws (comp kindly/hide-code ws-hiccup)) |
| 39 | + |
| 40 | +(md "## 4Clojure Problem 110, Pronunciation") |
| 41 | + |
| 42 | +(md "Produce a \"pronunciation\" of a sequence of numbers. For example, [1 1] is pronounced as [2 1] (\"two ones\"), which in turn is pronounced as [1 2 1 1] (\"one two, one one\"). The solution below is taken from the [4Clojure website](https://4clojure.oxal.org)." ) |
| 43 | + |
| 44 | +(defn pronounce |
| 45 | + [numbers] |
| 46 | + (mapcat (juxt count first) |
| 47 | + (partition-by identity |
| 48 | + numbers))) |
| 49 | + |
| 50 | +(doall [(pronounce [1]) |
| 51 | + (pronounce [1 1]) |
| 52 | + (pronounce [2 1])]) |
| 53 | + |
| 54 | +^:kindly/hide-code |
| 55 | +(defn add-ws [ws] |
| 56 | + (fn [code] |
| 57 | + (kindly/hide-code |
| 58 | + (kind/scittle |
| 59 | + (list 'js/addBlocks |
| 60 | + ws |
| 61 | + (str code)))))) |
| 62 | + |
| 63 | +(md "To memorize this solution, complete the following set of graphical puzzles. The most fun is on mobile devices. Maybe you want to scroll through the workspaces first, to get the idea.") |
| 64 | + |
| 65 | +^:kindly/hide-code |
| 66 | +(def add-pr1 (add-ws 'js/pr1)) |
| 67 | +(add-pr1 'numbers) |
| 68 | +(add-pr1 'identity) |
| 69 | +(add-pr1 '(:tiles/vert |
| 70 | + (partition-by :tiles/slot |
| 71 | + :tiles/slot))) |
| 72 | +(kind/hiccup (create-ws "pr1" "300px")) |
| 73 | + |
| 74 | + |
| 75 | +(md "Step two") |
| 76 | +^:kindly/hide-code |
| 77 | +(def add-pr2 (add-ws 'js/pr2)) |
| 78 | +(add-pr2 '(:tiles/vert |
| 79 | + (partition-by identity |
| 80 | + numbers))) |
| 81 | +(add-pr2 'first) |
| 82 | +(add-pr2 'count) |
| 83 | +(add-pr2 '(juxt :tiles/slot :tiles/slot)) |
| 84 | +(kind/hiccup (create-ws "pr2" "300px")) |
| 85 | + |
| 86 | +(md "Step three") |
| 87 | +^:kindly/hide-code |
| 88 | +(def add-pr3 (add-ws 'js/pr3)) |
| 89 | +(add-pr3 '(:tiles/vert |
| 90 | + (partition-by identity numbers))) |
| 91 | +(add-pr3 '(juxt count first)) |
| 92 | +(add-pr3 '(:tiles/vert |
| 93 | + (mapcat :tiles/slot |
| 94 | + :tiles/slot))) |
| 95 | +(kind/hiccup (create-ws "pr3" "300px")) |
| 96 | + |
| 97 | + |
| 98 | +(md "Step four") |
| 99 | +^:kindly/hide-code |
| 100 | +(def add-pr4 (add-ws 'js/pr4)) |
| 101 | +(add-pr4 |
| 102 | + '(:tiles/vert |
| 103 | + (mapcat (juxt count first) |
| 104 | + (:tiles/vert |
| 105 | + (partition-by identity |
| 106 | + numbers))))) |
| 107 | +(add-pr4 '[numbers]) |
| 108 | +(add-pr4 'pronounce) |
| 109 | +(add-pr4 '(defn :tiles/slot |
| 110 | + :tiles/slot |
| 111 | + :tiles/slot)) |
| 112 | +(kind/hiccup (create-ws "pr4" "300px")) |
| 113 | + |
| 114 | +(md "The final result") |
| 115 | +((add-ws 'js/pr5) |
| 116 | + '(defn pronounce [numbers] |
| 117 | + (:tiles/vert |
| 118 | + (mapcat (juxt count first) |
| 119 | + (:tiles/vert |
| 120 | + (partition-by identity |
| 121 | + numbers)))))) |
| 122 | + |
| 123 | +(kind/hiccup (create-ws "pr5" "300px")) |
| 124 | + |
| 125 | + |
| 126 | +(md "## 4Clojure #85: Powerset") |
| 127 | + |
| 128 | +(md "Write a function which generates the power set of a given set. The power set of a set x is the set of all subsets of x, including the empty set and x itself.") |
| 129 | + |
| 130 | +(defn powerset |
| 131 | + [original-set] |
| 132 | + (reduce (fn [result e] |
| 133 | + (into result |
| 134 | + (map (fn [x] |
| 135 | + (conj x e)) |
| 136 | + result))) |
| 137 | + (hash-set #{ }) |
| 138 | + original-set)) |
| 139 | + |
| 140 | +(powerset (hash-set 1 2)) |
| 141 | + |
| 142 | +^:kindly/hide-code |
| 143 | +(kind/scittle |
| 144 | + '(set! (.-add_ps js/window) |
| 145 | + (fn [code] |
| 146 | + (js/addBlocks js/ps code)))) |
| 147 | + |
| 148 | +^:kindly/hide-code |
| 149 | +(defn btn-hiccup [tupels] |
| 150 | + (into [:div] |
| 151 | + (map-indexed (fn [i cs] |
| 152 | + [:button |
| 153 | + {:onClick |
| 154 | + (reduce (fn [r c] |
| 155 | + (str r "add_ps('" c "');")) |
| 156 | + "" |
| 157 | + cs)} |
| 158 | + (str "Step number " (inc i))]) |
| 159 | + tupels))) |
| 160 | + |
| 161 | +(md "Again, complete a set of according puzzles step by step. This time, there is only one singe workspace. Start by clicking the first button.") |
| 162 | + |
| 163 | +^:kindly/hide-code |
| 164 | +(kind/hiccup |
| 165 | + (btn-hiccup |
| 166 | + [['(:tiles/vert (map :tiles/slot :tiles/slot)) |
| 167 | + '(:tiles/vert (fn [x] :tiles/slot)) |
| 168 | + 'e |
| 169 | + 'x |
| 170 | + '(conj :tiles/slot :tiles/slot) |
| 171 | + 'result |
| 172 | + ] |
| 173 | + ['(:tiles/vert (fn [result e] :tiles/slot)) |
| 174 | + '(:tiles/vert (into :tiles/slot :tiles/slot)) |
| 175 | + 'result] |
| 176 | + ['(:tiles/vert (reduce :tiles/slot :tiles/slot :tiles/slot)) |
| 177 | + '(hash-set #{}) |
| 178 | + 'original-set]])) |
| 179 | + |
| 180 | + |
| 181 | +(kind/hiccup (create-ws "ps" "500px")) |
0 commit comments