diff --git a/server/leanserver/GameServer/Commands.lean b/server/leanserver/GameServer/Commands.lean index 257def4..86e449f 100644 --- a/server/leanserver/GameServer/Commands.lean +++ b/server/leanserver/GameServer/Commands.lean @@ -230,7 +230,7 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com -- Check that the statement name is a lemma in the doc match statementName with | some name => checkInventoryDoc .Lemma name.getId - | none => pure Unit.unit + | none => pure () let lvlIdx ← getCurLevelIdx let defaultDeclName : Name := (← getCurGame).name ++ (← getCurWorld).name ++ @@ -283,6 +283,9 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com descrText := match descr with | none => "" | some s => s.getString + statementName := match statementName with + | none => default + | some name => name.getId descrFormat := match statementName with | none => "example " ++ (toString <| reprint sig.raw) ++ " := by" | some name => (Format.join ["lemma ", reprint name.raw, " ", reprint sig.raw, " := by"]).pretty 10 -- "lemma " ++ (toString <| reprint name.raw) ++ " " ++ (Format.pretty (reprint sig.raw) 40) ++ " := by" @@ -404,14 +407,42 @@ elab "MakeGame" : command => do throwError "World graph must not contain loops! Check your `Path` declarations." -- Compute which inventory items are available in which level: - for inventoryType in open InventoryType in #[Tactic, Definition, Lemma] do + for inventoryType in #[.Tactic, .Definition, .Lemma] do let mut newItemsInWorld : HashMap Name (HashSet Name) := {} + let mut lemmaStatements : HashMap (Name × Nat) Name := {} let mut allItems : HashSet Name := {} for (worldId, world) in game.worlds.nodes.toArray do let mut newItems : HashSet Name := {} - for (_, level) in world.levels.toArray do - newItems := newItems.insertMany (level.getInventory inventoryType).new - allItems := allItems.insertMany (level.getInventory inventoryType).new + for (levelId, level) in world.levels.toArray do + let newLemmas := (level.getInventory inventoryType).new + newItems := newItems.insertMany newLemmas + allItems := allItems.insertMany newLemmas + if inventoryType == .Lemma then + -- For levels `2, 3, …` we check if the previous level was named + -- in which case we add it as available lemma. + match levelId with + | 0 => pure () + | 1 => pure () -- level ids start with 1, so we need to skip 1, too. + | i₀ + 1 => + -- add named statement from previous level to the available lemmas. + match (world.levels.find! (i₀)).statementName with + | .anonymous => pure () + | .num _ _ => panic "Did not expect to get a numerical statement name!" + | .str pre s => + let name := Name.str pre s + newItems := newItems.insert name + allItems := allItems.insert name + lemmaStatements := lemmaStatements.insert (worldId, levelId) name + if inventoryType == .Lemma then + -- if named, add the lemma from the last level of the world to the inventory + let i₀ := world.levels.size + match (world.levels.find! (i₀)).statementName with + | .anonymous => pure () + | .num _ _ => panic "Did not expect to get a numerical statement name!" + | .str pre s => + let name := Name.str pre s + newItems := newItems.insert name + allItems := allItems.insert name newItemsInWorld := newItemsInWorld.insert worldId newItems -- Basic inventory item availability: all locked. @@ -457,6 +488,18 @@ elab "MakeGame" : command => do category := data.category locked := false } + -- add the statement from the previous level permanently as unlocked + if inventoryType == .Lemma then + match lemmaStatements.find? (worldId, levelId) with + | none => pure () + | some name => + let data := (← getInventoryDoc? name inventoryType).get! + items := items.insert name { + name := name + displayName := data.displayName + category := data.category + locked := false } + let itemsArray := items.toArray |>.insertionSort (fun a b => a.1.toString < b.1.toString) |>.map (·.2) diff --git a/server/leanserver/GameServer/EnvExtensions.lean b/server/leanserver/GameServer/EnvExtensions.lean index 19313b6..927dadb 100644 --- a/server/leanserver/GameServer/EnvExtensions.lean +++ b/server/leanserver/GameServer/EnvExtensions.lean @@ -173,6 +173,9 @@ structure GameLevel where /-- Introduction text shown all the time. (markdown) -/ introduction: String := default conclusion: String := default + /-- The name of the exercise proven. If provided this lemma will be available in + future levels. -/ + statementName: Name := default hints: Array GoalHintEntry := default /-- The statement in Lean. -/ goal : TSyntax `Lean.Parser.Command.declSig := default @@ -189,6 +192,7 @@ structure GameLevel where lemmas: InventoryInfo := default deriving Inhabited, Repr + /-! ## World -/ /-- A world is a collection of levels, like a chapter. -/ diff --git a/server/nng/NNG/Levels/Addition/Level_2.lean b/server/nng/NNG/Levels/Addition/Level_2.lean index d8c3b3f..00a379a 100644 --- a/server/nng/NNG/Levels/Addition/Level_2.lean +++ b/server/nng/NNG/Levels/Addition/Level_2.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Addition +import NNG.Levels.Addition.Level_1 Game "NNG" World "Addition" @@ -8,9 +8,7 @@ Title "add_assoc (associativity of addition)" open MyNat -namespace AdditionWorld - -theorem zero_add (n : ℕ) : 0 + n = n := by +theorem MyNat.zero_add (n : ℕ) : 0 + n = n := by induction n with n hn · rw [add_zero] rfl @@ -31,6 +29,7 @@ See if you can prove associativity of addition. " Statement MyNat.add_assoc + "On the set of natural numbers, addition is associative. In other words, for all natural numbers $a, b$ and $c$, we have $ (a + b) + c = a + (b + c). $" diff --git a/server/nng/NNG/Levels/Addition/Level_3.lean b/server/nng/NNG/Levels/Addition/Level_3.lean index b365655..7e63a68 100644 --- a/server/nng/NNG/Levels/Addition/Level_3.lean +++ b/server/nng/NNG/Levels/Addition/Level_3.lean @@ -1,5 +1,4 @@ import NNG.Metadata -import NNG.MyNat.Addition import NNG.Levels.Addition.Level_2 Game "NNG" @@ -9,9 +8,7 @@ Title "succ_add" open MyNat -namespace AdditionWorld - -theorem add_assoc (a b c : ℕ) : (a + b) + c = a + (b + c) := by +theorem MyNat.add_assoc (a b c : ℕ) : (a + b) + c = a + (b + c) := by induction c with c hc · rw [add_zero] rw [add_zero] @@ -60,8 +57,6 @@ $ \\operatorname{succ}(a) + b = \\operatorname{succ}(a + b)$." rw [add_succ] rfl -NewLemma MyNat.add_assoc - Conclusion " diff --git a/server/nng/NNG/Levels/Addition/Level_4.lean b/server/nng/NNG/Levels/Addition/Level_4.lean index 33329e4..0d0a659 100644 --- a/server/nng/NNG/Levels/Addition/Level_4.lean +++ b/server/nng/NNG/Levels/Addition/Level_4.lean @@ -1,5 +1,4 @@ import NNG.Metadata -import NNG.MyNat.Addition import NNG.Levels.Addition.Level_3 Game "NNG" @@ -9,9 +8,7 @@ Title "`add_comm` (boss level)" open MyNat -namespace AdditionWorld - -theorem succ_add (a b : ℕ) : succ a + b = succ (a + b) := by +theorem MyNat.succ_add (a b : ℕ) : succ a + b = succ (a + b) := by induction b with d hd · rw [add_zero] rw [add_zero] @@ -52,8 +49,6 @@ $a + b = b + a$." rw [succ_add] rfl -NewLemma MyNat.succ_add - Conclusion " If you got this far -- nice! You're nearly ready to make a choice: diff --git a/server/nng/NNG/Levels/Addition/Level_5.lean b/server/nng/NNG/Levels/Addition/Level_5.lean index afb74bc..1e39660 100644 --- a/server/nng/NNG/Levels/Addition/Level_5.lean +++ b/server/nng/NNG/Levels/Addition/Level_5.lean @@ -9,9 +9,7 @@ Title "succ_eq_add_one" open MyNat -namespace AdditionWorld - -theorem add_comm (a b : ℕ) : a + b = b + a := by +theorem MyNat.add_comm (a b : ℕ) : a + b = b + a := by induction b with d hd · rw [zero_add] rw [add_zero] @@ -23,7 +21,7 @@ theorem add_comm (a b : ℕ) : a + b = b + a := by theorem one_eq_succ_zero : (1 : ℕ) = succ 0 := by simp only -NewLemma MyNat.add_comm MyNat.one_eq_succ_zero +NewLemma MyNat.one_eq_succ_zero Introduction " diff --git a/server/nng/NNG/Levels/Addition/Level_6.lean b/server/nng/NNG/Levels/Addition/Level_6.lean index 44d60e7..44008e0 100644 --- a/server/nng/NNG/Levels/Addition/Level_6.lean +++ b/server/nng/NNG/Levels/Addition/Level_6.lean @@ -9,8 +9,6 @@ Title "add_right_comm" open MyNat -namespace AdditionWorld - Introduction " Lean sometimes writes `a + b + c`. What does it mean? The convention is diff --git a/server/nng/NNG/Levels/Function/Level_1.lean b/server/nng/NNG/Levels/Function/Level_1.lean index dec8165..cd19937 100644 --- a/server/nng/NNG/Levels/Function/Level_1.lean +++ b/server/nng/NNG/Levels/Function/Level_1.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 import NNG.MyNat.Multiplication Game "NNG" diff --git a/server/nng/NNG/Levels/Function/Level_2.lean b/server/nng/NNG/Levels/Function/Level_2.lean index 5c69454..0082d4f 100644 --- a/server/nng/NNG/Levels/Function/Level_2.lean +++ b/server/nng/NNG/Levels/Function/Level_2.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 import NNG.MyNat.Multiplication Game "NNG" diff --git a/server/nng/NNG/Levels/Function/Level_3.lean b/server/nng/NNG/Levels/Function/Level_3.lean index 9654dd0..c2d6e04 100644 --- a/server/nng/NNG/Levels/Function/Level_3.lean +++ b/server/nng/NNG/Levels/Function/Level_3.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 import NNG.MyNat.Multiplication Game "NNG" diff --git a/server/nng/NNG/Levels/Function/Level_4.lean b/server/nng/NNG/Levels/Function/Level_4.lean index a14542d..01fc51f 100644 --- a/server/nng/NNG/Levels/Function/Level_4.lean +++ b/server/nng/NNG/Levels/Function/Level_4.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 import NNG.MyNat.Multiplication Game "NNG" diff --git a/server/nng/NNG/Levels/Function/Level_5.lean b/server/nng/NNG/Levels/Function/Level_5.lean index 5a995e9..3ca4ce7 100644 --- a/server/nng/NNG/Levels/Function/Level_5.lean +++ b/server/nng/NNG/Levels/Function/Level_5.lean @@ -1,5 +1,5 @@ import NNG.Metadata -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 import NNG.MyNat.Multiplication Game "NNG" diff --git a/server/nng/NNG/MyNat/AdvAddition.lean b/server/nng/NNG/MyNat/AdvAddition.lean index 25251b5..898705c 100644 --- a/server/nng/NNG/MyNat/AdvAddition.lean +++ b/server/nng/NNG/MyNat/AdvAddition.lean @@ -1,4 +1,4 @@ -import NNG.MyNat.Theorems.Addition +import NNG.Levels.Addition.Level_6 namespace MyNat open MyNat diff --git a/server/nng/NNG/MyNat/Theorems/Addition.lean b/server/nng/NNG/MyNat/Theorems/Addition.lean deleted file mode 100644 index 0d04f8a..0000000 --- a/server/nng/NNG/MyNat/Theorems/Addition.lean +++ /dev/null @@ -1,46 +0,0 @@ -import NNG.Metadata -import NNG.MyNat.Addition - -open MyNat - -theorem MyNat.zero_add (n : ℕ) : 0 + n = n := by - induction n with n hn - · rw [add_zero] - rfl - · rw [add_succ] - rw [hn] - rfl - -theorem MyNat.add_assoc (a b c : ℕ) : (a + b) + c = a + (b + c) := by - induction c with c hc - · rw [add_zero] - rw [add_zero] - rfl - · rw [add_succ] - rw [add_succ] - rw [add_succ] - rw [hc] - rfl - -theorem MyNat.succ_add (a b : ℕ) : succ a + b = succ (a + b) := by - induction b with d hd - · rw [add_zero] - rw [add_zero] - rfl - · rw [add_succ] - rw [hd] - rw [add_succ] - rfl - -theorem MyNat.add_comm (a b : ℕ) : a + b = b + a := by - induction b with d hd - · rw [zero_add] - rw [add_zero] - rfl - · rw [add_succ] - rw [hd] - rw [succ_add] - rfl - -theorem MyNat.one_eq_succ_zero : (1 : ℕ) = succ 0 := by - simp only