JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html>

  <head>
    <script src="https://cdn.jsdelivr.net/npm/scittle-hoplon@0.0.1/dist/scittle.js" type="application/javascript"></script>
    <script src="https://cdn.jsdelivr.net/npm/scittle-hoplon@0.0.1/dist/scittle.javelin.js" type="application/javascript"></script>
    <script src="https://cdn.jsdelivr.net/npm/scittle-hoplon@0.0.1/dist/scittle.hoplon.js" type="application/javascript"></script>
    <script type="application/x-scittle">
      (require
 '[hoplon.core :as h]
 '[javelin.core :refer [cell cell= defc defc= dosync]])

(def transpose (partial apply map vector))
(def diagonal  (partial map (comp first drop) (range)))
(def indexed   (partial map-indexed vector))
(def new-game  (vec (repeat 9 nil)))

(defc  game      new-game)
(defc  undos     ())
(defc= rows      (partition 3 game))
(defc= columns   (transpose rows))
(defc= diagonals [(diagonal rows) (diagonal (map reverse rows))])
(defc= runs      (concat rows columns diagonals))
(defc= winner    (->> runs
                      (map set)
                      (remove #(contains? % nil))
                      (filter #(= 1 (count %)))
                      ffirst))
(defc= moves     (->> (indexed game)
                      (filter (comp nil? second))
                      (map first)))
(defc= no-moves? (not (seq moves)))
(defc= over      (cond winner    (str winner " won!")
                       no-moves? "Cat's game."))

(defn undo! []
  (when (seq @undos)
    (reset! game (peek @undos))
    (swap! undos pop)))

(defn ai! []
  (when-not @over
    (swap! game assoc (rand-nth @moves) "O")))

(defn play! [i j]
  (let [idx (+ (* i 3) j)]
    (when (and (not @over) (nil? (get @game idx)))
      (swap! undos conj @game)
      (swap! game assoc idx "X"))))

(defn reset-game! []
  (reset! game new-game)
  (reset! undos ()))

(h/body
  (h/div
    (h/table :class "tictac"
      (h/for-tpl [[i row] (cell= (indexed rows))]
        (h/tr
          (h/for-tpl [[j x] (cell= (indexed row))]
       ...

CSS

body {
  font-family: sans-serif;
  color: #333;
}

pre {
  padding: 10px;
  background-color: black;
  color: chartreuse;
}

table.tictac {
  border-collapse: collapse;
  border: 5px solid black;
  margin-right: 20px;
}

table.score {
  border-collapse: collapse;
  padding-left: 20px;
}

table.score th {
  padding: 5px;
  border-bottom: 2px solid black;
}

table.score td {
  padding: 5px;
}

table.tictac td {
  border:         5px solid black;
  cursor:         pointer;
  width:          1.3em;
  height:         1.3em;
  text-align:     center;
  vertical-align: middle;
  font:           bold 36px sans-serif
}