Finn Völkel / Jun 09 2020
with
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"