module Game-CoreInf where
-- in which we formalise the fundamentals of Game Semantics in Agda
-- but an infinitary version!

open import Data.Empty
open import Data.Unit
open import Data.Maybe
open import Data.Sum
open import Data.Product
open import Function
open import Relation.Binary.PropositionalEquality
open import Coinduction
open import Data.Nat renaming (_+_ to _+'_)

-- Games

-- At each level of the game, we have a set of possible moves. For
-- cardinality reasons, it is useful to restrict that set to one of
-- the following forms:

infixr 8 _⊹_
data MovEnc : Set where
  nil : MovEnc
  one : MovEnc
  _⊹_ : MovEnc → MovEnc → MovEnc
  ℕ× : MovEnc → MovEnc
-- where each constructor represents a set in the following manner:

T : MovEnc → Set
T nil      = ⊥
T one      = ⊤ 
T (x ⊹ y)  = T x ⊎ T y
T (ℕ× m)   = ℕ × T m 

-- So a game consists of an (encoded) set of moves, and for each move
-- a corresponding (delayed) "rest of the game":

data Game : Set where
  gam : {ι : MovEnc} → (T ι → ∞ Game) → Game

mvEnc : Game → MovEnc
mvEnc (gam {a} f) = a

Mov : Game → Set
Mov G = T (mvEnc G)

infix 10 _▸_
_▸_ : (G : Game) → Mov G → Game
(gam {ι} f) ▸ x = ♭ (f x)

-- Constructions on Games

I : Game
I = gam {nil} ⊥-elim

_×'_ : Game → Game → Game
gam {i} f ×' gam {j} g = gam {i ⊹ j} ([ f , g ])

infix 14 _⊗_
infix 12 _⊸_ _⊸̂_

mutual
  _⊸_ : Game → Game → Game
  G ⊸ (gam {i} f) = gam {i} (λ i' → ♯ (♭ (f i') ⊗ G))

  _⊗_ : Game → Game → Game
  (gam {i} f) ⊗ (gam {j} g) = gam {i ⊹ j} h
   where h : T (i ⊹ j) → ∞ Game
         h (inj₁ x) = ♯ (gam {j} g ⊸ ♭ (f x))
         h (inj₂ y) = ♯ (gam {i} f ⊸ ♭ (g y))

_⊘_ : Game → Game → Game
(gam {i} f) ⊘ G = gam {i} (λ i' → ♯ (G ⊸ (♭ $ f i')))

o : Game
o = gam {one} (λ _ → ♯ I)

bangΣ : Game
bangΣ = gam {one} (λ _ → ♯ bangΣ)

_⊸o : Game → Game
G ⊸o = gam {one} (λ tt → ♯ G)

ω× : Game → Game
ω× (gam {i} f) = gam {ℕ× i} (λ x → ♯ (♭ $ f (proj₂ x)))

-- ⊸̂ represents a strict function space:

_⊸̂_ : Game → Game → Game
G ⊸̂ (gam {i} f) = gam {i} (λ i' → ♯ (G ⊘ ♭ (f i')))

-- Exponential
-- bang G = G ⊘ bang G

data GameP : Set where
  gam : {ι : MovEnc} → (T ι → ∞ GameP) → GameP
  _⊸P_ : GameP → GameP → GameP
  _⊗P_ : GameP → GameP → GameP

data GameH : Set where
  gam : {ι : MovEnc} → (T ι → ∞ GameP) → GameH

HtoP : GameH → GameP
HtoP (gam {i} y) = gam {i} y

GtoP : Game → GameP
GtoP (gam {i} y) = gam {i} (λ x → ♯ (GtoP (♭ (y x))))

whnf : GameP → GameH
whnf (gam {i} y) = gam {i} y
whnf (y ⊸P y') = (whnf y) ⊸' (whnf y')
   where _⊸'_ : GameH → GameH → GameH
         G ⊸' gam {i} y = gam {i} (λ x → ♯ (♭ (y x) ⊗P (HtoP G)))
whnf (y ⊗P y') = (whnf y) ⊗' (whnf y')
   where _⊗'_ : GameH → GameH → GameH
         gam {i} z ⊗' gam {j} y = gam {i ⊹ j} [ (λ zi → ♯ ((gam {j} y) ⊸P (♭ (z zi)))) ,
                                                 (λ zi → ♯ ((gam {i} z) ⊸P (♭ (y zi)))) ]

mutual
  HtoG : GameH → Game
  HtoG (gam {i} y) = gam {i} (λ x → ♯ (PtoG (♭ (y x))))

  PtoG : GameP → Game
  PtoG g = HtoG (whnf g)
  
bangP : Game → GameP
bangP (gam {i} f) = gam {i} (λ x → ♯ (bangP (gam {i} f) ⊸P GtoP (♭ (f x))))

bang : Game → Game
bang g = PtoG $ bangP g

-- Strategies

{-
open import Data.Bool public
   renaming (true to -  ; false to +;
             Bool to Pol; not   to ¬;
             T to IsTrue)

open import Category.Monad.Partiality as P
open import Category.Functor
open import Category.Monad
open RawMonad P.monad using (_<$>_)

data Strat : Pol → Game → Set where
  pos : ∀ {G} → _⊥ (Σ (Mov G) (λ i → ∞ (Strat - (G ▸ i)))) → Strat + G
  neg : ∀ {G} → ((i : Mov G) → ∞ (Strat + (G ▸ i))) → Strat - G

swp' : ∀ {B} {C} → (Σ (T (mvEnc (C ⊗ B))) (λ i → ∞ (Strat - (C ⊗ B ▸ i))) →
         Σ (T (mvEnc (B ⊗ C))) (λ i → ∞ (Strat - (B ⊗ C ▸ i))))
swp' {gam f} {gam g} (inj₁ x , y') = inj₂ x , y'
swp' {gam f} {gam g} (inj₂ y' , y0) = inj₁ y' , y0

swp : ∀ {B C} → Strat + (C ⊗ B) → Strat + (B ⊗ C)
swp {B} {C} (pos y) = pos (swp' {B} {C} <$> y)

unpos : ∀ {G} → Strat + G → _⊥ (Σ (Mov G) (λ i → ∞ (Strat - (G ▸ i))))
unpos (pos y) = y

{-mutual
  _∙₁_ : ∀ {A B C} → Strat - (A ⊸ B) → Strat - (B ⊸ C) → Strat - (A ⊸ C)
  _∙₁_ {gam a} {gam b} {gam c} σ (neg g) = neg (λ c' → σ ∙₂ (g c'))

  _∙₂_ : ∀ {A B C} → Strat - (A ⊸ B) → Strat + (C ⊗ B) → Strat + (C ⊗ A)
  _∙₂_ {gam a} {gam b} {gam c} σ       (pos (inj₁ c') g) = pos (inj₁ c') (σ ∙₁ g)
  _∙₂_ {gam a} {gam b} {gam c} (neg f) (pos (inj₂ b') g) = swp $ g ∙₂ (swp $ f b')
-}

mutual
  _∙₁_ : ∀ {A B C} → Strat - (A ⊸ B) → Strat - (B ⊸ C) → Strat - (A ⊸ C)
  _∙₁_ {gam a} {gam b} {gam c} σ (neg g) = neg (λ c' → ♯ σ ∙₂ (♭ (g c')))

  _∙₂'_ : ∀ {A B C} → Strat - (A ⊸ B) →
             _⊥ (Σ (T (mvEnc (C ⊗ B))) (λ i → ∞ (Strat - (C ⊗ B ▸ i)))) →
              _⊥ (Σ (T (mvEnc (C ⊗ A))) (λ i → ∞ (Strat - (C ⊗ A ▸ i))))
  _∙₂'_ {gam a} {gam b} {gam c} σ (now (inj₁ x , y))
         = now (inj₁ x , ♯ σ ∙₁ ♭ y)
  _∙₂'_ {gam a} {gam b} {gam c} (neg y) (now (inj₂ y' , y0))
         = later (♯ (♭ y0) ∙₃' (unpos $ ♭ (y y')))
  _∙₂'_ {gam a} {gam b} {gam {i} c} σ (later x)
         = later (♯ _∙₂'_ {gam a} {gam b} {gam {i} c} σ (♭ x)) 

  _∙₃'_ : ∀ {A B C} → Strat - (A ⊸ B) →
             _⊥ (Σ (T (mvEnc (B ⊗ C))) (λ i → ∞ (Strat - (B ⊗ C ▸ i)))) →
              _⊥ (Σ (T (mvEnc (A ⊗ C))) (λ i → ∞ (Strat - (A ⊗ C ▸ i))))
  _∙₃'_ {gam a} {gam b} {gam c} σ (now (inj₂ x , y))
         = now (inj₂ x , ♯ σ ∙₁ ♭ y)
  _∙₃'_ {gam a} {gam b} {gam c} (neg y) (now (inj₁ y' , y0))
         = later (♯ ((♭ y0) ∙₂' (swp' {gam a} {♭ (b y')} <$> (unpos $ ♭ (y y')))))
  _∙₃'_ {gam a} {gam b} {gam {i} c} σ (later x)
         = later (♯ _∙₃'_ {gam a} {gam b} {gam {i} c} σ (♭ x)) 

  _∙₂_ : ∀ {A B C} → Strat - (A ⊸ B) → Strat + (C ⊗ B) → Strat + (C ⊗ A)
  _∙₂_ {A} {B} {C} σ (pos y) = pos (σ ∙₂' y)

-- If we consider a positive game Q, a P-strategy on Q is given by a
-- term of type Strat + Q.

-}

-- Game morphisms

-- An element of A ≲ B represents a copycat-shaped strategy on A ⊸ B,
-- but it is more convinient to work with and we need to define a lot
-- of these things.


infix 8 _≲_
data _≲_ : Game → Game → Set where
  sim : ∀ {A B} →
        (h : Mov A → Mov B) →
        ((i' : Mov A) → ∞ (B ▸ (h i') ≲ (A ▸ i'))) →
        A ≲ B

id≲ : ∀ {G} → G ≲ G
id≲ {gam f} = sim id (λ i → ♯ id≲ {♭ (f i)})


infixl 8 _≲∘≲_

_≲∘≲_ : ∀ {A B C} → A ≲ B → B ≲ C → A ≲ C
(sim f f') ≲∘≲ (sim g g') = sim (g ∘ f) (λ x → ♯ (♭ (g' (f x)) ≲∘≲ ♭ ((f' x))))


-- We bundle two-way copycat strategies into a ≈ structure.
-- This is how we represent isos.

infix 8 _≈_
data _≈_ : Game → Game → Set where
  bsm : ∀ {A B} → A ≲ B → B ≲ A → A ≈ B

infixl 8 _≈∘≈_

_≈∘≈_ : ∀ {A B C} → A ≈ B → B ≈ C → A ≈ C
(bsm s s') ≈∘≈ (bsm r r') = bsm (s ≲∘≲ r) (r' ≲∘≲ s')

id≈ : ∀ {G} → G ≈ G
id≈ = bsm id≲ id≲

infixr 9 _^-1

_^-1 : ∀ {M N} → M ≈ N → N ≈ M
(bsm f g) ^-1 = bsm g f

wk₁ : ∀ {M N} → M ≈ N → M ≲ N
wk₁ (bsm f g) = f

wk₂ : ∀ {M N} → M ≈ N → N ≲ M
wk₂ (bsm f g) = g


-- Composing morphisms with strategies

{-
infixr 8 _≲∘_ -- _≈∘_
infixl 8 _∘≲_ -- _∘≈_

mutual
  _≲∘_ : ∀ {M N} → M ≲ N → Strat - N → Strat - M
  (sim h h') ≲∘ (neg f) = neg (λ i → ♯ (♭ (f (h i)) ∘≲ ♭ (h' i)))

  _∘≲_ : ∀ {P Q} → Strat + P → P ≲ Q → Strat + Q
  _∘≲_ {P} {Q} (pos y) (sim h y') = pos (_∘≲'_ {P} {Q} y h y')

  _∘≲'_ : ∀ {P Q} → _⊥ (Σ (T (mvEnc P)) (λ i → ∞ (Strat - (P ▸ i)))) → 
               (h : T (mvEnc P) → T (mvEnc Q)) → ((i' : T (mvEnc P)) → ∞ (Q ▸ h i' ≲ P ▸ i'))
                   → _⊥ (Σ (Mov Q) (λ i → ∞ (Strat - (Q ▸ i))))
  _∘≲'_ {P} {Q} (now (x , y)) h y' = now (h x , (♯ (♭ (y' x) ≲∘ (♭ y))))
  _∘≲'_ {P} {Q} (later x) h y' = later (♯ (_∘≲'_ {P} {Q} (♭ x) h y'))

_≈∘_ : ∀ {M N} → M ≈ N → Strat - M → Strat - N
g ≈∘ σ = (wk₂ g) ≲∘ σ

_∘≈_ : ∀ {P Q} → Strat + P → P ≈ Q → Strat + Q
σ ∘≈ f = σ ∘≲ (wk₁ f)

-}