record used inventory

pull/118/head
Alexander Bentkamp 3 years ago
parent a32baeb8e7
commit df8fa2933b

@ -282,6 +282,38 @@ elab "LemmaTab" category:str : command =>
syntax statementAttr := "(" &"attr" ":=" Parser.Term.attrInstance,* ")" syntax statementAttr := "(" &"attr" ":=" Parser.Term.attrInstance,* ")"
-- TODO -- TODO
-- TODO: Reuse the following code for checking available tactics in user code:
structure UsedInventory where
(tactics : HashSet Name := {})
(definitions : HashSet Name := {})
(lemmas : HashSet Name := {})
partial def collectUsedInventory (stx : Syntax) (acc : UsedInventory := {}) : CommandElabM UsedInventory := do
match stx with
| .missing => return acc
| .node info kind args =>
if kind == `tacticHint__ || kind == `tacticBranch_ then return acc
return ← args.foldlM (fun acc arg => collectUsedInventory arg acc) acc
| .atom info val =>
-- ignore syntax elements that do not start with a letter
-- and ignore some standard keywords
let allowed := ["with", "fun", "at", "only", "by"]
if 0 < val.length ∧ val.data[0]!.isAlpha ∧ not (allowed.contains val) then
let val := val.dropRightWhile (fun c => c == '!' || c == '?') -- treat `simp?` and `simp!` like `simp`
return {acc with tactics := acc.tactics.insert val}
else
return acc
| .ident info rawVal val preresolved =>
let ns ←
try resolveGlobalConst (mkIdent val)
catch | _ => pure [] -- catch "unknown constant" error
return ← ns.foldlM (fun acc n => do
if let some (.thmInfo ..) := (← getEnv).find? n then
return {acc with lemmas := acc.lemmas.insertMany ns}
else
return {acc with definitions := acc.definitions.insertMany ns}
) acc
/-- Define the statement of the current level. -/ /-- Define the statement of the current level. -/
elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : command => do elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : command => do
let lvlIdx ← getCurLevelIdx let lvlIdx ← getCurLevelIdx
@ -298,6 +330,12 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com
let defaultDeclName : Ident := mkIdent <| (← getCurGame).name ++ (← getCurWorld).name ++ let defaultDeclName : Ident := mkIdent <| (← getCurGame).name ++ (← getCurWorld).name ++
("level" ++ toString lvlIdx : String) ("level" ++ toString lvlIdx : String)
-- Collect all used tactics/lemmas in the sample proof:
let usedInventory ← match val with
| `(Parser.Command.declVal| := $proof:term) => do
collectUsedInventory proof
| _ => throwError "expected `:=`"
-- Add theorem to context. -- Add theorem to context.
match statementName with match statementName with
| some name => | some name =>
@ -378,7 +416,10 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com
| none => default | none => default
| some name => currNamespace ++ name.getId | some name => currNamespace ++ name.getId
descrFormat := (Format.join [head, " ", st, " := by"]).pretty 10 descrFormat := (Format.join [head, " ", st, " := by"]).pretty 10
hints := hints } hints := hints
tactics := {level.tactics with used := usedInventory.tactics.toArray}
definitions := {level.definitions with used := usedInventory.definitions.toArray}
lemmas := {level.lemmas with used := usedInventory.lemmas.toArray} }
/-! # Hints -/ /-! # Hints -/
@ -629,7 +670,10 @@ elab "MakeGame" : command => do
-- Compute which inventory items are available in which level: -- Compute which inventory items are available in which level:
for inventoryType in #[.Tactic, .Definition, .Lemma] do for inventoryType in #[.Tactic, .Definition, .Lemma] do
-- Which items are introduced in which world?
let mut newItemsInWorld : HashMap Name (HashSet Name) := {} let mut newItemsInWorld : HashMap Name (HashSet Name) := {}
let mut worldsWithNewItem : HashMap Name (HashSet Name) := {}
let mut lemmaStatements : HashMap (Name × Nat) Name := {} let mut lemmaStatements : HashMap (Name × Nat) Name := {}
let mut allItems : HashSet Name := {} let mut allItems : HashSet Name := {}
for (worldId, world) in game.worlds.nodes.toArray do for (worldId, world) in game.worlds.nodes.toArray do
@ -665,6 +709,27 @@ elab "MakeGame" : command => do
newItems := newItems.insert name newItems := newItems.insert name
allItems := allItems.insert name allItems := allItems.insert name
newItemsInWorld := newItemsInWorld.insert worldId newItems newItemsInWorld := newItemsInWorld.insert worldId newItems
for newItem in newItems do
worldsWithNewItem := worldsWithNewItem.insert newItem $
(worldsWithNewItem.findD newItem {}).insert worldId
-- Which items are used in which world?
let mut usedItemsInWorld : HashMap Name (HashSet Name) := {}
for (worldId, world) in game.worlds.nodes.toArray do
let mut usedItems : HashSet Name := {}
for (levelId, level) in world.levels.toArray do
usedItems := usedItems.insertMany (level.getInventory inventoryType).used
usedItemsInWorld := usedItemsInWorld.insert worldId usedItems
let mut worldDependsOnWorlds : HashMap Name (HashSet Name) := {}
for (dependentWorldId, dependentWorld) in game.worlds.nodes.toArray do
let mut dependsOnWorlds : HashSet Name := {}
for usedItem in usedItemsInWorld.find! dependentWorldId do
match worldsWithNewItem.find? usedItem with
| some worldId => dependsOnWorlds := dependsOnWorlds.insertMany worldId
| none => logWarning m!"No world introducing {usedItem}, but required by {dependentWorldId}"
worldDependsOnWorlds := worldDependsOnWorlds.insert dependentWorldId dependsOnWorlds
logInfo m!"World {dependentWorldId} depends on {dependsOnWorlds.toArray}"
-- Basic inventory item availability: all locked. -- Basic inventory item availability: all locked.
let Availability₀ : HashMap Name InventoryTile := let Availability₀ : HashMap Name InventoryTile :=

@ -202,6 +202,8 @@ structure LevelId where
deriving Inhabited deriving Inhabited
structure InventoryInfo where structure InventoryInfo where
/-- inventory items used by the main sample solution of this level -/
used : Array Name
/-- new inventory items introduced by this level -/ /-- new inventory items introduced by this level -/
new : Array Name new : Array Name
/-- inventory items exceptionally forbidden in this level -/ /-- inventory items exceptionally forbidden in this level -/
@ -218,6 +220,7 @@ def getCurLevelId [MonadError m] : m LevelId := do
/-- Instance to make GameLevel Repr work -/ /-- Instance to make GameLevel Repr work -/
instance : Repr Elab.Command.Scope := ⟨fun s _ => repr s.currNamespace⟩ instance : Repr Elab.Command.Scope := ⟨fun s _ => repr s.currNamespace⟩
structure GameLevel where structure GameLevel where
index: Nat index: Nat
/-- The title of the level. -/ /-- The title of the level. -/

Loading…
Cancel
Save