Finn Völkel / Jun 09 2020
with  Arne Brasseur
Arne Brasseur
Tic Tac Toe
This notebook exemplifies the usage of tap support together with our MIME viewers for playing Tic Tac Toe.
{:deps {hiccup {:mvn/version "1.0.5"}}}deps.edn
Extensible Data Notation
(ns tictactoe.core)(use hiccup.core)1.6s
Clojure
nil
(defn game-board [states]  {:nextjournal/viewer :html   :nextjournal/tap-id :tic   :nextjournal.viewer/value   (html [:div {:class "flex flex-wrap -mx-1"}          (for [state states]            [:div {:class "my-1 px-1 w-1/3 overflow-hidden"} state])])})0.1s
Clojure
'tictactoe.core/game-board
The code for the logic of tic tac toe is copied from @trptcolin's tictactoe-clojure repo.
(def win-sets  [[0 1 2], [3 4 5], [6 7 8], [0 3 6], [1 4 7], [2 5 8], [0 4 8], [2 4 6]])(defn- winner-exists-on-spaces? [board spaces]  (and    (apply = (map (board %) spaces))    (not (= "#" (board (first spaces))))))(defn- winner-on-spaces [board spaces]  (if (winner-exists-on-spaces? board spaces)    (board (first spaces))    nil))(defn- indexed [coll]  (map vector coll (iterate inc 0)))(defn- index-filter [pred coll]  (for [[spot i] (indexed coll) :when (pred spot)] i));;; public functions(defn make-board [] (vec (repeat 9 "#")))(defn empty-square? [square]  (= "#" square))(defn full? [board] (not-any? empty-square? board))(defn winner [board] (some (winner-on-spaces board %) win-sets))(defn game-over? [board] (boolean (or (winner board) (full? board))))(defn place-on-board [board spot mark] (assoc board spot mark))(defn next-mark [mark] (if (= "X" mark) "O" "X"))(defn valid-move? [board move]  (try (= (board move) "#")    (catch Exception e false)))(defn final-message [winner]  (if (nil? winner)    "Cat's Game!"    (str winner " Wins!!!")))(defn empty-squares [board]  (index-filter empty-square? board))0.5s
Clojure
'tictactoe.core/empty-squares
(def :dynamic board (make-board))(def :dynamic player "X")0.0s
Clojure
'tictactoe.core/player
(defn play [move]  (println "It's players " player "turn!")  (println "Player " player "has chosen move" move)  (cond     (valid-move? board move)    (do       (alter-var-root (var board) place-on-board move player)      (tap> (game-board board))      (if-some [gewinner (winner board)]        (println "The winner is :" gewinner)        (do           (println "No winner yet! Continue!")          (alter-var-root (var player) next-mark))))              :else    (println "Invalid move! Try again player " player)))0.0s
Clojure
'tictactoe.core/play
We tap the empty game board to initialize our viewer. # means an empty cell. X and O mean the cell was marked by player 1 and player 2 respectively.
(tap> (game-board board))0.0s
Clojure
X
O
#
#
#
#
#
#
#
true
Type a number from 0 to 8 to make your move.
(play 1)0.8s
Clojure
"X"