File: Mathlib/SetTheory/Game/Nim.lean

full_name: SetTheory.PGame.nim
code: /-- The definition of single-heap nim, which can be viewed as a pile of stones where each player can
  take a positive number of stones from it on their turn. -/
noncomputable def nim : Ordinal.{u} → PGame.{u}
  
goal: Ordinal.{u} → SetTheory.PGame

full_name: SetTheory.PGame.nim_def
code: theorem nim_def (o : Ordinal) :
    have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance
    nim o =
      PGame.mk o.out.α o.out.α (fun o₂ => nim (Ordinal.typein (· < ·) o₂)) fun o₂ =>
        nim (Ordinal.typein (· < ·) o₂) 
goal: let_fun this := ⋯;
SetTheory.PGame.nim o =
  SetTheory.PGame.mk (Quotient.out o).α (Quotient.out o).α
    (fun o₂ => SetTheory.PGame.nim (Ordinal.typein (fun x x_1 => x < x_1) o₂)) fun o₂ =>
    SetTheory.PGame.nim (Ordinal.typein (fun x x_1 => x < x_1) o₂)

full_name: SetTheory.PGame.leftMoves_nim
code: theorem leftMoves_nim (o : Ordinal) : (nim o).LeftMoves = o.out.α 
goal: (SetTheory.PGame.nim o).LeftMoves = (Quotient.out o).α

full_name: SetTheory.PGame.rightMoves_nim
code: theorem rightMoves_nim (o : Ordinal) : (nim o).RightMoves = o.out.α 
goal: (SetTheory.PGame.nim o).RightMoves = (Quotient.out o).α

full_name: SetTheory.PGame.moveLeft_nim_hEq
code: theorem moveLeft_nim_hEq (o : Ordinal) :
    have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance
    HEq (nim o).moveLeft fun i : o.out.α => nim (typein (· < ·) i) 
goal: let_fun this := ⋯;
HEq (SetTheory.PGame.nim o).moveLeft fun i => SetTheory.PGame.nim (Ordinal.typein (fun x x_1 => x < x_1) i)

full_name: SetTheory.PGame.moveRight_nim_hEq
code: theorem moveRight_nim_hEq (o : Ordinal) :
    have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance
    HEq (nim o).moveRight fun i : o.out.α => nim (typein (· < ·) i) 
goal: let_fun this := ⋯;
HEq (SetTheory.PGame.nim o).moveRight fun i => SetTheory.PGame.nim (Ordinal.typein (fun x x_1 => x < x_1) i)

full_name: SetTheory.PGame.toLeftMovesNim
code: /-- Turns an ordinal less than `o` into a left move for `nim o` and viceversa. -/
noncomputable def toLeftMovesNim {o : Ordinal} : Set.Iio o ≃ (nim o).LeftMoves 
goal: ↑(Set.Iio o) ≃ (SetTheory.PGame.nim o).LeftMoves

full_name: SetTheory.PGame.toRightMovesNim
code: /-- Turns an ordinal less than `o` into a right move for `nim o` and viceversa. -/
noncomputable def toRightMovesNim {o : Ordinal} : Set.Iio o ≃ (nim o).RightMoves 
goal: ↑(Set.Iio o) ≃ (SetTheory.PGame.nim o).RightMoves

full_name: SetTheory.PGame.toLeftMovesNim_symm_lt
code: @[simp]
theorem toLeftMovesNim_symm_lt {o : Ordinal} (i : (nim o).LeftMoves) :
    ↑(toLeftMovesNim.symm i) < o 
goal: ↑(SetTheory.PGame.toLeftMovesNim.symm i) < o

full_name: SetTheory.PGame.toRightMovesNim_symm_lt
code: @[simp]
theorem toRightMovesNim_symm_lt {o : Ordinal} (i : (nim o).RightMoves) :
    ↑(toRightMovesNim.symm i) < o 
goal: ↑(SetTheory.PGame.toRightMovesNim.symm i) < o

full_name: SetTheory.PGame.moveLeft_nim'
code: @[simp]
theorem moveLeft_nim' {o : Ordinal.{u}} (i) :
    (nim o).moveLeft i = nim (toLeftMovesNim.symm i).val 
goal: (SetTheory.PGame.nim o).moveLeft i = SetTheory.PGame.nim ↑(SetTheory.PGame.toLeftMovesNim.symm i)

full_name: SetTheory.PGame.moveLeft_nim
code: theorem moveLeft_nim {o : Ordinal} (i) : (nim o).moveLeft (toLeftMovesNim i) = nim i 
goal: (SetTheory.PGame.nim o).moveLeft (SetTheory.PGame.toLeftMovesNim i) = SetTheory.PGame.nim ↑i

full_name: SetTheory.PGame.moveRight_nim'
code: @[simp]
theorem moveRight_nim' {o : Ordinal} (i) : (nim o).moveRight i = nim (toRightMovesNim.symm i).val 
goal: (SetTheory.PGame.nim o).moveRight i = SetTheory.PGame.nim ↑(SetTheory.PGame.toRightMovesNim.symm i)

full_name: SetTheory.PGame.moveRight_nim
code: theorem moveRight_nim {o : Ordinal} (i) : (nim o).moveRight (toRightMovesNim i) = nim i 
goal: (SetTheory.PGame.nim o).moveRight (SetTheory.PGame.toRightMovesNim i) = SetTheory.PGame.nim ↑i

full_name: SetTheory.PGame.leftMovesNimRecOn
code: /-- A recursion principle for left moves of a nim game. -/
@[elab_as_elim]
def leftMovesNimRecOn {o : Ordinal} {P : (nim o).LeftMoves → Sort*} (i : (nim o).LeftMoves)
    (H : ∀ a (H : a < o), P <| toLeftMovesNim ⟨a, H⟩) : P i 
goal: P i

full_name: SetTheory.PGame.rightMovesNimRecOn
code: /-- A recursion principle for right moves of a nim game. -/
@[elab_as_elim]
def rightMovesNimRecOn {o : Ordinal} {P : (nim o).RightMoves → Sort*} (i : (nim o).RightMoves)
    (H : ∀ a (H : a < o), P <| toRightMovesNim ⟨a, H⟩) : P i 
goal: P i

full_name: SetTheory.PGame.isEmpty_nim_zero_leftMoves
code: instance isEmpty_nim_zero_leftMoves : IsEmpty (nim 0).LeftMoves 
goal: IsEmpty (SetTheory.PGame.nim 0).LeftMoves

full_name: SetTheory.PGame.isEmpty_nim_zero_rightMoves
code: instance isEmpty_nim_zero_rightMoves : IsEmpty (nim 0).RightMoves 
goal: IsEmpty (SetTheory.PGame.nim 0).RightMoves

full_name: SetTheory.PGame.nimZeroRelabelling
code: /-- `nim 0` has exactly the same moves as `0`. -/
def nimZeroRelabelling : nim 0 ≡r 0 
goal: (SetTheory.PGame.nim 0).Relabelling 0

full_name: SetTheory.PGame.nim_zero_equiv
code: theorem nim_zero_equiv : nim 0 ≈ 0 
goal: SetTheory.PGame.nim 0 ≈ 0

full_name: SetTheory.PGame.uniqueNimOneLeftMoves
code: noncomputable instance uniqueNimOneLeftMoves : Unique (nim 1).LeftMoves 
goal: Unique (SetTheory.PGame.nim 1).LeftMoves

full_name: SetTheory.PGame.uniqueNimOneRightMoves
code: noncomputable instance uniqueNimOneRightMoves : Unique (nim 1).RightMoves 
goal: Unique (SetTheory.PGame.nim 1).RightMoves

full_name: SetTheory.PGame.default_nim_one_leftMoves_eq
code: @[simp]
theorem default_nim_one_leftMoves_eq :
    (default : (nim 1).LeftMoves) = @toLeftMovesNim 1 ⟨0, Set.mem_Iio.mpr zero_lt_one⟩ 
goal: default = SetTheory.PGame.toLeftMovesNim ⟨0, ⋯⟩

full_name: SetTheory.PGame.default_nim_one_rightMoves_eq
code: @[simp]
theorem default_nim_one_rightMoves_eq :
    (default : (nim 1).RightMoves) = @toRightMovesNim 1 ⟨0, Set.mem_Iio.mpr zero_lt_one⟩ 
goal: default = SetTheory.PGame.toRightMovesNim ⟨0, ⋯⟩

full_name: SetTheory.PGame.toLeftMovesNim_one_symm
code: @[simp]
theorem toLeftMovesNim_one_symm (i) :
    (@toLeftMovesNim 1).symm i = ⟨0, Set.mem_Iio.mpr zero_lt_one⟩ 
goal: SetTheory.PGame.toLeftMovesNim.symm i = ⟨0, ⋯⟩

full_name: SetTheory.PGame.toRightMovesNim_one_symm
code: @[simp]
theorem toRightMovesNim_one_symm (i) :
    (@toRightMovesNim 1).symm i = ⟨0, Set.mem_Iio.mpr zero_lt_one⟩ 
goal: SetTheory.PGame.toRightMovesNim.symm i = ⟨0, ⋯⟩

full_name: SetTheory.PGame.nim_one_moveLeft
code: theorem nim_one_moveLeft (x) : (nim 1).moveLeft x = nim 0 
goal: (SetTheory.PGame.nim 1).moveLeft x = SetTheory.PGame.nim 0

full_name: SetTheory.PGame.nim_one_moveRight
code: theorem nim_one_moveRight (x) : (nim 1).moveRight x = nim 0 
goal: (SetTheory.PGame.nim 1).moveRight x = SetTheory.PGame.nim 0

full_name: SetTheory.PGame.nimOneRelabelling
code: /-- `nim 1` has exactly the same moves as `star`. -/
def nimOneRelabelling : nim 1 ≡r star 
goal: (SetTheory.PGame.nim 1).Relabelling SetTheory.PGame.star

full_name: SetTheory.PGame.nim_one_equiv
code: theorem nim_one_equiv : nim 1 ≈ star 
goal: SetTheory.PGame.nim 1 ≈ SetTheory.PGame.star

full_name: SetTheory.PGame.nim_birthday
code: @[simp]
theorem nim_birthday (o : Ordinal) : (nim o).birthday = o 
goal: (SetTheory.PGame.nim o).birthday = o

full_name: SetTheory.PGame.neg_nim
code: @[simp]
theorem neg_nim (o : Ordinal) : -nim o = nim o 
goal: -SetTheory.PGame.nim o = SetTheory.PGame.nim o

full_name: SetTheory.PGame.nim_impartial
code: instance nim_impartial (o : Ordinal) : Impartial (nim o) 
goal: (SetTheory.PGame.nim o).Impartial

full_name: SetTheory.PGame.nim_fuzzy_zero_of_ne_zero
code: theorem nim_fuzzy_zero_of_ne_zero {o : Ordinal} (ho : o ≠ 0) : nim o ‖ 0 
goal: (SetTheory.PGame.nim o).Fuzzy 0

full_name: SetTheory.PGame.nim_add_equiv_zero_iff
code: @[simp]
theorem nim_add_equiv_zero_iff (o₁ o₂ : Ordinal) : (nim o₁ + nim o₂ ≈ 0) ↔ o₁ = o₂ 
goal: SetTheory.PGame.nim o₁ + SetTheory.PGame.nim o₂ ≈ 0 ↔ o₁ = o₂

full_name: SetTheory.PGame.nim_add_fuzzy_zero_iff
code: @[simp]
theorem nim_add_fuzzy_zero_iff {o₁ o₂ : Ordinal} : nim o₁ + nim o₂ ‖ 0 ↔ o₁ ≠ o₂ 
goal: (SetTheory.PGame.nim o₁ + SetTheory.PGame.nim o₂).Fuzzy 0 ↔ o₁ ≠ o₂

full_name: SetTheory.PGame.nim_equiv_iff_eq
code: @[simp]
theorem nim_equiv_iff_eq {o₁ o₂ : Ordinal} : (nim o₁ ≈ nim o₂) ↔ o₁ = o₂ 
goal: SetTheory.PGame.nim o₁ ≈ SetTheory.PGame.nim o₂ ↔ o₁ = o₂

full_name: SetTheory.PGame.grundyValue
code: /-- The Grundy value of an impartial game, the ordinal which corresponds to the game of nim that the
 game is equivalent to -/
noncomputable def grundyValue : PGame.{u} → Ordinal.{u}
  
goal: SetTheory.PGame → Ordinal.{u}

full_name: SetTheory.PGame.grundyValue_eq_mex_left
code: theorem grundyValue_eq_mex_left (G : PGame) :
    grundyValue G = Ordinal.mex.{u, u} fun i => grundyValue (G.moveLeft i) 
goal: G.grundyValue = Ordinal.mex fun i => (G.moveLeft i).grundyValue

full_name: SetTheory.PGame.equiv_nim_grundyValue
code: /-- The Sprague-Grundy theorem which states that every impartial game is equivalent to a game of
 nim, namely the game of nim corresponding to the games Grundy value -/
theorem equiv_nim_grundyValue : ∀ (G : PGame.{u}) [G.Impartial], G ≈ nim (grundyValue G)
  
goal: G ≈ SetTheory.PGame.nim G.grundyValue

full_name: SetTheory.PGame.grundyValue_eq_iff_equiv_nim
code: theorem grundyValue_eq_iff_equiv_nim {G : PGame} [G.Impartial] {o : Ordinal} :
    grundyValue G = o ↔ (G ≈ nim o) 
goal: G.grundyValue = o ↔ G ≈ SetTheory.PGame.nim o

full_name: SetTheory.PGame.nim_grundyValue
code: @[simp]
theorem nim_grundyValue (o : Ordinal.{u}) : grundyValue (nim o) = o 
goal: (SetTheory.PGame.nim o).grundyValue = o

full_name: SetTheory.PGame.grundyValue_eq_iff_equiv
code: theorem grundyValue_eq_iff_equiv (G H : PGame) [G.Impartial] [H.Impartial] :
    grundyValue G = grundyValue H ↔ (G ≈ H) 
goal: G.grundyValue = H.grundyValue ↔ G ≈ H

full_name: SetTheory.PGame.grundyValue_zero
code: @[simp]
theorem grundyValue_zero : grundyValue 0 = 0 
goal: SetTheory.PGame.grundyValue 0 = 0

full_name: SetTheory.PGame.grundyValue_iff_equiv_zero
code: theorem grundyValue_iff_equiv_zero (G : PGame) [G.Impartial] : grundyValue G = 0 ↔ (G ≈ 0) 
goal: G.grundyValue = 0 ↔ G ≈ 0

full_name: SetTheory.PGame.grundyValue_star
code: @[simp]
theorem grundyValue_star : grundyValue star = 1 
goal: SetTheory.PGame.star.grundyValue = 1

full_name: SetTheory.PGame.grundyValue_neg
code: @[simp]
theorem grundyValue_neg (G : PGame) [G.Impartial] : grundyValue (-G) = grundyValue G 
goal: (-G).grundyValue = G.grundyValue

full_name: SetTheory.PGame.grundyValue_eq_mex_right
code: theorem grundyValue_eq_mex_right :
    ∀ (G : PGame) [G.Impartial],
      grundyValue G = Ordinal.mex.{u, u} fun i => grundyValue (G.moveRight i)
   
goal: G.grundyValue = Ordinal.mex fun i => (G.moveRight i).grundyValue

full_name: SetTheory.PGame.grundyValue_nim_add_nim
code: /-- The Grundy value of the sum of two nim games with natural numbers of piles equals their bitwise
xor. -/
@[simp]
theorem grundyValue_nim_add_nim (n m : ℕ) :
    grundyValue (nim.{u} n + nim.{u} m) = n ^^^ m 
goal: (SetTheory.PGame.nim ↑n + SetTheory.PGame.nim ↑m).grundyValue = ↑(n ^^^ m)

full_name: SetTheory.PGame.nim_add_nim_equiv
code: theorem nim_add_nim_equiv {n m : ℕ} : nim n + nim m ≈ nim (n ^^^ m) 
goal: SetTheory.PGame.nim ↑n + SetTheory.PGame.nim ↑m ≈ SetTheory.PGame.nim ↑(n ^^^ m)

full_name: SetTheory.PGame.grundyValue_add
code: theorem grundyValue_add (G H : PGame) [G.Impartial] [H.Impartial] {n m : ℕ} (hG : grundyValue G = n)
    (hH : grundyValue H = m) : grundyValue (G + H) = n ^^^ m 
goal: (G + H).grundyValue = ↑(n ^^^ m)