Martin Escardo, Paulo Oliva, 27th November 2024 - 14th May 2025

We define optimal moves and optimal plays for sequential games. Then
using the JT monad, with T the monad List⁺ of non-empty lists, we
compute all optimal plays of a game, provided it has ordinary
selection functions.

\begin{code}

{-# OPTIONS --safe --without-K #-}

open import MLTT.Spartan hiding (J)
open import UF.FunExt
open import UF.DiscreteAndSeparated

\end{code}

We work with a type of outcomes R with decidable equality (called
discreteness).

\begin{code}

module Games.OptimalPlays
        (fe : Fun-Ext)
        (R  : Type)
        (R-is-discrete : is-discrete R)
       where

open import Games.FiniteHistoryDependent R
open import Games.TypeTrees
open import MLTT.List hiding ([_]) renaming (map to lmap)
open import MonadOnTypes.J-transf-variation
open import MonadOnTypes.JK
open import MonadOnTypes.K
open import MonadOnTypes.List
open import MonadOnTypes.Monad
open import MonadOnTypes.NonEmptyList
open import Notation.CanonicalMap
open import UF.Base
open import UF.Subsingletons

open K-definitions R

\end{code}

The following are the main two notions considered in this file.

\begin{code}

is-optimal-move : {X : Type}
                  {Xf : X  𝑻}
                  (q : (Σ x  X , Path (Xf x))  R)
                  (ϕ : K X)
                  (ϕf : (x : X)  𝓚 (Xf x))
                 X
                 Type
is-optimal-move {X} {Xf} q ϕ ϕf x =
 optimal-outcome (game (X  Xf) q (ϕ :: ϕf))
  optimal-outcome (game (Xf x) (subpred q x) (ϕf x))

is-optimal-play : {Xt : 𝑻}  𝓚 Xt  (Path Xt  R)  Path Xt  Type
is-optimal-play {[]}     ⟨⟩        q ⟨⟩        = 𝟙
is-optimal-play {X  Xf} (ϕ :: ϕf) q (x :: xs) =
   is-optimal-move {X} {Xf} q ϕ ϕf x
 × is-optimal-play {Xf x} (ϕf x) (subpred q x) xs

\end{code}

Being an optimal move is a decidable proposition.

\begin{code}

being-optimal-move-is-prop : {X : Type}
                             {Xf : X  𝑻}
                             (q : (Σ x  X , Path (Xf x))  R)
                             (ϕ : K X)
                             (ϕf : (x : X)  𝓚 (Xf x))
                             (x : X)
                            is-prop (is-optimal-move q ϕ ϕf x)
being-optimal-move-is-prop q ϕ ϕf x = discrete-types-are-sets R-is-discrete

being-optimal-move-is-decidable : {X : Type}
                                  {Xf : X  𝑻}
                                  (q : (Σ x  X , Path (Xf x))  R)
                                  (ϕ : K X)
                                  (ϕf : (x : X)  𝓚 (Xf x))
                                  (x : X)
                                 is-decidable (is-optimal-move q ϕ ϕf x)
being-optimal-move-is-decidable q ϕ ϕf x = R-is-discrete _ _

\end{code}



We now show that the strategic path of a strategy in subgame perfect
equilibrium is an optimal play. We start with a lemma that is
interesting on its own right.

\begin{code}

optimal-play-gives-optimal-outcome
 : {Xt : 𝑻}
   (ϕt : 𝓚 Xt)
   (q : Path Xt  R)
   (xs : Path Xt)
  is-optimal-play {Xt} ϕt q xs
  q xs  optimal-outcome (game Xt q ϕt)
optimal-play-gives-optimal-outcome {[]}     ⟨⟩        q ⟨⟩        ⟨⟩ = refl
optimal-play-gives-optimal-outcome {X  Xf} (ϕ :: ϕf) q (x :: xs) (o :: os)
 = subpred q x xs                                     =⟨ IH 
   optimal-outcome (game (Xf x) (subpred q x) (ϕf x)) =⟨ o ⁻¹ 
   optimal-outcome (game (X  Xf) q (ϕ :: ϕf))        
 where
  IH : subpred q x xs  optimal-outcome (game (Xf x) (subpred q x) (ϕf x))
  IH = optimal-play-gives-optimal-outcome {Xf x} (ϕf x) (subpred q x) xs os

strategic-path-is-optimal-play
 : {Xt : 𝑻}
   (ϕt : 𝓚 Xt)
   (q : Path Xt  R)
   (σ : Strategy Xt)
  is-in-sgpe ϕt q σ
  is-optimal-play ϕt q (strategic-path σ)
strategic-path-is-optimal-play {[]} ⟨⟩ q ⟨⟩ ⟨⟩ = 
strategic-path-is-optimal-play {X  Xf} ϕt@(ϕ :: ϕf) q σ@(x₀ :: σf) ot@(o :: os)
 = I , IH x₀
 where
  IH : (x : X)  is-optimal-play (ϕf x) (subpred q x) (strategic-path (σf x))
  IH x = strategic-path-is-optimal-play {Xf x} (ϕf x) (subpred q x) (σf x) (os x)

  I : is-optimal-move q ϕ ϕf x₀
  I = optimal-outcome (game (X  Xf) q (ϕ :: ϕf))                  =⟨ refl 
      sequenceᴷ {X  Xf} (ϕ :: ϕf) q                               =⟨ refl 
      ϕ  x  sequenceᴷ (ϕf x) (subpred q x))                     =⟨ refl 
      ϕ  x  optimal-outcome (game (Xf x) (subpred q x) (ϕf x))) =⟨ I₁ 
      ϕ  x  subpred q x (strategic-path (σf x)))                =⟨ o ⁻¹ 
      q (strategic-path σ)                                         =⟨ refl 
      subpred q x₀ (strategic-path (σf x₀))                        =⟨ I₂ 
      optimal-outcome (game (Xf x₀) (subpred q x₀) (ϕf x₀))        
       where
        I₀ : (x : X)
            optimal-outcome (game (Xf x) (subpred q x) (ϕf x))
            subpred q x (strategic-path (σf x))
        I₀ x = (optimal-play-gives-optimal-outcome
                 (ϕf x) (subpred q x) (strategic-path (σf x)) (IH x))⁻¹

        I₁ = ap ϕ (dfunext fe I₀)
        I₂ = optimal-play-gives-optimal-outcome
              (ϕf x₀) (subpred q x₀) (strategic-path (σf x₀)) (IH x₀)

\end{code}

We now proceed to compute the non-empty list of all optimal plays of a
game, under suitable assumptions on the game.

The algebras of the nonempty list monad 𝕃⁺ are the semigroups
(associative magmas). We work with the magma structure on R defined by
x · y = x. Concretely, this amounts to the following construction.

\begin{code}

𝓐 : Algebra 𝕃⁺ R
𝓐 = record {
     structure-map = head⁺ ;
     aunit = u ;
     aassoc = a
    }
 where
  u : head⁺  η 𝕃⁺  id
  u r = refl

  a : head⁺  ext 𝕃⁺ (η 𝕃⁺  head⁺)  head⁺  ext 𝕃⁺ id
  a ((((r  _) , _)  _) , _) = refl

open T-definitions 𝕃⁺
open α-definitions 𝕃⁺ R 𝓐
open JT-definitions 𝕃⁺ R 𝓐 fe
open JK R

\end{code}

Ordinary selection functions are of type J X := (X → R) → X. Here we
work with JT defined as follows.

\begin{code}

JT-remark : JT  λ X  (X  R)  List⁺ X
JT-remark = by-definition

\end{code}

Every algebra α of any monad T induces an extension operator α­extᵀ,
which for the case T = List⁺ with the algebra defined above is
characterized as follows.

\begin{code}

α-extᵀ-explicitly : {X : Type} (p : X  R) (t : List⁺ X)
                   α-extᵀ p t  p (head⁺ t)
α-extᵀ-explicitly p ((x  _) :: _) = refl

\end{code}

We now construct a JT-selection function ε⁺ from an ordinary
J-selection function ε that attains a quantifier ϕ, for any listed
type X with at least one element.

Recall that we say that a type is listed⁺ if it has a distinguished
element and a list of all its elements (which will automatically
include the distinguished element).

\begin{code}

module _ (X : Type)
         (X-is-listed⁺@(x₀ , xs , μ) : listed⁺ X)
         (ϕ : (X  R)  R)
      where

 private
  A : (X  R)  X  Type
  A p x = p x  ϕ p

  δA : (p : X  R) (x : X)  is-decidable (A p x)
  δA p x = R-is-discrete (p x) (ϕ p)

 εᴸ :  (X  R)  List X
 εᴸ p = filter (A p) (δA p) xs

 εᴸ-property→ : (p : X  R) (x : X)  member x (εᴸ p)  p x  ϕ p
 εᴸ-property→ p x = filter-member→ (A p) (δA p) x xs

 εᴸ-property← : (p : X  R) (x : X)  p x  ϕ p  member x (εᴸ p)
 εᴸ-property← p x e = filter-member← (A p) (δA p) x xs e (μ x)

 module _ (ε : (X  R)  X)
          (ε-attains-ϕ : ε attains ϕ)
        where

  ε-member-of-εᴸ : (p : X  R)  member (ε p) (εᴸ p)
  ε-member-of-εᴸ p = filter-member← (A p) (δA p) (ε p) xs (ε-attains-ϕ p) (μ (ε p))

  εᴸ-is-non-empty : (p : X  R)  is-non-empty (εᴸ p)
  εᴸ-is-non-empty p = lists-with-members-are-non-empty (ε-member-of-εᴸ p)

  ε⁺ : JT X
  ε⁺ p = εᴸ p , εᴸ-is-non-empty p

\end{code}

We now extend this to trees of selection functions that attain
quantifiers.

\begin{code}

𝓙𝓣 : 𝑻  Type
𝓙𝓣 = structure JT

εt⁺ : (Xt : 𝑻)
     structure listed⁺ Xt
     (ϕt : 𝓚 Xt)
     (εt : 𝓙 Xt)
     εt Attains ϕt
     𝓙𝓣 Xt
εt⁺ [] ⟨⟩ ⟨⟩ ⟨⟩ ⟨⟩ = ⟨⟩
εt⁺ (X  Xf) (l :: lf) (ϕ :: ϕf) (ε :: εf) (a :: af) =
 ε⁺ X l ϕ ε a ::  x  εt⁺ (Xf x) (lf x) (ϕf x) (εf x) (af x))

open List⁺-definitions

\end{code}

We now prove a couple of technical lemmas.

\begin{code}

module _ {X : Type} {Xf : X  𝑻}
         (e⁺ : JT X)
         (d⁺ : (x : X)  JT (Path (Xf x)))
         (q : Path (X  Xf)   R)
       where

 private
  g : (x : X)  T (Path (Xf x))
  g x = d⁺ x (subpred q x)

  f : X  R
  f x = α-extᵀ (subpred q x) (g x)

  xt : T X
  xt = e⁺ f

  x : X
  x = head⁺ xt

  xs : Path (Xf x)
  xs = head⁺ (g x)

 head⁺-of-⊗ᴶᵀ : head⁺ ((e⁺ ⊗ᴶᵀ d⁺) q)  x :: xs
 head⁺-of-⊗ᴶᵀ =
  head⁺ ((e⁺ ⊗ᴶᵀ d⁺) q)                                         =⟨ I 
  head⁺ (xt ⊗ᴸ⁺ g)                                              =⟨ II 
  head⁺ (concat⁺ (lmap⁺  x  lmap⁺  y  x :: y) (g x)) xt)) =⟨ III 
  head⁺ (head⁺ (lmap⁺  x  lmap⁺  y  x :: y) (g x)) xt))   =⟨ IV 
  head⁺ (lmap⁺ (head⁺ xt ::_) (g (head⁺ xt)))                   =⟨ refl 
  head⁺ (lmap⁺ (x ::_) (g x))                                   =⟨ V 
  x :: head⁺ (g x)                                              =⟨ refl 
  x :: xs                                                       
   where
    I   = ap head⁺ (⊗ᴶᵀ-in-terms-of-⊗ᵀ e⁺ d⁺ q fe)
    II  = ap head⁺ (⊗ᴸ⁺-explicitly fe (e⁺ f) g)
    III = head⁺-of-concat⁺ (lmap⁺  x  lmap⁺  y  x :: y) (g x)) xt)
    IV  = ap head⁺ (head⁺-of-lmap⁺  x  lmap⁺  y  x :: y) (g x)) xt)
    V   = head⁺-of-lmap⁺ (x ::_) (g x)

JT-in-terms-of-K : (Xt : 𝑻)
                   (ϕt : 𝓚 Xt)
                   (q : Path Xt  R)
                   (εt : 𝓙 Xt)
                   (at : εt Attains ϕt)
                   (lt : structure listed⁺ Xt)
                  α-extᵀ q (path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q)
                  path-sequence (𝕂 R) ϕt q
JT-in-terms-of-K [] ϕt q εt at lt = refl
JT-in-terms-of-K Xt@(X  Xf) ϕt@(ϕ :: ϕf) q εt@(ε :: εf) at@(a :: af) lt@(l :: lf) = II
 where
  d⁺ : (x : X)  JT (Path (Xf x))
  d⁺ x = path-sequence 𝕁𝕋 (εt⁺ (Xf x) (lf x) (ϕf x) (εf x) (af x))

  f : (x : X)  List⁺ (Path (Xf x))
  f x = d⁺ x (subpred q x)

  p : X  R
  p x = α-extᵀ (subpred q x) (f x)

  IH : (x : X)  p x  path-sequence (𝕂 R) (ϕf x) (subpred q x)
  IH x = JT-in-terms-of-K (Xf x) (ϕf x) (subpred q x) (εf x) (af x) (lf x)

  e⁺ : JT X
  e⁺ = ε⁺ X l ϕ ε a

  x : X
  x = head⁺ (e⁺ p)

  I : member x (ι (e⁺ p))
  I = head⁺-is-member (e⁺ p)

  II = α-extᵀ q ((e⁺ ⊗ᴶᵀ d⁺) q)                           =⟨ II₀ 
       q (head⁺ ((e⁺ ⊗ᴶᵀ d⁺) q))                          =⟨ II₁ 
       q (x :: head⁺ (f x))                               =⟨ II₂ 
       p x                                                =⟨ II₃ 
       ϕ p                                                =⟨ II₄ 
       ϕ  x  path-sequence (𝕂 R) (ϕf x) (subpred q x)) =⟨ refl 
       (ϕ ⊗[ 𝕂 R ]  x  path-sequence (𝕂 R) (ϕf x))) q  
        where
         II₀ = α-extᵀ-explicitly q ((e⁺ ⊗[ 𝕁𝕋 ] d⁺) q)
         II₁ = ap q (head⁺-of-⊗ᴶᵀ e⁺ d⁺ q)
         II₂ = (α-extᵀ-explicitly (subpred q x) (f x))⁻¹
         II₃ = εᴸ-property→ X l ϕ p x I
         II₄ = ap ϕ (dfunext fe IH)

\end{code}

We now show that path-sequence 𝕁𝕋 computes the non-empty list of all
optimal plays.

\begin{code}

main-lemma→ : (Xt : 𝑻)
              (ϕt : 𝓚 Xt)
              (q : Path Xt  R)
              (εt : 𝓙 Xt)
              (at : εt Attains ϕt)
              (lt : structure listed⁺ Xt)
              (xs : Path Xt)
             member xs (ι (path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q))
             is-optimal-play ϕt q xs
main-lemma→ [] ⟨⟩ q ⟨⟩ ⟨⟩ ⟨⟩ ⟨⟩ in-head = ⟨⟩
main-lemma→ Xt@(X  Xf) ϕt@(ϕ :: ϕf) q εt@(ε :: εf) at@(a :: af)
            lt@(l :: lf) (x :: xs) m =
 head-is-optimal-move , tail-is-optimal-play
 where
  e⁺ : JT X
  e⁺ = ε⁺ X l ϕ ε a

  d⁺ : (x : X)  JT (Path (Xf x))
  d⁺ x = path-sequence 𝕁𝕋 (εt⁺ (Xf x) (lf x) (ϕf x) (εf x) (af x))

  t : List⁺ X
  t = τ e⁺ d⁺ q

  tf : (x : X)  T (Path (Xf x))
  tf x = d⁺ x (subpred q x)

  p : X  R
  p x = path-sequence (𝕂 R) (ϕf x) (subpred q x)

  p' : X  R
  p' x = α-extᵀ
          (subpred q x)
          (path-sequence 𝕁𝕋
            (εt⁺ (Xf x) (lf x) (ϕf x) (εf x) (af x))
            (subpred q x))

  I : path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q  t ⊗ᴸ⁺ tf
  I = ⊗ᴶᵀ-in-terms-of-⊗ᵀ e⁺ d⁺ q fe

  II : member (x :: xs) (ι (t ⊗ᴸ⁺ tf))
  II = transport (member (x :: xs)) (ap ι I) m

  III : member x (ι t)
  III = pr₁ (split-membership fe x xs t tf II)

  IV : member xs (ι (tf x))
  IV = pr₂ (split-membership fe x xs t tf II)

  V : p'  p
  V x = JT-in-terms-of-K (Xf x) (ϕf x) (subpred q x) (εf x ) (af x) (lf x)

  VI : t  e⁺ p
  VI = ap e⁺ (dfunext fe V)

  VII : member x (ι (e⁺ p))
  VII = transport  -  member x (ι -)) VI III

  head-is-optimal-move =
   ϕ p                                      =⟨ VIII 
   p x                                      =⟨ refl 
   path-sequence (𝕂 R) (ϕf x) (subpred q x) 
    where
     VIII = (εᴸ-property→ X l ϕ p x VII)⁻¹

  IH : member xs (ι (tf x))
      is-optimal-play (ϕf x) (subpred q x) xs
  IH = main-lemma→ (Xf x) (ϕf x) (subpred q x) (εf x) (af x) (lf x) xs

  tail-is-optimal-play : is-optimal-play (ϕf x) (subpred q x) xs
  tail-is-optimal-play = IH IV

main-lemma← : (Xt : 𝑻)
              (ϕt : 𝓚 Xt)
              (q : Path Xt  R)
              (εt : 𝓙 Xt)
              (at : εt Attains ϕt)
              (lt : structure listed⁺ Xt)
              (xs : Path Xt)
             is-optimal-play ϕt q xs
             member xs (ι (path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q))
main-lemma← [] ⟨⟩ q ⟨⟩ ⟨⟩ ⟨⟩ ⟨⟩  = in-head
main-lemma← Xt@(X  Xf) ϕt@(ϕ :: ϕf) q εt@(ε :: εf) at@(a :: af)
            lt@(l :: lf) (x :: xs) (om , op) = VI
 where
  p : X  R
  p x = path-sequence (𝕂 R) (ϕf x) (subpred q x)

  e⁺ : JT X
  e⁺ = ε⁺ X l ϕ ε a

  d⁺ : (x : X)  JT (Path (Xf x))
  d⁺ x = path-sequence 𝕁𝕋 (εt⁺ (Xf x) (lf x) (ϕf x) (εf x) (af x))

  t : List⁺ X
  t = τ e⁺ d⁺ q

  tf : (x : X)  T (Path (Xf x))
  tf x = d⁺ x (subpred q x)

  p' : X  R
  p' x = α-extᵀ (subpred q x) (tf x)

  IH : member xs (ι (tf x))
  IH = main-lemma← (Xf x) (ϕf x) (subpred q x) (εf x) (af x) (lf x) xs op

  I : p  p'
  I = dfunext fe
        x  (JT-in-terms-of-K (Xf x) (ϕf x) (subpred q x) (εf x) (af x) (lf x))⁻¹)

  II : p' x  ϕ p'
  II = transport  -  - x  ϕ -) I (om ⁻¹)

  III : member x (ι t)
  III = εᴸ-property← X l ϕ p' x II

  IV : member (x :: xs) (ι (t ⊗ᴸ⁺ tf))
  IV = join-membership fe x xs t tf (III , IH)

  V : ι (t ⊗ᴸ⁺ tf)  ι (path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q)
  V = (ap ι (⊗ᴶᵀ-in-terms-of-⊗ᵀ e⁺ d⁺ q fe))⁻¹

  VI : member (x :: xs) (ι (path-sequence 𝕁𝕋 (εt⁺ Xt lt ϕt εt at) q))
  VI = transport (member (x :: xs)) V IV

\end{code}

To conclude, we package the above with a game as a parameter, where
the types of moves are listed, and where we are given attaining
selection functions for the quantifiers.

\begin{code}

module _ (G@(game Xt q ϕt) : Game)
         (Xt-is-listed⁺ : structure listed⁺ Xt)
         (εt : 𝓙 Xt)
         (εt-Attains-ϕt : εt Attains ϕt)
       where

 optimal-plays : List⁺ (Path Xt)
 optimal-plays = path-sequence 𝕁𝕋 (εt⁺ Xt Xt-is-listed⁺ ϕt εt εt-Attains-ϕt) q

 Theorem→ : (xs : Path Xt)  member xs (ι optimal-plays)  is-optimal-play ϕt q xs
 Theorem→ = main-lemma→ Xt ϕt q εt εt-Attains-ϕt Xt-is-listed⁺

 Theorem← : (xs : Path Xt)  is-optimal-play ϕt q xs  member xs (ι optimal-plays)
 Theorem← = main-lemma← Xt ϕt q εt εt-Attains-ϕt Xt-is-listed⁺

\end{code}

This concludes what we wished to construct and prove.

Remark. The assumption Xt-is-listed⁺ implies that the type R of
outcomes has at least one element.

\begin{code}

 r₀ : R
 r₀ = q (head⁺ optimal-plays)

\end{code}

In a previous version of this file, we instead assumed r₀ : R, and we
worked with "listed" instead of "listed⁺", but the listings were
automatically non-empty.

Added 24th September 2025.

\begin{code}

quantifiers-over-empty-types-are-not-attainable
 : {X : Type}
  is-empty X
  (ϕ : K X)
  ¬ is-attainable ϕ
quantifiers-over-empty-types-are-not-attainable e ϕ (ε , a)
 = e (ε (unique-from-𝟘  e))

\end{code}

TODO. It is not in general decidable whether a quantifier is attainable.

Added 17th September. We calculate the subtree of the game tree whose
paths are precisely the optimal plays of the original game.

\begin{code}

prune : (Xt : 𝑻)
        (q : Path Xt  R)
        (ϕt : 𝓚 Xt)
       𝑻
prune [] q ⟨⟩ = []
prune (X  Xf) q (ϕ :: ϕf) = (Σ x  X , is-optimal-move q ϕ ϕf x)
                             (x , o)  prune (Xf x) (subpred q x) (ϕf x))
\end{code}

Notice that it may happen that the pruned tree is non-empty, but all
the nodes in the tree are empty types of moves. So we can't use the
pruned tree to decide whether or not there is an optimal
play. However, if we further assume that the types of moves in the
original tree are listed, we can decide this, and, moreover, get the
list of all optimal plays from the pruned tree *without* assuming that
the quantifiers are attainable (as we did above).

Each path in the pruned tree is a path in the original tree.

\begin{code}

inclusion : {Xt : 𝑻}
            (q : Path Xt  R)
            (ϕt : 𝓚 Xt)
           Path (prune Xt q ϕt)
           Path Xt
inclusion {[]} q ⟨⟩ ⟨⟩ = ⟨⟩
inclusion {X  Xf} q (ϕ :: ϕf) ((x , _) :: xos)
 = x :: inclusion {Xf x} (subpred q x) (ϕf x) xos

\end{code}

The predicate q restricts to a predicate in the pruned tree.

\begin{code}

restriction : {Xt : 𝑻}
              (q : Path Xt  R)
              (ϕt : 𝓚 Xt)
             Path (prune Xt q ϕt)  R
restriction q ϕt = q  inclusion q ϕt

\end{code}

The paths in the pruned tree are precisely the optimals plays in the
original tree.

\begin{code}

lemma→ : {Xt : 𝑻}
         (q : Path Xt  R)
         (ϕt : 𝓚 Xt)
        (xos : Path (prune Xt q ϕt))
        is-optimal-play ϕt q (inclusion q ϕt xos)
lemma→ {[]} q ⟨⟩ ⟨⟩ = ⟨⟩
lemma→ {X  Xf} q (ϕ :: ϕf) ((x , o) :: xos)
 = o , lemma→ {Xf x} (subpred q x) (ϕf x) xos

lemma← : {Xt : 𝑻}
         (q : Path Xt  R)
         (ϕt : 𝓚 Xt)
         (xs : Path Xt)
        is-optimal-play ϕt q xs
        Σ xos  Path (prune Xt q ϕt) , inclusion q ϕt xos  xs
lemma← {[]} q ⟨⟩ ⟨⟩ ⟨⟩ = ⟨⟩ , refl
lemma← {X  Xf} q (ϕ :: ϕf) (x :: xs) (o :: os)
 = ((x , o) :: pr₁ IH) , ap (x ::_) (pr₂ IH)
 where
  IH : Σ xos  Path (prune (Xf x) (subpred q x) (ϕf x))
             , inclusion (subpred q x) (ϕf x) xos  xs
  IH = lemma← {Xf x} (subpred q x) (ϕf x) xs os

\end{code}

This gives an alternative way to calculate the list of optimal plays,
which doesn't use selection functions.

Added 8th October 2025.

TODO. Move the following general purpose functions on paths and on
lists to appropriate modules. Also think of better names for the
functions.

\begin{code}

module _ {X : Type}
         {Xf : X  𝑻}
       where

 prepend : (x : X)
          List (Path (Xf x))
          List (Path (X  Xf))
 prepend x [] = []
 prepend x (xs  xss) = (x :: xs)  prepend x xss

 map-prepend : ((x : X)  List (Path (Xf x)))
              List X
              List (List (Path (X  Xf)))
 map-prepend f [] = []
 map-prepend f (x  xs) = prepend x (f x)  map-prepend f xs

 map-concat-prepend : ((x : X)  List (Path (Xf x)))
                     List X
                     List (Path (X  Xf))
 map-concat-prepend f [] = []
 map-concat-prepend f (x  xs) = prepend x (f x) ++ map-concat-prepend f xs


list-of-paths : (Xt : 𝑻)
                (Xt-is-listed : structure listed Xt)
               List (Path Xt)
list-of-paths [] ⟨⟩ = []
list-of-paths (X  Xf) ((xs , m) , Xf-is-listed) = map-concat-prepend IH xs
 where
  IH : (x : X)  List (Path (Xf x))
  IH x = list-of-paths (Xf x) (Xf-is-listed x)

conditionally-prepend : {X : 𝓤 ̇ } (A : X  𝓥 ̇ )
                       (x : X)
                       A x + ¬ A x
                       List (Σ x  X , A x)
                       List (Σ x  X , A x)
conditionally-prepend A x (inl a) ys = (x , a)  ys
conditionally-prepend A x (inr _) ys = ys


filter' : {X : 𝓤 ̇ }
          (A : X  𝓥 ̇ )
         ((x : X)  A x + ¬ A x)
         List X
         List (Σ x  X , A x)
filter' A δ []       = []
filter' A δ (x  xs) = conditionally-prepend A x (δ x) (filter' A δ xs)

filter'-member← : {X : 𝓤 ̇ }
                  (A : X  𝓥 ̇ )
                  (δ : (x : X)  A x + ¬ A x)
                  (A-is-prop-valued : (x : X)  is-prop (A x))
                  (y : X)
                  (xs : List X)
                  (a : A y)
                 member y xs
                 member (y , a) (filter' A δ xs)
filter'-member← {𝓤} {𝓥} {X} A δ A-is-prop-valued y (x  xs) = h x xs (δ x)
 where
  h : (x : X)
      (xs : List X)
     (d : A x + ¬ A x)
      (a : A y)
     member y (x  xs)
     member (y , a) (conditionally-prepend A x d (filter' A δ xs))
  h x xs (inl b) a in-head = II
   where
    I : member (y , a) ((y , a)  filter' A δ xs)
    I = in-head

    II : member (y , a) ((y , b)  filter' A δ xs)
    II = transport
           -  member (y , a) ((y , -)  filter' A δ xs))
          (A-is-prop-valued y a b)
          I
  h x (x'  xs) (inl b) a (in-tail m) = in-tail (h x' xs (δ x') a m)
  h x xs (inr r) a in-head = 𝟘-elim (r a)
  h x xs (inr x₁) a (in-tail m) = filter'-member← A δ A-is-prop-valued y xs a m

detachable-subtype-of-listed-type-is-listed
 : {X : Type}
  (A : X  Type)
  ((x : X)  is-decidable (A x))
  ((x : X)  is-prop (A x))
  listed X
  listed (Σ x  X , A x)
detachable-subtype-of-listed-type-is-listed {X} A δ A-is-prop-valued (xs , m)
 = filter' A δ xs , γ
 where
  γ : (σ : Σ x  X , A x)  member σ (filter' A δ xs)
  γ (x , a) = filter'-member← A δ A-is-prop-valued x xs a (m x)

prune-is-listed : (Xt : 𝑻)
                  (q : Path Xt  R)
                  (ϕt : 𝓚 Xt)
                 structure listed Xt
                 structure listed (prune Xt q ϕt)
prune-is-listed [] q ϕt ⟨⟩ = ⟨⟩
prune-is-listed (X  Xf) q (ϕ :: ϕf) (X-is-listed , Xf-is-listed) =
 X'-is-listed :: Xf'-is-listed
 where
  X' : Type
  X' = Σ x  X , is-optimal-move q ϕ ϕf x

  X'-is-listed : listed X'
  X'-is-listed = detachable-subtype-of-listed-type-is-listed
                  (is-optimal-move q ϕ ϕf)
                  (being-optimal-move-is-decidable q ϕ ϕf)
                  (being-optimal-move-is-prop q ϕ ϕf)
                  X-is-listed

  Xf' : X'  𝑻
  Xf' (x , o) = prune (Xf x) (subpred q x) (ϕf x)

  Xf'-is-listed : (x' : X')  structure listed (Xf' x')
  Xf'-is-listed (x , o) = prune-is-listed
                           (Xf x)
                           (subpred q x)
                           (ϕf x)
                           (Xf-is-listed x)

optimal-plays' : {Xt : 𝑻}
                 (q : Path Xt  R)
                 (ϕt : 𝓚 Xt)
                 (Xt-is-listed : structure listed Xt)
                List (Path Xt)
optimal-plays' {Xt} q ϕt Xt-is-listed = xss
 where
  Xt' : 𝑻
  Xt' = prune Xt q ϕt

  xss' : List (Path (prune Xt q ϕt))
  xss' = list-of-paths Xt' (prune-is-listed Xt q ϕt Xt-is-listed)

  xss : List (Path Xt)
  xss = lmap (inclusion q ϕt) xss'

\end{code}

Notice that this way of computing the optimal plays doesn't need the
assumption that the quantifiers are attainable.

TODO. Prove that optimal-plays' lists precisely the optimal plays.