new tactic display
This commit is contained in:
@@ -1,110 +1,25 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
|
||||||
import './inventory.css'
|
import './inventory.css'
|
||||||
|
|
||||||
import { Paper, Box, Typography, Accordion, AccordionSummary, AccordionDetails, Tabs, Tab, Divider, Button, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faLock, faLockOpen, faBook, faHammer, faBan } from '@fortawesome/free-solid-svg-icons'
|
import { faLock, faLockOpen, faBook, faHammer, faBan } from '@fortawesome/free-solid-svg-icons'
|
||||||
import Markdown from './Markdown';
|
import Markdown from './Markdown';
|
||||||
|
|
||||||
function TacticDoc(props) {
|
|
||||||
return (
|
|
||||||
<Accordion>
|
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
|
||||||
<Typography>{props.tactic.name}</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
<Markdown>{props.tactic.content}</Markdown>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>)
|
|
||||||
}
|
|
||||||
|
|
||||||
function LemmaDoc({ lemma }) {
|
function LeftPanel({ tactics, inventory, showSidePanel, setShowSidePanel }) {
|
||||||
return (
|
|
||||||
<Accordion>
|
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
|
||||||
<Typography>{lemma.userName}</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
<Markdown>{lemma.content}</Markdown>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>)
|
|
||||||
}
|
|
||||||
|
|
||||||
function LemmaDocs({ lemmas }) {
|
|
||||||
const [categories, setCategories] = useState(new Map())
|
|
||||||
const [curCategory, setCurCategory] = useState("")
|
|
||||||
|
|
||||||
const changeTab = (event: React.SyntheticEvent, newValue : string) => {
|
|
||||||
setCurCategory(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const cats = new Map()
|
|
||||||
lemmas.forEach(function (item) {
|
|
||||||
const category = item.category
|
|
||||||
cats.set(category, (cats.get(category) || []).concat([item]))
|
|
||||||
});
|
|
||||||
setCategories(cats)
|
|
||||||
setCurCategory(cats.keys().next().value)
|
|
||||||
}, [lemmas]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
|
||||||
<Tabs
|
|
||||||
value={curCategory}
|
|
||||||
onChange={changeTab}
|
|
||||||
aria-label="Categories" variant="scrollable" scrollButtons="auto">
|
|
||||||
{(Array.from(categories)).map(([category, _]) => <Tab value={category} label={category} key={category} wrapped />)}
|
|
||||||
</Tabs>
|
|
||||||
</Box>
|
|
||||||
{curCategory && categories.get(curCategory).map((lemma) => <LemmaDoc lemma={lemma} key={lemma.name} />)}
|
|
||||||
</div>)
|
|
||||||
}
|
|
||||||
|
|
||||||
function LeftPanel({ spells, inventory, showSidePanel, setShowSidePanel }) {
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="tactic-inventory">
|
<div className="tactic-inventory">
|
||||||
{ ["rfl", "tauto", "trivial", "simp", "left", "right", "assumption", "constructor"].map ((tac) => {
|
{ tactics.map (({name, locked, disabled}) => {
|
||||||
const locked = Math.random() > 0.5
|
const icon = locked ? <FontAwesomeIcon icon={faLock} /> :
|
||||||
const disabled = Math.random() > 0.5
|
disabled ? <FontAwesomeIcon icon={faBan} /> : ""
|
||||||
const icon = locked ? faLock : disabled ? faBan : faLockOpen
|
|
||||||
const className = locked ? "locked" : disabled ? "disabled" : ""
|
const className = locked ? "locked" : disabled ? "disabled" : ""
|
||||||
return <div className={`tactic ${className}`}><FontAwesomeIcon icon={icon} /> {tac}</div>
|
return <div className={`tactic ${className}`}>{icon} {name}</div>
|
||||||
})}
|
})}
|
||||||
|
{/* TODO: Click on Tactic: show info
|
||||||
|
TODO: click on paste icon -> paste into command line */}
|
||||||
</div>
|
</div>
|
||||||
<List className="side">
|
|
||||||
<ListItem key="tactics" disablePadding sx={{ display: 'block' }}>
|
|
||||||
<ListItemButton sx={{ minHeight: 48, justifyContent: showSidePanel ? 'initial' : 'center', px: 2.5 }} onClick={() => setShowSidePanel(true)}>
|
|
||||||
<ListItemIcon sx={{minWidth: 0, mr: showSidePanel ? 3 : 'auto', justifyContent: 'center' }}>
|
|
||||||
<FontAwesomeIcon icon={faHammer}></FontAwesomeIcon>
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary="Known Tactics" sx={{ display: showSidePanel ? null : "none" }} />
|
|
||||||
</ListItemButton>
|
|
||||||
{spells && spells.length > 0 &&
|
|
||||||
<Paper sx={{ px: 2, py: 1, display: showSidePanel ? null : "none" }} elevation={0} >
|
|
||||||
{spells.map((spell) => <TacticDoc key={spell.name} tactic={spell} />)}
|
|
||||||
</Paper>}
|
|
||||||
</ListItem>
|
|
||||||
<ListItem key="lemmas" disablePadding sx={{ display: 'block' }}>
|
|
||||||
<ListItemButton sx={{ minHeight: 48, justifyContent: showSidePanel ? 'initial' : 'center', px: 2.5 }} >
|
|
||||||
<ListItemIcon sx={{minWidth: 0, mr: showSidePanel ? 3 : 'auto', justifyContent: 'center' }}>
|
|
||||||
<FontAwesomeIcon icon={faBook}></FontAwesomeIcon>
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary="Known Lemmas" sx={{ display: showSidePanel ? null : "none" }} />
|
|
||||||
</ListItemButton>
|
|
||||||
{inventory && inventory.length > 0 &&
|
|
||||||
<Paper sx={{ px: 2, py: 1, mt: 2, display: showSidePanel ? null : "none" }} elevation={0} >
|
|
||||||
<LemmaDocs lemmas={inventory} />
|
|
||||||
</Paper>}
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ function Level() {
|
|||||||
</EditorContext.Provider>
|
</EditorContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
<div className="doc-panel">
|
<div className="doc-panel">
|
||||||
<LeftPanel spells={level?.data?.tactics} inventory={level?.data?.lemmas}
|
{!level.isLoading && <LeftPanel tactics={level?.data?.tactics} inventory={level?.data?.lemmas}
|
||||||
showSidePanel={showSidePanel} setShowSidePanel={setShowSidePanel} />
|
showSidePanel={showSidePanel} setShowSidePanel={setShowSidePanel} />}
|
||||||
</div>
|
</div>
|
||||||
</Split>
|
</Split>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: .5em;
|
gap: .5em;
|
||||||
flex-wrap : wrap;
|
flex-wrap : wrap;
|
||||||
|
padding: 1em
|
||||||
}
|
}
|
||||||
|
|
||||||
.tactic-inventory .tactic {
|
.tactic-inventory .tactic {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface LevelInfo {
|
|||||||
title: null|string,
|
title: null|string,
|
||||||
introduction: null|string,
|
introduction: null|string,
|
||||||
index: number,
|
index: number,
|
||||||
tactics: any[],
|
tactics: {name: string, disabled: boolean, locked: boolean}[],
|
||||||
lemmas: any[],
|
lemmas: any[],
|
||||||
descrText: null|string,
|
descrText: null|string,
|
||||||
descrFormat: null|string,
|
descrFormat: null|string,
|
||||||
|
|||||||
@@ -266,28 +266,41 @@ elab "MakeGame" : command => do
|
|||||||
|
|
||||||
-- Compute which tactics are available in which level:
|
-- Compute which tactics are available in which level:
|
||||||
let mut newTacticsInWorld : HashMap Name (HashSet Name) := {}
|
let mut newTacticsInWorld : HashMap Name (HashSet Name) := {}
|
||||||
|
let mut allTactics : HashSet Name := {}
|
||||||
for (worldId, world) in game.worlds.nodes.toArray do
|
for (worldId, world) in game.worlds.nodes.toArray do
|
||||||
let mut newTactics : HashSet Name:= {}
|
let mut newTactics : HashSet Name:= {}
|
||||||
for (_, level) in world.levels.toArray do
|
for (_, level) in world.levels.toArray do
|
||||||
newTactics := newTactics.insertMany level.newTactics
|
newTactics := newTactics.insertMany level.newTactics
|
||||||
|
allTactics := allTactics.insertMany level.newTactics
|
||||||
newTacticsInWorld := newTacticsInWorld.insert worldId newTactics
|
newTacticsInWorld := newTacticsInWorld.insert worldId newTactics
|
||||||
|
|
||||||
let mut tacticsInWorld : HashMap Name (HashSet Name) := {}
|
let tacticAvailability₀ : HashMap Name TacticAvailability :=
|
||||||
|
HashMap.ofList $
|
||||||
|
allTactics.toList.map fun name =>
|
||||||
|
(name, {name, locked := true, disabled := false})
|
||||||
|
|
||||||
|
let mut tacticsInWorld : HashMap Name (HashMap Name TacticAvailability) := {}
|
||||||
for (worldId, _) in game.worlds.nodes.toArray do
|
for (worldId, _) in game.worlds.nodes.toArray do
|
||||||
let mut tactics : HashSet Name:= {}
|
let mut tactics : HashMap Name TacticAvailability := tacticAvailability₀
|
||||||
let predecessors := game.worlds.predecessors worldId
|
let predecessors := game.worlds.predecessors worldId
|
||||||
for predWorldId in predecessors do
|
for predWorldId in predecessors do
|
||||||
tactics := tactics.insertMany (newTacticsInWorld.find! predWorldId)
|
for tac in newTacticsInWorld.find! predWorldId do
|
||||||
|
tactics := tactics.insert tac {name := tac, locked := false, disabled := false}
|
||||||
tacticsInWorld := tacticsInWorld.insert worldId tactics
|
tacticsInWorld := tacticsInWorld.insert worldId tactics
|
||||||
|
|
||||||
for (worldId, world) in game.worlds.nodes.toArray do
|
for (worldId, world) in game.worlds.nodes.toArray do
|
||||||
let mut tactics := tacticsInWorld.find! worldId
|
let mut tactics := tacticsInWorld.find! worldId
|
||||||
logInfo m!"{tactics.toArray}"
|
|
||||||
|
|
||||||
let levels := world.levels.toArray.insertionSort fun a b => a.1 < b.1
|
let levels := world.levels.toArray.insertionSort fun a b => a.1 < b.1
|
||||||
|
|
||||||
for (levelId, level) in levels do
|
for (levelId, level) in levels do
|
||||||
tactics := tactics.insertMany level.newTactics
|
for tac in level.newTactics do
|
||||||
|
tactics := tactics.insert tac {name := tac, locked := false, disabled := false}
|
||||||
|
for tac in level.disabledTactics do
|
||||||
|
tactics := tactics.insert tac {name := tac, locked := false, disabled := true}
|
||||||
|
|
||||||
|
let tacticArray := tactics.toArray
|
||||||
|
|>.insertionSort (fun a b => a.1.toString < b.1.toString)
|
||||||
|
|>.map (·.2)
|
||||||
modifyLevel ⟨← getCurGameId, worldId, levelId⟩ fun level => do
|
modifyLevel ⟨← getCurGameId, worldId, levelId⟩ fun level => do
|
||||||
return {level with tactics := ← tactics.toArray.mapM getTacticDoc!}
|
return {level with tactics := tacticArray}
|
||||||
|
|||||||
@@ -144,6 +144,12 @@ structure LevelId where
|
|||||||
level : Nat
|
level : Nat
|
||||||
deriving Inhabited
|
deriving Inhabited
|
||||||
|
|
||||||
|
structure TacticAvailability where
|
||||||
|
name : Name
|
||||||
|
locked : Bool
|
||||||
|
disabled : Bool
|
||||||
|
deriving ToJson, FromJson, Repr
|
||||||
|
|
||||||
def getCurLevelId [MonadError m] : m LevelId := do
|
def getCurLevelId [MonadError m] : m LevelId := do
|
||||||
return { game := ← getCurGameId, world := ← getCurWorldId, level := ← getCurLevelIdx}
|
return { game := ← getCurGameId, world := ← getCurWorldId, level := ← getCurLevelIdx}
|
||||||
|
|
||||||
@@ -170,7 +176,7 @@ structure GameLevel where
|
|||||||
-- only these tactics are allowed in this level (ignore if empty):
|
-- only these tactics are allowed in this level (ignore if empty):
|
||||||
onlyTactics: Array Name := default
|
onlyTactics: Array Name := default
|
||||||
-- tactics in this level (computed by `MakeGame`):
|
-- tactics in this level (computed by `MakeGame`):
|
||||||
tactics: Array TacticDocEntry := default
|
tactics: Array TacticAvailability := default
|
||||||
-- new lemmas introduces by this level:
|
-- new lemmas introduces by this level:
|
||||||
newLemmas: Array Name := default
|
newLemmas: Array Name := default
|
||||||
-- lemmas exceptionally forbidden in this level:
|
-- lemmas exceptionally forbidden in this level:
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ Fields:
|
|||||||
structure LevelInfo where
|
structure LevelInfo where
|
||||||
index : Nat
|
index : Nat
|
||||||
title : String
|
title : String
|
||||||
tactics: Array TacticDocEntry
|
tactics: Array TacticAvailability
|
||||||
lemmas: Array LemmaDocEntry
|
lemmas: Array LemmaDocEntry
|
||||||
introduction : String
|
introduction : String
|
||||||
descrText : String := ""
|
descrText : String := ""
|
||||||
|
|||||||
Reference in New Issue
Block a user