Martin Escardo, Paulo Oliva, 2-27 July 2021

Example: Tic-tac-toe. We have two versions. The other version is in
another file.

\begin{code}

{-# OPTIONS --safe --without-K --no-exact-split #-}


module Games.TicTacToe2 where

open import MLTT.Spartan hiding (J)
open import MLTT.Fin

data πŸ› : Type where
 O-wins draw X-wins : πŸ›

open import Games.Constructor πŸ›
open import Games.FiniteHistoryDependent πŸ›
open import Games.TypeTrees
open import Games.J
open import MLTT.Athenian

open list-util

tic-tac-toeβ‚‚J : GameJ
tic-tac-toeβ‚‚J = build-GameJ draw Board transition 9 boardβ‚€
 where
  flip : πŸ› β†’ πŸ›
  flip O-wins = X-wins
  flip draw   = draw
  flip X-wins = O-wins

  data Player : Type where
   O X : Player

  Cell = Fin 9

  record Board : Type where
   pattern
   constructor board
   field
    next-player     : Player
    available-moves : List Cell
    X-moves         : List Cell
    O-moves         : List Cell

  open Board

  opponent-wins : Player β†’ πŸ›
  opponent-wins X = O-wins
  opponent-wins O = X-wins

  winning : List Cell β†’ Bool
  winning = some-contained ((𝟎 ∷ 𝟏 ∷ 𝟐 ∷ [])
                          ∷ (πŸ‘ ∷ πŸ’ ∷ πŸ“ ∷ [])
                          ∷ (πŸ” ∷ πŸ• ∷ πŸ– ∷ [])
                          ∷ (𝟎 ∷ πŸ‘ ∷ πŸ” ∷ [])
                          ∷ (𝟏 ∷ πŸ’ ∷ πŸ• ∷ [])
                          ∷ (𝟐 ∷ πŸ“ ∷ πŸ– ∷ [])
                          ∷ (𝟎 ∷ πŸ’ ∷ πŸ– ∷ [])
                          ∷ (𝟐 ∷ πŸ’ ∷ πŸ” ∷ [])
                          ∷ [])

  wins : Board β†’ Bool
  wins (board O _ _  os) = winning os
  wins (board X _ xs  _) = winning xs

  boardβ‚€ : Board
  boardβ‚€ = board X (list-Fin 9) [] []

  Move : List Cell β†’ Type
  Move xs = Ξ£ c κž‰ Cell , ((c is-in xs) = true)

\end{code}

The following definition of argmax is somewhat convoluted because it
is optimized for time, by minimizing the number of evaluations of the
predicate q:

\begin{code}

  argmax : (m : Cell) (ms : List Cell) β†’ πŸ› β†’ (Move (m ∷ ms) β†’ πŸ›) β†’ Move (m ∷ ms)
  argmax m ms       X-wins  q = m , need m == m || (m is-in ms) = true
                                    which-is-given-by ||-left-intro _ (==-refl m)

  argmax m []       r       q = m , need m == m || (m is-in []) = true
                                    which-is-given-by ||-left-intro _ (==-refl m)

  argmax m (x ∷ xs) O-wins  q = ι γ
   where
    ΞΉ : Move (x ∷ xs) β†’ Move (m ∷ x ∷ xs)
    ι (c , e) = c , need c == m || (c is-in (x ∷ xs)) = true
                    which-is-given-by ||-right-intro {c == m} _ e

    q' : Move (x ∷ xs) β†’ πŸ›
    q' m = q (ΞΉ m)

    a : (x == m) || ((x == x) || (x is-in xs)) = true
    a = ||-right-intro {x == m} _ (||-left-intro _ (==-refl x))

    γ : Move (x ∷ xs)
    Ξ³ = argmax x xs (q (x , a)) q'

  argmax m us@(x ∷ ms) draw q = g us c
   where
    c : ((x == x) || (x is-in ms)) && (ms contained-in (x ∷ ms)) = true
    c = &&-intro (||-left-intro _ (==-refl x)) (contained-lemma₁ x ms)

    g : (vs : List Cell) β†’ vs contained-in us = true β†’ Move (m ∷ us)
    g []       c = m , need m == m || (m is-in (x ∷ ms)) = true
                       which-is-given-by ||-left-intro _ (==-refl m)

    g (y ∷ vs) c = k (q (y , a))
     where
      a : (y == m) || ((y == x) || (y is-in ms)) = true
      a = ||-right-intro {y == m} _ (pr₁ (&&-gives-Γ— c))

      b : (vs contained-in (x ∷ ms)) = true
      b = prβ‚‚ (&&-gives-Γ— c)

      k : πŸ› β†’ Move (m ∷ us)
      k X-wins = y , a
      k r      = g vs b

  open J-definitions πŸ›

  argmin : (m : Cell) (ms : List Cell) β†’ πŸ› β†’ (Move (m ∷ ms) β†’ πŸ›) β†’ Move (m ∷ ms)
  argmin m ms r q = argmax m ms (flip r) (Ξ» xs β†’ flip (q xs))

  arg : Player β†’ (ms : List Cell) β†’ empty ms = false β†’  J (Move ms)
  arg _ []       e q = 𝟘-elim (true-is-not-false e)
  arg X (m ∷ ms) e q = argmax m ms (q (m , ||-left-intro (m is-in ms) (==-refl m))) q
  arg O (m ∷ ms) e q = argmin m ms (q (m , ||-left-intro (m is-in ms) (==-refl m))) q

  play : (b : Board) β†’ Move (available-moves b) β†’ Board
  play (board X as xs os) (c , e) = board O (remove c as) (insert c xs) os
  play (board O as xs os) (c , e) = board X (remove c as) xs            (insert c os)

  transition : Board β†’ πŸ› + (Ξ£ M κž‰ Type , (M β†’ Board) Γ— J M)
  transition b@(board next as xs os) =
   if wins b
   then inl (opponent-wins next)
   else Bool-equality-cases (empty as)
         (Ξ» (_ : empty as = true)  β†’ inl draw)
         (Ξ» (e : empty as = false) β†’ inr (Move as , play b , arg next as e))

tic-tac-toeβ‚‚ : Game
tic-tac-toeβ‚‚ = Game-from-GameJ tic-tac-toeβ‚‚J

tβ‚‚ : πŸ›
tβ‚‚ = optimal-outcome tic-tac-toeβ‚‚

sβ‚‚ : Path (Xt tic-tac-toeβ‚‚)
sβ‚‚ = strategic-path (selection-strategy (selections tic-tac-toeβ‚‚J) (q tic-tac-toeβ‚‚))

uβ‚‚ : Path (Xt tic-tac-toeβ‚‚)
uβ‚‚ = sequenceα΄Ά (selections tic-tac-toeβ‚‚J) (q tic-tac-toeβ‚‚)

lβ‚‚ : β„•
lβ‚‚ = plength sβ‚‚

{- Slow

tβ‚‚-test : tβ‚‚ = draw
tβ‚‚-test = refl

-}

{- Slow:

lβ‚‚-test : lβ‚‚ = 9
lβ‚‚-test = refl

-}

{- slow


uβ‚‚-test : sβ‚‚ = (𝟎 :: refl)
           :: ((πŸ’ :: refl)
           :: ((𝟏 :: refl)
           :: ((𝟐 :: refl)
           :: ((πŸ” :: refl)
           :: ((πŸ‘ :: refl)
           :: ((πŸ“ :: refl)
           :: ((πŸ• :: refl)
           :: ((πŸ– :: refl)
           :: ⟨⟩))))))))
uβ‚‚-test = refl
-}

\end{code}