Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 28568bd

Browse files
committed
feat(set_theory/game/nim): Add basic API (#13857)
1 parent a80e568 commit 28568bd

File tree

1 file changed

+62
-21
lines changed

1 file changed

+62
-21
lines changed

src/set_theory/game/nim.lean

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,28 +96,69 @@ begin
9696
exact funext (λ i, IH _ (typein_lt_self i))
9797
end
9898

99-
instance nim_impartial : ∀ (O : ordinal), impartial (nim O)
100-
| O :=
99+
lemma left_moves_nim (O : ordinal) : (nim O).left_moves = O.out.α :=
100+
by { rw nim_def, refl }
101+
lemma right_moves_nim (O : ordinal) : (nim O).right_moves = O.out.α :=
102+
by { rw nim_def, refl }
103+
104+
lemma move_left_nim_heq (O : ordinal) : (nim O).move_left == λ i : O.out.α, nim (typein (<) i) :=
105+
by { rw nim_def, refl }
106+
lemma move_right_nim_heq (O : ordinal) : (nim O).move_right == λ i : O.out.α, nim (typein (<) i) :=
107+
by { rw nim_def, refl }
108+
109+
/-- Turns an ordinal less than `O` into a left move for `nim O` and viceversa. -/
110+
noncomputable def to_left_moves_nim {O : ordinal} : {O' // O' < O} ≃ (nim O).left_moves :=
111+
(out_equiv_lt O).trans (equiv.cast (left_moves_nim O).symm)
112+
113+
/-- Turns an ordinal less than `O` into a right move for `nim O` and viceversa. -/
114+
noncomputable def to_right_moves_nim {O : ordinal} : {O' // O' < O} ≃ (nim O).right_moves :=
115+
(out_equiv_lt O).trans (equiv.cast (right_moves_nim O).symm)
116+
117+
@[simp] theorem to_left_moves_nim_symm_lt {O : ordinal} (i : (nim O).left_moves) :
118+
↑(to_left_moves_nim.symm i) < O :=
119+
(to_left_moves_nim.symm i).prop
120+
121+
@[simp] theorem to_right_moves_nim_symm_lt {O : ordinal} (i : (nim O).right_moves) :
122+
↑(to_right_moves_nim.symm i) < O :=
123+
(to_right_moves_nim.symm i).prop
124+
125+
@[simp] lemma move_left_nim' {O : ordinal.{u}} (i) :
126+
(nim O).move_left i = nim (to_left_moves_nim.symm i).val :=
127+
(congr_heq (move_left_nim_heq O).symm (cast_heq _ i)).symm
128+
129+
lemma move_left_nim {O : ordinal} (i) :
130+
(nim O).move_left (to_left_moves_nim i) = nim i :=
131+
by simp
132+
133+
@[simp] lemma move_right_nim' {O : ordinal} (i) :
134+
(nim O).move_right i = nim (to_right_moves_nim.symm i).val :=
135+
(congr_heq (move_right_nim_heq O).symm (cast_heq _ i)).symm
136+
137+
lemma move_right_nim {O : ordinal} (i) :
138+
(nim O).move_right (to_right_moves_nim i) = nim i :=
139+
by simp
140+
141+
@[simp] lemma neg_nim (O : ordinal) : -nim O = nim O :=
101142
begin
102-
rw [impartial_def, nim_def, neg_def],
103-
split, split;
104-
rw pgame.le_def,
105-
all_goals { refine ⟨λ i, let hwf := ordinal.typein_lt_self i in _,
106-
λ j, let hwf := ordinal.typein_lt_self j in _⟩ },
107-
{ exact or.inl ⟨i, (@impartial.neg_equiv_self _ $ nim_impartial $ typein (<) i).1⟩ },
108-
{ exact or.inr ⟨j, (@impartial.neg_equiv_self _ $ nim_impartial $ typein (<) j).1⟩ },
109-
{ exact or.inl ⟨i, (@impartial.neg_equiv_self _ $ nim_impartial $ typein (<) i).2⟩ },
110-
{ exact or.inr ⟨j, (@impartial.neg_equiv_self _ $ nim_impartial $ typein (<) j).2⟩ },
111-
{ exact nim_impartial (typein (<) i) },
112-
{ exact nim_impartial (typein (<) j) }
143+
induction O using ordinal.induction with O IH,
144+
rw nim_def, dsimp; congr;
145+
funext i;
146+
exact IH _ (ordinal.typein_lt_self i)
147+
end
148+
149+
instance nim_impartial (O : ordinal) : impartial (nim O) :=
150+
begin
151+
induction O using ordinal.induction with O IH,
152+
rw [impartial_def, neg_nim],
153+
refine ⟨equiv_refl _, λ i, _, λ i, _⟩;
154+
simpa using IH _ (typein_lt_self _)
113155
end
114-
using_well_founded { dec_tac := tactic.assumption }
115156

116-
lemma exists_ordinal_move_left_eq (O : ordinal) : ∀ i, ∃ O' < O, (nim O).move_left i = nim O' :=
117-
by { rw nim_def, exact λ i, ⟨_, ⟨ordinal.typein_lt_self i, rfl⟩⟩ }
157+
lemma exists_ordinal_move_left_eq {O : ordinal} (i) : ∃ O' < O, (nim O).move_left i = nim O' :=
158+
⟨_, typein_lt_self _, move_left_nim' i⟩
118159

119-
lemma exists_move_left_eq {O : ordinal} : ∀ O' < O, ∃ i, (nim O).move_left i = nim O' :=
120-
by { rw nim_def, exact λ _ h, ⟨(ordinal.principal_seg_out h).top, by simp⟩ }
160+
lemma exists_move_left_eq {O O' : ordinal} (h : O' < O) : ∃ i, (nim O).move_left i = nim O' :=
161+
⟨to_left_moves_nim ⟨O', h⟩, by simp⟩
121162

122163
@[simp] lemma zero_first_loses : (nim (0 : ordinal)).first_loses :=
123164
begin
@@ -254,7 +295,7 @@ begin
254295

255296
all_goals
256297
{ -- One of the piles is reduced to `k` stones, with `k < n` or `k < m`.
257-
obtain ⟨ok, hk, hk'⟩ := nim.exists_ordinal_move_left_eq _ a,
298+
obtain ⟨ok, hk, hk'⟩ := nim.exists_ordinal_move_left_eq a,
258299
obtain ⟨k, rfl⟩ := ordinal.lt_omega.1 (lt_trans hk (ordinal.nat_lt_omega _)),
259300
replace hk := ordinal.nat_cast_lt.1 hk,
260301

@@ -288,11 +329,11 @@ begin
288329

289330
-- Therefore, we can play the corresponding move, and by the inductive hypothesis the new state
290331
-- is `(u xor m) xor m = u` or `n xor (u xor n) = u` as required.
291-
{ obtain ⟨i, hi⟩ := nim.exists_move_left_eq _ (ordinal.nat_cast_lt.2 h),
332+
{ obtain ⟨i, hi⟩ := nim.exists_move_left_eq (ordinal.nat_cast_lt.2 h),
292333
refine ⟨(left_moves_add _ _).symm (sum.inl i), _⟩,
293334
simp only [hi, add_move_left_inl],
294335
rw [hn _ h, nat.lxor_assoc, nat.lxor_self, nat.lxor_zero] },
295-
{ obtain ⟨i, hi⟩ := nim.exists_move_left_eq _ (ordinal.nat_cast_lt.2 h),
336+
{ obtain ⟨i, hi⟩ := nim.exists_move_left_eq (ordinal.nat_cast_lt.2 h),
296337
refine ⟨(left_moves_add _ _).symm (sum.inr i), _⟩,
297338
simp only [hi, add_move_left_inr],
298339
rw [hm _ h, nat.lxor_comm, nat.lxor_assoc, nat.lxor_self, nat.lxor_zero] } },

0 commit comments

Comments
 (0)