merge necessary as upstream developed while storyline slept
This commit is contained in:
+5
-1
@@ -5,11 +5,15 @@ cd $(dirname $0)
|
||||
|
||||
cd server
|
||||
|
||||
cd testgame
|
||||
cd adam
|
||||
lake update
|
||||
|
||||
cp lake-packages/mathlib/lean-toolchain lean-toolchain
|
||||
cp lake-packages/mathlib/lean-toolchain ../leanserver/lean-toolchain
|
||||
cp lake-packages/mathlib/lean-toolchain ../nng/lean-toolchain
|
||||
|
||||
cd ../leanserver
|
||||
lake update
|
||||
|
||||
cd ../nng
|
||||
lake update
|
||||
|
||||
+7
-2
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { Outlet, useParams } from "react-router-dom";
|
||||
|
||||
import '@fontsource/roboto/300.css';
|
||||
import '@fontsource/roboto/400.css';
|
||||
@@ -10,10 +10,15 @@ import '@fontsource/roboto/700.css';
|
||||
import './reset.css';
|
||||
import './app.css';
|
||||
|
||||
export const GameIdContext = React.createContext<string>(undefined);
|
||||
|
||||
function App() {
|
||||
const params = useParams();
|
||||
return (
|
||||
<div className="app">
|
||||
<Outlet />
|
||||
<GameIdContext.Provider value={params.gameId}>
|
||||
<Outlet />
|
||||
</GameIdContext.Provider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faLock, faLockOpen, faBook, faHammer, faBan } from '@fortawesome/free-solid-svg-icons'
|
||||
import Markdown from './Markdown';
|
||||
import { useLoadDocQuery, ComputedInventoryItem } from '../state/api';
|
||||
import { GameIdContext } from '../App';
|
||||
|
||||
export function Inventory({ tactics, lemmas, definitions, setInventoryDoc } :
|
||||
{lemmas: ComputedInventoryItem[],
|
||||
@@ -55,14 +56,14 @@ function InventoryList({items, docType, openDoc} : {items: ComputedInventoryItem
|
||||
).map(item => {
|
||||
if (tab == item.category) {
|
||||
return <InventoryItem key={item.name} showDoc={() => {openDoc(item.name, docType)}}
|
||||
name={item.name} locked={item.locked} disabled={item.disabled} />
|
||||
name={item.name} displayName={item.displayName} locked={item.locked} disabled={item.disabled} />
|
||||
}
|
||||
}) }
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
function InventoryItem({name, locked, disabled, showDoc}) {
|
||||
function InventoryItem({name, displayName, locked, disabled, showDoc}) {
|
||||
const icon = locked ? <FontAwesomeIcon icon={faLock} /> :
|
||||
disabled ? <FontAwesomeIcon icon={faBan} /> : ""
|
||||
const className = locked ? "locked" : disabled ? "disabled" : ""
|
||||
@@ -73,15 +74,15 @@ function InventoryItem({name, locked, disabled, showDoc}) {
|
||||
}
|
||||
}
|
||||
|
||||
return <div className={`item ${className}`} onClick={handleClick}>{icon} {name}</div>
|
||||
return <div className={`item ${className}`} onClick={handleClick}>{icon} {displayName}</div>
|
||||
}
|
||||
|
||||
export function Documentation({name, type}) {
|
||||
|
||||
const doc = useLoadDocQuery({type: type, name: name})
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const doc = useLoadDocQuery({game: gameId, type: type, name: name})
|
||||
|
||||
return <>
|
||||
<h2 className="doc">{doc.data?.name}</h2>
|
||||
<h2 className="doc">{doc.data?.displayName}</h2>
|
||||
<Markdown>{doc.data?.text}</Markdown>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import './level.css'
|
||||
import { Button } from './Button'
|
||||
import { ConnectionContext, useLeanClient } from '../connection';
|
||||
import { useGetGameInfoQuery, useLoadLevelQuery } from '../state/api';
|
||||
import { codeEdited, selectCode, progressSlice, selectCompleted } from '../state/progress';
|
||||
import { changedSelection, codeEdited, selectCode, selectSelections, progressSlice, selectCompleted } from '../state/progress';
|
||||
import { useAppDispatch, useAppSelector } from '../hooks';
|
||||
import { useStore } from 'react-redux';
|
||||
|
||||
@@ -40,6 +40,7 @@ import Markdown from './Markdown';
|
||||
|
||||
import Split from 'react-split'
|
||||
import { Alert } from '@mui/material';
|
||||
import { GameIdContext } from '../App';
|
||||
|
||||
export const MonacoEditorContext = React.createContext<monaco.editor.IStandaloneCodeEditor>(null as any);
|
||||
|
||||
@@ -75,7 +76,9 @@ function PlayableLevel({worldId, levelId}) {
|
||||
const codeviewRef = useRef<HTMLDivElement>(null)
|
||||
const introductionPanelRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const initialCode = useAppSelector(selectCode(worldId, levelId))
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const initialCode = useAppSelector(selectCode(gameId, worldId, levelId))
|
||||
const initialSelections = useAppSelector(selectSelections(gameId, worldId, levelId))
|
||||
|
||||
const [commandLineMode, setCommandLineMode] = useState(true)
|
||||
const [commandLineInput, setCommandLineInput] = useState("")
|
||||
@@ -86,6 +89,8 @@ function PlayableLevel({worldId, levelId}) {
|
||||
useEffect(() => {
|
||||
// Scroll to top when loading a new level
|
||||
introductionPanelRef.current!.scrollTo(0,0)
|
||||
// Reset command line input when loading a new level
|
||||
setCommandLineInput("")
|
||||
}, [levelId])
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -122,24 +127,48 @@ function PlayableLevel({worldId, levelId}) {
|
||||
}]);
|
||||
}
|
||||
|
||||
const connection = React.useContext(ConnectionContext)
|
||||
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
|
||||
const level = useLoadLevelQuery({world: worldId, level: levelId})
|
||||
const gameInfo = useGetGameInfoQuery({game: gameId})
|
||||
const level = useLoadLevelQuery({game: gameId, world: worldId, level: levelId})
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const onDidChangeContent = (code) => {
|
||||
dispatch(codeEdited({world: worldId, level: levelId, code}))
|
||||
dispatch(codeEdited({game: gameId, world: worldId, level: levelId, code}))
|
||||
|
||||
setCanUndo(code.trim() !== "")
|
||||
}
|
||||
|
||||
const completed = useAppSelector(selectCompleted(worldId, levelId))
|
||||
const onDidChangeSelection = (monacoSelections) => {
|
||||
const selections = monacoSelections.map(
|
||||
({selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn}) =>
|
||||
{return {selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn}})
|
||||
dispatch(changedSelection({game: gameId, world: worldId, level: levelId, selections}))
|
||||
}
|
||||
|
||||
const completed = useAppSelector(selectCompleted(gameId, worldId, levelId))
|
||||
|
||||
const {editor, infoProvider, editorConnection} =
|
||||
useLevelEditor(worldId, levelId, codeviewRef, initialCode, onDidChangeContent)
|
||||
useLevelEditor(worldId, levelId, codeviewRef, initialCode, initialSelections, onDidChangeContent, onDidChangeSelection)
|
||||
|
||||
// Effect when command line mode gets enabled
|
||||
useEffect(() => {
|
||||
if (editor && commandLineMode) {
|
||||
let endPos = editor.getModel().getFullModelRange().getEndPosition()
|
||||
if (editor.getModel().getLineContent(endPos.lineNumber).trim() !== "") {
|
||||
editor.executeEdits("command-line", [{
|
||||
range: monaco.Selection.fromPositions(endPos, endPos),
|
||||
text: "\n",
|
||||
forceMoveMarkers: true
|
||||
}]);
|
||||
}
|
||||
endPos = editor.getModel().getFullModelRange().getEndPosition()
|
||||
let currPos = editor.getPosition()
|
||||
if (currPos.column != 1 || (currPos.lineNumber != endPos.lineNumber && currPos.lineNumber != endPos.lineNumber - 1)) {
|
||||
// This is not a position that would naturally occur from CommandLine, reset:
|
||||
editor.setSelection(monaco.Selection.fromPositions(endPos, endPos))
|
||||
}
|
||||
}
|
||||
}, [editor, commandLineMode])
|
||||
|
||||
const [inventoryDoc, setInventoryDoc] = useState<{name: string, type: string}>(null)
|
||||
|
||||
@@ -151,9 +180,9 @@ function PlayableLevel({worldId, levelId}) {
|
||||
<Split minSize={0} snapOffset={200} sizes={[50, 25, 25]} className={`app-content level ${level.isLoading ? 'hidden' : ''}`}>
|
||||
<div className="exercise-panel">
|
||||
<div ref={introductionPanelRef} className="introduction-panel">
|
||||
<Alert severity="info" sx={{ mt: 1 }}>
|
||||
<div className="message info">
|
||||
<Markdown>{level?.data?.introduction}</Markdown>
|
||||
</Alert>
|
||||
</div>
|
||||
</div>
|
||||
<div className="exercise">
|
||||
{/* <h4>Aufgabe:</h4> */}
|
||||
@@ -177,10 +206,12 @@ function PlayableLevel({worldId, levelId}) {
|
||||
</EditorContext.Provider>
|
||||
|
||||
{completed && <div className="conclusion">
|
||||
<Markdown>{level?.data?.conclusion}</Markdown>
|
||||
<div className="message info">
|
||||
<Markdown>{level?.data?.conclusion}</Markdown>
|
||||
</div>
|
||||
{levelId >= gameInfo.data?.worldSize[worldId] ?
|
||||
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button> :
|
||||
<Button to={`/world/${worldId}/level/${levelId + 1}`}>
|
||||
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button> :
|
||||
<Button to={`/game/${gameId}/world/${worldId}/level/${levelId + 1}`}>
|
||||
Next <FontAwesomeIcon icon={faArrowRight} /></Button>}
|
||||
|
||||
</div>}
|
||||
@@ -200,23 +231,24 @@ function PlayableLevel({worldId, levelId}) {
|
||||
export default Level
|
||||
|
||||
function Introduction({worldId}) {
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const gameInfo = useGetGameInfoQuery({game: gameId})
|
||||
|
||||
return <>
|
||||
<div style={gameInfo.isLoading ? null : {display: "none"}} className="app-content loading"><CircularProgress /></div>
|
||||
<LevelAppBar isLoading={gameInfo.isLoading} levelTitle="Einführung" worldId={worldId} levelId={0} />
|
||||
<div style={gameInfo.isLoading ? {display: "none"} : null} className="exercise-panel">
|
||||
<div className="introduction-panel">
|
||||
<Alert severity="info" sx={{ mt: 1 }}>
|
||||
<div className="message info">
|
||||
<Markdown>
|
||||
{gameInfo.data?.worlds.nodes[worldId].introduction}
|
||||
</Markdown>
|
||||
</Alert>
|
||||
</div>
|
||||
</div>
|
||||
<div className="conclusion">
|
||||
{0 == gameInfo.data?.worldSize[worldId] ?
|
||||
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button> :
|
||||
<Button to={`/world/${worldId}/level/1`}>
|
||||
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button> :
|
||||
<Button to={`/game/${gameId}/world/${worldId}/level/1`}>
|
||||
Start <FontAwesomeIcon icon={faArrowRight} />
|
||||
</Button>}
|
||||
</div>
|
||||
@@ -225,11 +257,12 @@ function Introduction({worldId}) {
|
||||
}
|
||||
|
||||
function LevelAppBar({isLoading, levelId, worldId, levelTitle}) {
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const gameInfo = useGetGameInfoQuery({game: gameId})
|
||||
|
||||
return <div className="app-bar" style={isLoading ? {display: "none"} : null} >
|
||||
<div>
|
||||
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button>
|
||||
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button>
|
||||
<span className="app-bar-title">
|
||||
{gameInfo.data?.worlds.nodes[worldId].title && `World: ${gameInfo.data?.worlds.nodes[worldId].title}`}
|
||||
</span>
|
||||
@@ -239,19 +272,20 @@ function LevelAppBar({isLoading, levelId, worldId, levelTitle}) {
|
||||
{levelTitle}
|
||||
</span>
|
||||
<Button disabled={levelId <= 0} inverted={true}
|
||||
to={`/world/${worldId}/level/${levelId - 1}`}
|
||||
to={`/game/${gameId}/world/${worldId}/level/${levelId - 1}`}
|
||||
><FontAwesomeIcon icon={faArrowLeft} /> Previous</Button>
|
||||
<Button disabled={levelId >= gameInfo.data?.worldSize[worldId]} inverted={true}
|
||||
to={`/world/${worldId}/level/${levelId + 1}`}
|
||||
to={`/game/${gameId}/world/${worldId}/level/${levelId + 1}`}
|
||||
>Next <FontAwesomeIcon icon={faArrowRight} /></Button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCode, onDidChangeContent) {
|
||||
function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCode, initialSelections, onDidChangeContent, onDidChangeSelection) {
|
||||
|
||||
const connection = React.useContext(ConnectionContext)
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
|
||||
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
|
||||
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
|
||||
@@ -278,7 +312,7 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
||||
theme: 'vs-code-theme-converted'
|
||||
})
|
||||
|
||||
const infoProvider = new InfoProvider(connection.getLeanClient())
|
||||
const infoProvider = new InfoProvider(connection.getLeanClient(gameId))
|
||||
|
||||
const editorApi = infoProvider.getApi()
|
||||
|
||||
@@ -328,7 +362,7 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
||||
return () => { infoProvider.dispose(); editor.dispose() }
|
||||
}, [])
|
||||
|
||||
const {leanClient, leanClientStarted} = useLeanClient()
|
||||
const {leanClient, leanClientStarted} = useLeanClient(gameId)
|
||||
|
||||
// Create model when level changes
|
||||
useEffect(() => {
|
||||
@@ -340,8 +374,11 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
||||
model = monaco.editor.createModel(initialCode, 'lean4', uri)
|
||||
}
|
||||
model.onDidChangeContent(() => onDidChangeContent(model.getValue()))
|
||||
editor.onDidChangeCursorSelection(() => onDidChangeSelection(editor.getSelections()))
|
||||
editor.setModel(model)
|
||||
editor.setPosition(model.getFullModelRange().getEndPosition())
|
||||
if (initialSelections) {
|
||||
editor.setSelections(initialSelections)
|
||||
}
|
||||
|
||||
infoviewApi.serverRestarted(leanClient.initializeResult)
|
||||
infoProvider.openPreview(editor, infoviewApi)
|
||||
@@ -358,7 +395,8 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
||||
|
||||
/** Open all files in this world on the server so that they will load faster when accessed */
|
||||
function useLoadWorldFiles(worldId) {
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const gameInfo = useGetGameInfoQuery({game: gameId})
|
||||
const store = useStore()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -370,7 +408,7 @@ function useLoadWorldFiles(worldId) {
|
||||
if (model) {
|
||||
models.push(model)
|
||||
} else {
|
||||
const code = selectCode(worldId, levelId)(store.getState())
|
||||
const code = selectCode(gameId, worldId, levelId)(store.getState())
|
||||
models.push(monaco.editor.createModel(code, 'lean4', uri))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { faShield } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import * as React from 'react'
|
||||
|
||||
const PrivacyPolicy: React.FC = () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const handleOpen = () => setOpen(true);
|
||||
const handleClose = () => setOpen(false);
|
||||
|
||||
return (
|
||||
<span>
|
||||
<div className="privacy" onClick={handleOpen} title="Privacy Policy & Impressum">
|
||||
<FontAwesomeIcon icon={faShield} />
|
||||
<p className="p1">legal</p>
|
||||
<p className="p2">notes</p>
|
||||
</div>
|
||||
{open?
|
||||
<div className="modal-wrapper">
|
||||
<div className="modal-backdrop" onClick={handleClose} />
|
||||
<div className="modal">
|
||||
<div className="codicon codicon-close modal-close" onClick={handleClose}></div>
|
||||
<h2>Privacy Policy & Impressum</h2>
|
||||
|
||||
<p>Our server collects metadata (such as IP address, browser, operating system)
|
||||
and the data that the user enters into the editor. The data is used to
|
||||
compute the Lean output and display it to the user. The information will be stored
|
||||
as long as the user stays on our website and will be deleted immediately afterwards.
|
||||
We keep logs to improve our software, but the contained data is anonymized.</p>
|
||||
|
||||
<p>We do not use cookies, but your game progress is stored in the browser
|
||||
as site data. Your game progress is not saved on the server; if you delete
|
||||
your browser storage, it is completely gone.
|
||||
</p>
|
||||
|
||||
<p>Our server is located in Germany.</p>
|
||||
|
||||
<p><strong>Contact information:</strong><br />
|
||||
Jon Eugster<br />
|
||||
Mathematisches Institut der Heinrich-Heine-Universität Düsseldorf<br />
|
||||
Universitätsstr. 1<br />
|
||||
40225 Düsseldorf<br />
|
||||
Germany<br />
|
||||
<a href="mailto:jon.eugster@hhu.de">jon.eugster@hhu.de</a>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div> : null}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default PrivacyPolicy
|
||||
@@ -5,7 +5,9 @@ import cytoscape, { LayoutOptions } from 'cytoscape'
|
||||
import klay from 'cytoscape-klay';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Split from 'react-split'
|
||||
|
||||
import PrivacyPolicy from './PrivacyPolicy';
|
||||
|
||||
cytoscape.use( klay );
|
||||
|
||||
@@ -14,14 +16,25 @@ import { useGetGameInfoQuery } from '../state/api';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Markdown from './Markdown';
|
||||
import { selectCompleted } from '../state/progress';
|
||||
import { GameIdContext } from '../App';
|
||||
|
||||
const N = 24 // max number of levels per world
|
||||
const R = 800 // radius of a world
|
||||
const r = 110 // radius of a level
|
||||
const s = 100 // global scale
|
||||
const padding = 2000 // padding of the graphic (on a different scale)
|
||||
|
||||
function LevelIcon({ worldId, levelId, position }) {
|
||||
const completed = useSelector(selectCompleted(worldId,levelId))
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const completed = useSelector(selectCompleted(gameId, worldId,levelId))
|
||||
|
||||
const x = s * position.x + Math.sin(levelId * 2 * Math.PI / N) * (R + 1.2*r + 2*Math.floor((levelId - 1)/N))
|
||||
const y = s * position.y - Math.cos(levelId * 2 * Math.PI / N) * (R + 1.2*r + 2*Math.floor((levelId - 1)/N))
|
||||
|
||||
// TODO: relative positioning?
|
||||
return (
|
||||
<Link to={`/world/${worldId}/level/${levelId}`} key={`/world/${worldId}/level/${levelId}`}>
|
||||
<circle fill={completed ? "green" :"#aaa"} cx={position.x + Math.sin(levelId/5) * 9} cy={position.y - Math.cos(levelId/5) * 9} r="0.8" />
|
||||
<Link to={`/game/${gameId}/world/${worldId}/level/${levelId}`} key={`/game/${gameId}/world/${worldId}/level/${levelId}`}>
|
||||
<circle fill={completed ? "green" :"#999"} cx={x} cy={y} r={r} />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -29,7 +42,8 @@ function LevelIcon({ worldId, levelId, position }) {
|
||||
function Welcome() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
const gameInfo = useGetGameInfoQuery({game: gameId})
|
||||
|
||||
const { nodes, bounds }: any = gameInfo.data ? computeWorldLayout(gameInfo.data?.worlds) : {nodes: []}
|
||||
|
||||
@@ -39,56 +53,66 @@ function Welcome() {
|
||||
}
|
||||
}, [gameInfo.data?.title])
|
||||
|
||||
const padding = 20
|
||||
|
||||
const svgElements = []
|
||||
|
||||
if (gameInfo.data) {
|
||||
for (let i in gameInfo.data.worlds.edges) {
|
||||
const edge = gameInfo.data.worlds.edges[i]
|
||||
svgElements.push(
|
||||
<line key={`pathway${i}`} x1={nodes[edge[0]].position.x} y1={nodes[edge[0]].position.y}
|
||||
x2={nodes[edge[1]].position.x} y2={nodes[edge[1]].position.y} stroke="#1976d2" strokeWidth="1"/>
|
||||
<line key={`pathway${i}`} x1={s*nodes[edge[0]].position.x} y1={s*nodes[edge[0]].position.y}
|
||||
x2={s*nodes[edge[1]].position.x} y2={s*nodes[edge[1]].position.y} stroke="#1976d2" strokeWidth={s}/>
|
||||
)
|
||||
}
|
||||
|
||||
for (let id in nodes) {
|
||||
let position: cytoscape.Position = nodes[id].position
|
||||
|
||||
svgElements.push(
|
||||
<Link key={`world${id}`} to={`/world/${id}/level/0`}>
|
||||
<circle className="world-circle" cx={position.x} cy={position.y} r="8" />
|
||||
<text className="world-name"
|
||||
x={position.x} y={position.y}>{nodes[id].data.title ? nodes[id].data.title : id}</text>
|
||||
</Link>
|
||||
)
|
||||
|
||||
for (let i = 1; i <= gameInfo.data.worldSize[id]; i++) {
|
||||
svgElements.push(
|
||||
<LevelIcon position={position} worldId={id} levelId={i} />
|
||||
)
|
||||
}
|
||||
|
||||
svgElements.push(
|
||||
<Link key={`world${id}`} to={`/game/${gameId}/world/${id}/level/0`}>
|
||||
<circle className="world-circle" cx={s*position.x} cy={s*position.y} r={R}
|
||||
fill="#1976d2"/>
|
||||
<foreignObject className="world-title-wrapper" x={s*position.x} y={s*position.y}
|
||||
width={1.42*R} height={1.42*R} transform={"translate("+ -.71*R +","+ -.71*R +")"}>
|
||||
<div>
|
||||
<p className="world-title" style={{fontSize: Math.floor(R/4) + "px"}}>
|
||||
{nodes[id].data.title ? nodes[id].data.title : id}
|
||||
</p>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return <div>
|
||||
return <div className="app-content ">
|
||||
{ gameInfo.isLoading?
|
||||
<Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
|
||||
<Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
:
|
||||
<div className="app-content">
|
||||
<Box sx={{ m: 3 }}>
|
||||
<Typography variant="body1" component="div">
|
||||
<Split className="welcome" minSize={200} sizes={[70, 30]}>
|
||||
<div className="column">
|
||||
<Typography variant="body1" component="div" className="welcome-text">
|
||||
<Markdown>{gameInfo.data?.introduction}</Markdown>
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box textAlign='center' sx={{ m: 5 }}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="30%"
|
||||
viewBox={bounds ? `${bounds.x1 - padding} ${bounds.y1 - padding} ${bounds.x2 - bounds.x1 + 2 * padding} ${bounds.y2 - bounds.y1 + 2 * padding}` : ''}>
|
||||
{svgElements}
|
||||
</svg>
|
||||
</Box>
|
||||
</div>
|
||||
</div>
|
||||
<div className="column">
|
||||
<Box textAlign='center' sx={{ m: 5 }}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox={bounds ? `${s*bounds.x1 - padding} ${s*bounds.y1 - padding} ${s*bounds.x2 - s*bounds.x1 + 2 * padding} ${s*bounds.y2 - s*bounds.y1 + 2 * padding}` : ''}>
|
||||
{svgElements}
|
||||
</svg>
|
||||
</Box>
|
||||
</div>
|
||||
</Split>
|
||||
}
|
||||
|
||||
<PrivacyPolicy/>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -116,9 +140,8 @@ function computeWorldLayout(worlds) {
|
||||
headless: true,
|
||||
styleEnabled: false
|
||||
})
|
||||
// TODO: Jon play around with graph layout
|
||||
|
||||
const layout = cy.layout({name: "klay", klay: {direction: "DOWN"}} as LayoutOptions).run()
|
||||
const layout = cy.layout({name: "klay", klay: {direction: "DOWN", nodePlacement: "LINEAR_SEGMENTS"}} as LayoutOptions).run()
|
||||
let nodes = {}
|
||||
cy.nodes().forEach((node, id) => {
|
||||
nodes[node.id()] = {
|
||||
|
||||
@@ -170,21 +170,6 @@ export function CommandLine() {
|
||||
return () => { l.dispose() }
|
||||
}, [oneLineEditor, runCommand])
|
||||
|
||||
// Effect when command line mode gets enabled
|
||||
useEffect(() => {
|
||||
if (commandLineMode) {
|
||||
const endPos = editor.getModel().getFullModelRange().getEndPosition()
|
||||
if (editor.getModel().getLineContent(endPos.lineNumber).trim() !== "") {
|
||||
editor.executeEdits("command-line", [{
|
||||
range: monaco.Selection.fromPositions(endPos, endPos),
|
||||
text: commandLineInput + "\n",
|
||||
forceMoveMarkers: false
|
||||
}]);
|
||||
}
|
||||
editor.setPosition(editor.getModel().getFullModelRange().getEndPosition())
|
||||
}
|
||||
}, [commandLineMode])
|
||||
|
||||
const handleSubmit : React.FormEventHandler<HTMLFormElement> = (ev) => {
|
||||
ev.preventDefault()
|
||||
runCommand()
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Alert, FormControlLabel, Switch } from '@mui/material';
|
||||
import Markdown from '../Markdown';
|
||||
|
||||
function Hint({hint} : {hint: GameHint}) {
|
||||
return <Alert severity="info" sx={{ mt: 1 }}><Markdown>{hint.text}</Markdown></Alert>
|
||||
return <div className="message info"><Markdown>{hint.text}</Markdown></div>
|
||||
}
|
||||
|
||||
export function Hints({hints} : {hints: GameHint[]}) {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
}
|
||||
.message.information {
|
||||
color: #059;
|
||||
background-color: #BEF;
|
||||
.message.info {
|
||||
/* color: #059; */
|
||||
background-color: #DDF6FF;
|
||||
}
|
||||
.message.warning {
|
||||
color: #9F6000;
|
||||
|
||||
@@ -18,11 +18,13 @@ import { EditorContext, ConfigContext, ProgressContext, VersionContext } from '.
|
||||
import { WithRpcSessions } from '../../../../node_modules/lean4-infoview/src/infoview/rpcSessions';
|
||||
import { ServerVersion } from '../../../../node_modules/lean4-infoview/src/infoview/serverVersion';
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import { codeEdited, levelCompleted, selectCompleted } from '../../state/progress';
|
||||
import { levelCompleted, selectCompleted } from '../../state/progress';
|
||||
import { GameIdContext } from '../../App';
|
||||
|
||||
|
||||
export function Main(props: {world: string, level: number}) {
|
||||
const ec = React.useContext(EditorContext);
|
||||
const gameId = React.useContext(GameIdContext)
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
@@ -33,13 +35,13 @@ export function Main(props: {world: string, level: number}) {
|
||||
|
||||
if (ec.events.changedCursorLocation.current &&
|
||||
ec.events.changedCursorLocation.current.uri === params.uri) {
|
||||
dispatch(levelCompleted({world: props.world, level: props.level}))
|
||||
dispatch(levelCompleted({game: gameId, world: props.world, level: props.level}))
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const completed = useAppSelector(selectCompleted(props.world, props.level))
|
||||
const completed = useAppSelector(selectCompleted(gameId, props.world, props.level))
|
||||
|
||||
/* Set up updates to the global infoview state on editor events. */
|
||||
const config = useEventResult(ec.events.changedInfoviewConfig) ?? defaultInfoviewConfig;
|
||||
|
||||
@@ -1,12 +1,191 @@
|
||||
|
||||
svg .world-circle {
|
||||
/* svg .world-circle {
|
||||
fill: var(--clr-primary)
|
||||
} */
|
||||
|
||||
.welcome {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
svg .world-name {
|
||||
fill: white;
|
||||
font-size: 2px;
|
||||
font-weight: 500;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
.app-content {
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.welcome .column {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.1em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h5, h6 {
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/***************/
|
||||
/* SVG Graphic */
|
||||
/***************/
|
||||
|
||||
svg .world-title-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
svg .world-title-wrapper div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
svg .world-title-wrapper div {
|
||||
display: flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
overflow: visible;
|
||||
|
||||
}
|
||||
|
||||
svg .world-title {
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Privacy Button */
|
||||
/******************/
|
||||
|
||||
.privacy {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 25px;
|
||||
border-radius: 20px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
display: flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
color: #aaa;
|
||||
background-color: #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.privacy p {
|
||||
position: absolute;
|
||||
color: #888;
|
||||
bottom: 1.5px;
|
||||
font-size: 6px;
|
||||
}
|
||||
|
||||
.privacy .p1 {
|
||||
transform: rotate(50deg);
|
||||
left: 1.5px;
|
||||
}
|
||||
|
||||
.privacy .p2 {
|
||||
transform: rotate(-50deg);
|
||||
right: 1.5px;
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* Privacy Popup */
|
||||
/*****************/
|
||||
|
||||
.modal-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.modal h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
min-width: 50%;
|
||||
max-width: 60ch;
|
||||
background: #fff;
|
||||
z-index: 3;
|
||||
padding: 2em;
|
||||
border-radius: 1em;
|
||||
text-align: left;
|
||||
color: var(--vscode-breadcrumb-foreground);
|
||||
}
|
||||
|
||||
.modal input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal .form-error {
|
||||
color: #a00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.modal input[type="submit"] {
|
||||
border: none;
|
||||
color: var(--vscode-button-foreground);
|
||||
background: var(--vscode-button-background);
|
||||
cursor: pointer;
|
||||
padding: .5em 1em;
|
||||
border-radius: .2em;
|
||||
display: block;
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
float: right;
|
||||
scale: 2;
|
||||
color: var(--vscode-breadcrumb-foreground);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
float: right;
|
||||
scale: 2;
|
||||
color: var(--vscode-breadcrumb-focusForeground);
|
||||
}
|
||||
|
||||
.modal table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,17 @@ import { useState } from 'react';
|
||||
|
||||
|
||||
export class Connection {
|
||||
private leanClient = null
|
||||
|
||||
getLeanClient(): LeanClient {
|
||||
if (this.leanClient === null) {
|
||||
const socketUrl = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + '/websocket/'
|
||||
private game: string = undefined // We only keep a connection to a single game at a time
|
||||
private leanClient: LeanClient = null
|
||||
|
||||
getLeanClient(game): LeanClient {
|
||||
if (this.game !== game) {
|
||||
if (this.leanClient) {
|
||||
this.leanClient.stop() // Stop previous Lean client
|
||||
}
|
||||
this.game = game
|
||||
// Start a new Lean client for the new `gameId`.
|
||||
const socketUrl = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + '/websocket/' + game
|
||||
const uri = monaco.Uri.parse('file:///')
|
||||
this.leanClient = new LeanClient(socketUrl, undefined, uri, () => {})
|
||||
}
|
||||
@@ -22,9 +27,9 @@ export class Connection {
|
||||
/** If not already started, starts the Lean client. resolves the returned promise as soon as a
|
||||
* Lean client is running.
|
||||
*/
|
||||
startLeanClient = () => {
|
||||
startLeanClient = (game) => {
|
||||
return new Promise<LeanClient>((resolve) => {
|
||||
const leanClient = this.getLeanClient()
|
||||
const leanClient = this.getLeanClient(game)
|
||||
if (leanClient.isRunning()) {
|
||||
resolve(leanClient)
|
||||
} else {
|
||||
@@ -47,8 +52,8 @@ export const connection = new Connection()
|
||||
|
||||
export const ConnectionContext = React.createContext(null);
|
||||
|
||||
export const useLeanClient = () => {
|
||||
const leanClient = connection.getLeanClient()
|
||||
export const useLeanClient = (gameId) => {
|
||||
const leanClient = connection.getLeanClient(gameId)
|
||||
const [leanClientStarted, setLeanClientStarted] = useState(leanClient.isStarted())
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
@@ -13,21 +13,26 @@ import ErrorPage from './ErrorPage';
|
||||
import Welcome from './components/Welcome';
|
||||
import Level from './components/Level';
|
||||
import { monacoSetup } from 'lean4web/client/src/monacoSetup';
|
||||
import { redirect } from 'react-router-dom';
|
||||
|
||||
monacoSetup()
|
||||
|
||||
const router = createHashRouter([
|
||||
{
|
||||
path: "/",
|
||||
loader: () => redirect("/game/adam")
|
||||
},
|
||||
{
|
||||
path: "/game/:gameId",
|
||||
element: <App />,
|
||||
errorElement: <ErrorPage />,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
path: "/game/:gameId",
|
||||
element: <Welcome />,
|
||||
},
|
||||
{
|
||||
path: "/world/:worldId/level/:levelId",
|
||||
path: "/game/:gameId/world/:worldId/level/:levelId",
|
||||
element: <Level />,
|
||||
},
|
||||
],
|
||||
|
||||
+10
-8
@@ -12,6 +12,7 @@ interface GameInfo {
|
||||
|
||||
export interface ComputedInventoryItem {
|
||||
name: string,
|
||||
displayName: string,
|
||||
category: string,
|
||||
disabled: boolean,
|
||||
locked: boolean
|
||||
@@ -31,18 +32,19 @@ interface LevelInfo {
|
||||
|
||||
interface Doc {
|
||||
name: string,
|
||||
displayName: string,
|
||||
text: string
|
||||
}
|
||||
|
||||
|
||||
const customBaseQuery = async (
|
||||
args : {method: string, params?: any},
|
||||
args : {game: string, method: string, params?: any},
|
||||
{ signal, dispatch, getState, extra },
|
||||
extraOptions
|
||||
) => {
|
||||
try {
|
||||
const connection : Connection = extra.connection
|
||||
let leanClient = await connection.startLeanClient()
|
||||
let leanClient = await connection.startLeanClient(args.game)
|
||||
console.log(`Sending request ${args.method}`)
|
||||
let res = await leanClient.sendRequest(args.method, args.params)
|
||||
console.log('Received response', res)
|
||||
@@ -57,14 +59,14 @@ export const apiSlice = createApi({
|
||||
reducerPath: 'gameApi',
|
||||
baseQuery: customBaseQuery,
|
||||
endpoints: (builder) => ({
|
||||
getGameInfo: builder.query<GameInfo, void>({
|
||||
query: () => {return {method: 'info', params: {}}},
|
||||
getGameInfo: builder.query<GameInfo, {game: string}>({
|
||||
query: ({game}) => {return {game, method: 'info', params: {}}},
|
||||
}),
|
||||
loadLevel: builder.query<LevelInfo, {world: string, level: number}>({
|
||||
query: ({world, level}) => {return {method: "loadLevel", params: {world, level}}},
|
||||
loadLevel: builder.query<LevelInfo, {game: string, world: string, level: number}>({
|
||||
query: ({game, world, level}) => {return {game, method: "loadLevel", params: {world, level}}},
|
||||
}),
|
||||
loadDoc: builder.query<Doc, {name: string, type: "lemma"|"tactic"}>({
|
||||
query: ({name, type}) => {return {method: "loadDoc", params: {name, type}}},
|
||||
loadDoc: builder.query<Doc, {game: string, name: string, type: "lemma"|"tactic"}>({
|
||||
query: ({game, name, type}) => {return {game, method: "loadDoc", params: {name, type}}},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const KEY = "progress";
|
||||
const KEY = "game_progress";
|
||||
export function loadState() {
|
||||
try {
|
||||
const serializedState = localStorage.getItem(KEY);
|
||||
|
||||
@@ -3,23 +3,32 @@ import type { PayloadAction } from '@reduxjs/toolkit'
|
||||
import { loadState } from "./localStorage";
|
||||
|
||||
interface ProgressState {
|
||||
level: {[world: string]: {[level: number]: LevelProgressState}}
|
||||
level: {[game: string]: {[world: string]: {[level: number]: LevelProgressState}}}
|
||||
}
|
||||
interface Selection {
|
||||
selectionStartLineNumber: number,
|
||||
selectionStartColumn: number,
|
||||
positionLineNumber: number
|
||||
positionColumn: number
|
||||
}
|
||||
|
||||
interface LevelProgressState {
|
||||
code: string,
|
||||
selections: Selection[],
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
const initialProgressState = loadState() ?? { level: {} } as ProgressState
|
||||
const initalLevelProgressState = {code: "", completed: false} as LevelProgressState
|
||||
|
||||
function addLevelProgress(state, action: PayloadAction<{world: string, level: number}>) {
|
||||
if (!state.level[action.payload.world]) {
|
||||
state.level[action.payload.world] = {}
|
||||
function addLevelProgress(state, action: PayloadAction<{game: string, world: string, level: number}>) {
|
||||
if (!state.level[action.payload.game]) {
|
||||
state.level[action.payload.game] = {}
|
||||
}
|
||||
if (!state.level[action.payload.world][action.payload.level]) {
|
||||
state.level[action.payload.world][action.payload.level] = {...initalLevelProgressState}
|
||||
if (!state.level[action.payload.game][action.payload.world]) {
|
||||
state.level[action.payload.game][action.payload.world] = {}
|
||||
}
|
||||
if (!state.level[action.payload.game][action.payload.world][action.payload.level]) {
|
||||
state.level[action.payload.game][action.payload.world][action.payload.level] = {...initalLevelProgressState}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,35 +36,46 @@ export const progressSlice = createSlice({
|
||||
name: 'progress',
|
||||
initialState: initialProgressState,
|
||||
reducers: {
|
||||
codeEdited(state, action: PayloadAction<{world: string, level: number, code: string}>) {
|
||||
codeEdited(state, action: PayloadAction<{game: string, world: string, level: number, code: string}>) {
|
||||
addLevelProgress(state, action)
|
||||
state.level[action.payload.world][action.payload.level].code = action.payload.code
|
||||
state.level[action.payload.world][action.payload.level].completed = false
|
||||
state.level[action.payload.game][action.payload.world][action.payload.level].code = action.payload.code
|
||||
state.level[action.payload.game][action.payload.world][action.payload.level].completed = false
|
||||
},
|
||||
levelCompleted(state, action: PayloadAction<{world: string, level: number}>) {
|
||||
changedSelection(state, action: PayloadAction<{game: string, world: string, level: number, selections: Selection[]}>) {
|
||||
addLevelProgress(state, action)
|
||||
state.level[action.payload.world][action.payload.level].completed = true
|
||||
state.level[action.payload.game][action.payload.world][action.payload.level].selections = action.payload.selections
|
||||
},
|
||||
levelCompleted(state, action: PayloadAction<{game: string, world: string, level: number}>) {
|
||||
addLevelProgress(state, action)
|
||||
state.level[action.payload.game][action.payload.world][action.payload.level].completed = true
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export function selectLevel(world: string, level: number) {
|
||||
export function selectLevel(game: string, world: string, level: number) {
|
||||
return (state) =>{
|
||||
if (!state.progress.level[world]) { return initalLevelProgressState }
|
||||
if (!state.progress.level[world][level]) { return initalLevelProgressState }
|
||||
return state.progress.level[world][level]
|
||||
if (!state.progress.level[game]) { return initalLevelProgressState }
|
||||
if (!state.progress.level[game][world]) { return initalLevelProgressState }
|
||||
if (!state.progress.level[game][world][level]) { return initalLevelProgressState }
|
||||
return state.progress.level[game][world][level]
|
||||
}
|
||||
}
|
||||
|
||||
export function selectCode(world: string, level: number) {
|
||||
export function selectCode(game: string, world: string, level: number) {
|
||||
return (state) => {
|
||||
return selectLevel(world, level)(state).code
|
||||
return selectLevel(game, world, level)(state).code
|
||||
}
|
||||
}
|
||||
|
||||
export function selectCompleted(world: string, level: number) {
|
||||
export function selectSelections(game: string, world: string, level: number) {
|
||||
return (state) => {
|
||||
return selectLevel(world, level)(state).completed
|
||||
return selectLevel(game, world, level)(state).selections
|
||||
}
|
||||
}
|
||||
|
||||
export function selectCompleted(game: string, world: string, level: number) {
|
||||
return (state) => {
|
||||
return selectLevel(game, world, level)(state).completed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +85,4 @@ export function selectProgress() {
|
||||
}
|
||||
}
|
||||
|
||||
export const { codeEdited, levelCompleted } = progressSlice.actions
|
||||
export const { changedSelection, codeEdited, levelCompleted } = progressSlice.actions
|
||||
|
||||
Generated
+23
@@ -18,6 +18,7 @@
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-elk": "^2.1.0",
|
||||
"cytoscape-klay": "^3.1.4",
|
||||
"debounce": "^1.2.1",
|
||||
"express": "^4.18.2",
|
||||
@@ -34,6 +35,7 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"vscode-ws-jsonrpc": "^2.0.1",
|
||||
"web-worker": "^1.2.0",
|
||||
"ws": "^8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -4180,6 +4182,17 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cytoscape-elk": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape-elk/-/cytoscape-elk-2.1.0.tgz",
|
||||
"integrity": "sha512-stkKoUTNOqpyP5eMuqatK0EYir2NWGTH+XlY0rxFj0t0HiQPGI4AuSuTPaGbNM1WhVfb0tWJ5TQQ0R0qshACLw==",
|
||||
"dependencies": {
|
||||
"elkjs": "^0.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cytoscape": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cytoscape-klay": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape-klay/-/cytoscape-klay-3.1.4.tgz",
|
||||
@@ -4435,6 +4448,11 @@
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz",
|
||||
"integrity": "sha512-Vp3CVhmYpgf4iXNKAucoQUDcCrBQX3XLBtwgFqP9BUXuucgvAV9zWp1kYU7LL9j4++s9O+12cb3wMtN4SJy6UQ=="
|
||||
},
|
||||
"node_modules/elkjs": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz",
|
||||
"integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ=="
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
@@ -9869,6 +9887,11 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/web-worker": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
|
||||
"integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA=="
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
|
||||
+3
-1
@@ -14,6 +14,7 @@
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-elk": "^2.1.0",
|
||||
"cytoscape-klay": "^3.1.4",
|
||||
"debounce": "^1.2.1",
|
||||
"express": "^4.18.2",
|
||||
@@ -30,6 +31,7 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"vscode-ws-jsonrpc": "^2.0.1",
|
||||
"web-worker": "^1.2.0",
|
||||
"ws": "^8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -56,7 +58,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "concurrently -n server,client -c blue,green \"npm run start_server\" \"npm run start_client\"",
|
||||
"start_server": "cd server && (cd leanserver && lake build) && (cd testgame && lake exe cache get && lake build) && NODE_ENV=development nodemon -e mjs --exec \"node ./index.mjs\"",
|
||||
"start_server": "cd server && (cd leanserver && lake build) && (cd adam && lake exe cache get && lake build) && (cd nng && lake build) && NODE_ENV=development nodemon -e mjs --exec \"node ./index.mjs\"",
|
||||
"start_client": "NODE_ENV=development webpack-dev-server --hot",
|
||||
"build": "npm run build_server && npm run build_client",
|
||||
"build_server": "server/build.sh",
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Adam.Levels.Proposition
|
||||
import Adam.Levels.Implication
|
||||
import Adam.Levels.Predicate
|
||||
import Adam.Levels.Contradiction
|
||||
-- import Adam.Levels.Prime
|
||||
import Adam.Levels.Sum
|
||||
-- import Adam.Levels.Induction
|
||||
|
||||
import Adam.Levels.Numbers
|
||||
import Adam.Levels.Inequality
|
||||
|
||||
import Adam.Levels.Lean
|
||||
import Adam.Levels.SetTheory
|
||||
import Adam.Levels.Function
|
||||
import Adam.Levels.SetFunction
|
||||
import Adam.Levels.LinearAlgebra
|
||||
|
||||
|
||||
|
||||
Game "Adam"
|
||||
Title "Lean 4 game"
|
||||
Introduction
|
||||
"
|
||||
"
|
||||
|
||||
Conclusion
|
||||
"Fertig!"
|
||||
|
||||
|
||||
Path Proposition → Implication → Predicate → Predicate → Contradiction → Sum → Lean
|
||||
Path Predicate → Inequality → Sum
|
||||
-- Path Inequality → Prime
|
||||
-- Path Sum → Inequality -- → Induction
|
||||
|
||||
Path Lean → SetTheory → SetTheory2 → SetFunction → Module
|
||||
Path Lean → Function → SetFunction
|
||||
|
||||
|
||||
Path SetTheory2 → Numbers
|
||||
Path Module → Basis → Module2
|
||||
|
||||
MakeGame
|
||||
@@ -0,0 +1,514 @@
|
||||
import GameServer.Commands
|
||||
|
||||
-- Wird im Level "Implication 11" ohne Beweis angenommen.
|
||||
LemmaDoc not_not as "not_not" in "Logic"
|
||||
"
|
||||
`not_not {A : Prop} : ¬¬A ↔ A`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `Classical`
|
||||
* Minimal Import: `Std.Logic`
|
||||
* Mathlib Doc: [#not_not](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Classical.not_not)
|
||||
"
|
||||
|
||||
-- Wird im Level "Implication 10" ohne Beweis angenommen.
|
||||
LemmaDoc not_or_of_imp as "not_or_of_imp" in "Logic"
|
||||
"
|
||||
`not_or_of_imp {A B : Prop} : (A → B) → ¬A ∨ B`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `-`
|
||||
* Minimal Import: `Mathlib.Logic.Basic`
|
||||
* Mathlib Doc: [#not_or_of_imp](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#not_or_of_imp)
|
||||
"
|
||||
|
||||
-- Wird im Level "Implication 12" bewiesen.
|
||||
LemmaDoc imp_iff_not_or as "imp_iff_not_or" in "Logic"
|
||||
"
|
||||
`imp_iff_not_or {A B : Prop} : (A → B) ↔ (¬A ∨ B)`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `-`
|
||||
* Minimal Import: `Mathlib.Logic.Basic`
|
||||
* Mathlib Doc: [#imp_iff_not_or](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#imp_iff_not_or)
|
||||
"
|
||||
|
||||
LemmaDoc Nat.succ_pos as "succ_pos" in "Nat"
|
||||
"
|
||||
`Nat.succ_pos (n : ℕ) : 0 < n.succ`
|
||||
|
||||
$n + 1$ ist strikt grösser als Null.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp` Lemma: Nein
|
||||
* Namespace: `Nat`
|
||||
* Minimal Import: `Mathlib.Init.Prelude`
|
||||
* Mathlib Doc: [#Nat.succ_pos](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#Nat.succ_pos)
|
||||
"
|
||||
|
||||
LemmaDoc Nat.pos_iff_ne_zero as "pos_iff_ne_zero" in "Nat"
|
||||
"
|
||||
`Nat.pos_iff_ne_zero {n : ℕ} : 0 < n ↔ n ≠ 0`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Nat`
|
||||
* Minimal Import: `Std.Data.Nat.Lemmas`
|
||||
* Mathlib Doc: [#Nat.pos_iff_ne_zero](https://leanprover-community.github.io/mathlib4_docs/Std/Data/Nat/Lemmas.html#Nat.pos_iff_ne_zero)
|
||||
"
|
||||
|
||||
-- TODO: Not minimal description
|
||||
LemmaDoc zero_add as "zero_add" in "Addition"
|
||||
"
|
||||
`zero_add (a : ℕ) : 0 + a = a`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `-`
|
||||
* Import: `Mathlib.Nat.Basic`
|
||||
* Mathlib Doc: [#zero_add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Group/Defs.html#zero_add)
|
||||
"
|
||||
|
||||
LemmaDoc add_zero as "add_zero" in "Addition"
|
||||
"
|
||||
This lemma says `∀ a : ℕ, a + 0 = a`.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc"
|
||||
|
||||
LemmaDoc add_succ as "add_succ" in "Addition"
|
||||
"This lemma says `∀ a b : ℕ, a + succ b = succ (a + b)`.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#]()"
|
||||
|
||||
LemmaDoc not_forall as "not_forall" in "Logic"
|
||||
"
|
||||
`not_forall {α : Sort _} {P : α → Prop} : ¬(∀ x, → P x) ↔ ∃ x, ¬P x`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `-`
|
||||
* Minimal Import: `Mathlib.Logic.Basic`
|
||||
* Mathlib Doc: [#not_forall](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#not_forall)
|
||||
"
|
||||
|
||||
LemmaDoc not_exists as "not_exists" in "Logic"
|
||||
"
|
||||
`not_exists {α : Sort _} {P : α → Prop} : (¬∃ x, P x) ↔ ∀ (x : α), ¬P x.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `-`
|
||||
* Minimal Import: `Std.Logic`
|
||||
* Mathlib Doc: [#not_exists](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#not_exists)"
|
||||
|
||||
LemmaDoc Nat.even_iff_not_odd as "even_iff_not_odd" in "Nat"
|
||||
"
|
||||
`even_iff_not_odd {n : ℕ} : Even n ↔ ¬Odd n`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Nat`
|
||||
* Minimal Import: `Mathlib.Data.Nat.Parity`
|
||||
* Mathlib Doc: [#Nat.even_iff_not_odd](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Parity.html#Nat.even_iff_not_odd)"
|
||||
|
||||
LemmaDoc Nat.odd_iff_not_even as "odd_iff_not_even" in "Nat"
|
||||
"
|
||||
`Nat.odd_iff_not_even {n : ℕ} : Odd n ↔ ¬Even n`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `Nat`
|
||||
* Minimal Import: `Mathlib.Data.Nat.Parity`
|
||||
* Mathlib Doc: [#Nat.odd_iff_not_even](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Parity.html#Nat.odd_iff_not_even)"
|
||||
|
||||
LemmaDoc even_square as "even_square" in "Nat"
|
||||
"
|
||||
`even_square : (n : ℕ), Even n → Even (n ^ 2)`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* *Nicht in Mathlib*
|
||||
"
|
||||
|
||||
|
||||
|
||||
|
||||
LemmaDoc Set.mem_univ as "mem_univ" in "Set"
|
||||
"
|
||||
`Set.mem_univ {α : Type _} (x : α) : x ∈ @univ α`
|
||||
|
||||
Jedes Element ist in `univ`, der Menge aller Elemente eines Typs `α`.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `Set`
|
||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
||||
* Mathlib Doc: [#mem_univ](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.mem_univ)
|
||||
"
|
||||
|
||||
LemmaDoc not_mem_empty as "not_mem_empty" in "Set"
|
||||
"
|
||||
`Set.not_mem_empty {α : Type _} (x : α) : x ∉ ∅`
|
||||
|
||||
Kein Element ist in der leeren Menge.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Set`
|
||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
||||
* Mathlib Doc: [#not_mem_empty](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.not_mem_empty)
|
||||
"
|
||||
|
||||
LemmaDoc empty_subset as "empty_subset" in "Set"
|
||||
"
|
||||
`Set.empty_subset {α : Type u} (s : Set α) : ∅ ⊆ s`
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Ja
|
||||
* Namespace: `Set`
|
||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
||||
* Mathlib Doc: [#empty_subset](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.empty_subset)
|
||||
"
|
||||
|
||||
LemmaDoc Subset.antisymm as "Subset.antisymm" in "Set"
|
||||
"
|
||||
`Set.Subset.antisymm {α : Type u} {a : Set α} {b : Set α} (h₁ : a ⊆ b) (h₂ : b ⊆ a) : a = b`
|
||||
|
||||
Zwei Mengen sind identisch, wenn sowohl $A \\subseteq B$ wie auch $B \\subseteq A$.
|
||||
## Details
|
||||
|
||||
`apply Subset.antisymm` ist eine Möglichkeit Gleichungen von Mengen zu zeigen.
|
||||
eine andere ist `ext i`, welches Elementweise funktiniert.
|
||||
Siehe auch
|
||||
[`#Subset.antisymm_iff`](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm_iff)
|
||||
für die Iff-Version.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Set.Subset`
|
||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
||||
* Mathlib Doc: [#Subset.antisymm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm)
|
||||
"
|
||||
|
||||
LemmaDoc Subset.antisymm_iff as "Subset.antisymm_iff" in "Set"
|
||||
"
|
||||
`Set.Subset.antisymm_iff {α : Type u} {a : Set α} {b : Set α} : a = b ↔ a ⊆ b ∧ b ⊆ a`
|
||||
|
||||
Zwei Mengen sind identisch, wenn sowohl $A \\subseteq B$ wie auch $B \\subseteq A$.
|
||||
|
||||
## Details
|
||||
|
||||
`rw [Subset.antisymm_iff]` ist eine Möglichkeit Gleichungen von Mengen zu zeigen.
|
||||
eine andere ist `ext i`, welches Elementweise funktiniert.
|
||||
Siehe auch
|
||||
[`#Subset.antisymm`](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm)
|
||||
für eine verwandte Version.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Set.Subset`
|
||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
||||
* Mathlib Doc: [#Subset.antisymm_iff](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm_iff)
|
||||
"
|
||||
|
||||
|
||||
LemmaDoc Nat.prime_def_lt'' as "prime_def_lt''" in "Nat"
|
||||
"
|
||||
`Nat.prime_def_lt'' {p : ℕ} :
|
||||
Nat.Prime p ↔ 2 ≤ p ∧ ∀ (m : ℕ), m ∣ p → m = 1 ∨ m = p`
|
||||
|
||||
Die bekannte Definition einer Primmzahl in `ℕ`: Eine Zahl (`p ≥ 2`) mit genau zwei Teilern.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Nat`
|
||||
* Mathlib Doc: [#Nat.prime_def_lt''](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Prime.html#Nat.prime_def_lt'')
|
||||
"
|
||||
|
||||
|
||||
LemmaDoc Finset.sum_add_distrib as "sum_add_distrib" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Finset`
|
||||
* Mathlib Doc: [#Finset.sum_add_distrib](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Basic.html#Finset.sum_add_distrib)
|
||||
"
|
||||
|
||||
LemmaDoc Fin.sum_univ_castSucc as "sum_univ_castSucc" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Fin`
|
||||
* Mathlib Doc: [#sum_univ_castSucc](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Fin.html#Fin.sum_univ_castSucc)
|
||||
"
|
||||
|
||||
LemmaDoc Nat.succ_eq_add_one as "succ_eq_add_one" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* `simp`-Lemma: Nein
|
||||
* Namespace: `Nat`
|
||||
* Mathlib Doc: [#succ_eq_add_one](https://leanprover-community.github.io/mathlib4_docs/Init/Data/Nat/Basic.html#Nat.succ_eq_add_one)
|
||||
"
|
||||
|
||||
LemmaDoc Nat.zero_eq as "zero_eq" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#zero_eq](https://leanprover-community.github.io/mathlib4_docs/Init/Data/Nat/Basic.html#Nat.zero_eq)
|
||||
"
|
||||
|
||||
LemmaDoc add_comm as "add_comm" in "Nat"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#add_comm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Group/Defs.html#add_comm)
|
||||
"
|
||||
|
||||
LemmaDoc mul_add as "mul_add" in "Nat"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#mul_add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Ring/Defs.html#mul_add)
|
||||
"
|
||||
|
||||
LemmaDoc add_mul as "add_mul" in "Nat"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#add_mul](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Ring/Defs.html#add_mul)
|
||||
"
|
||||
|
||||
LemmaDoc arithmetic_sum as "arithmetic_sum" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Not a mathlib lemma.
|
||||
"
|
||||
|
||||
LemmaDoc add_pow_two as "add_pow_two" in "Nat"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#add_pow_two](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/GroupPower/Ring.html#add_pow_two)
|
||||
"
|
||||
|
||||
LemmaDoc Finset.sum_comm as "Finset.sum_comm" in "Sum"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#sum_comm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Basic.html#Finset.sum_comm)
|
||||
"
|
||||
|
||||
LemmaDoc Function.comp_apply as "Function.comp_apply" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#comp_apply](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Function.comp_apply)
|
||||
"
|
||||
|
||||
LemmaDoc not_le as "not_le" in "Logic"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#not_le](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Algebra/Order.html#not_le)
|
||||
"
|
||||
|
||||
LemmaDoc if_pos as "if_pos" in "Logic"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#if_pos](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#if_pos)
|
||||
"
|
||||
|
||||
LemmaDoc if_neg as "if_neg" in "Logic"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#if_neg](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#if_neg)
|
||||
"
|
||||
|
||||
LemmaDoc StrictMono.injective as "StrictMono.injective" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#StrictMono.injective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Order/Monotone/Basic.html#StrictMono.injective)
|
||||
"
|
||||
|
||||
LemmaDoc StrictMono.add as "StrictMono.add" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#StrictMono.add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Order/Monoid/Lemmas.html#StrictMono.add)
|
||||
"
|
||||
|
||||
LemmaDoc Odd.strictMono_pow as "Odd.strictMono_pow" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Odd.strictMono_pow](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Odd.strictMono_pow)
|
||||
"
|
||||
|
||||
LemmaDoc Exists.choose as "Exists.choose" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Exists.choose](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Exists.choose)
|
||||
"
|
||||
|
||||
LemmaDoc Exists.choose_spec as "Exists.choose_spec" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Exists.choose_spec](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Exists.choose_spec)
|
||||
"
|
||||
LemmaDoc congrArg as "congrArg" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#congrArg](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#congrArg)
|
||||
"
|
||||
LemmaDoc congrFun as "congrFun" in "Function"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#congrFun](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#congrFun)
|
||||
"
|
||||
|
||||
LemmaDoc Iff.symm as "Iff.symm" in "Logic"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Iff.symm](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Iff.symm)
|
||||
"
|
||||
|
||||
|
||||
|
||||
/-! ## Definitions -/
|
||||
|
||||
DefinitionDoc Even as "Even"
|
||||
"
|
||||
`even n` ist definiert als `∃ r, a = 2 * r`.
|
||||
Die Definition kann man mit `unfold even at *` einsetzen.
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Even](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Even)"
|
||||
|
||||
DefinitionDoc Odd as "Odd"
|
||||
"
|
||||
`odd n` ist definiert als `∃ r, a = 2 * r + 1`.
|
||||
Die Definition kann man mit `unfold odd at *` einsetzen.
|
||||
|
||||
* Mathlib Doc: [Odd](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Odd)"
|
||||
|
||||
DefinitionDoc Injective as "Injective"
|
||||
"
|
||||
`Injective f` ist definiert als
|
||||
|
||||
```
|
||||
∀ a b, f a = f b → a = b
|
||||
```
|
||||
definiert.
|
||||
|
||||
* Mathlib Doc: [Injective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Injective)"
|
||||
|
||||
DefinitionDoc Surjective as "Surjective"
|
||||
"
|
||||
`Surjective f` ist definiert als
|
||||
|
||||
```
|
||||
∀ a, (∃ b, f a = b)
|
||||
```
|
||||
|
||||
* Mathlib Doc: [Surjective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Surjective)"
|
||||
|
||||
DefinitionDoc Bijective as "Bijective"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#Bijective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Bijective)
|
||||
"
|
||||
|
||||
DefinitionDoc LeftInverse as "LeftInverse"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#LeftInverse](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.LeftInverse)
|
||||
"
|
||||
|
||||
DefinitionDoc RightInverse as "RightInverse"
|
||||
"
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#RightInverse](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Logic.html#RightInverse)
|
||||
"
|
||||
|
||||
DefinitionDoc StrictMono as "StrictMono"
|
||||
"
|
||||
`StrictMono f` ist definiert als
|
||||
|
||||
```
|
||||
∀ a b, a < b → f a < f b
|
||||
```
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
* Mathlib Doc: [#StrictMono](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Order/Monotone/Basic.html#StrictMono)
|
||||
|
||||
"
|
||||
|
||||
DefinitionDoc Symbol.Subset as "⊆" "
|
||||
|
||||
Auf Mengen (`Set`) ist `A ⊆ B` als `∀x, x ∈ A → x ∈ B` implementiert.
|
||||
"
|
||||
@@ -0,0 +1,16 @@
|
||||
import Adam.Levels.Contradiction.L01_Have
|
||||
import Adam.Levels.Contradiction.L02_Suffices
|
||||
import Adam.Levels.Contradiction.L03_ByContra
|
||||
import Adam.Levels.Contradiction.L04_ByContra
|
||||
import Adam.Levels.Contradiction.L05_Contrapose
|
||||
import Adam.Levels.Contradiction.L06_Summary
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Title "Widerspruch"
|
||||
|
||||
Introduction "
|
||||
Ihr begebt euch auf die Suche nach *Oddeus*. Nach etwas rumfragen, kommt ihr tatsächlich an
|
||||
eine Dornenfestung und nachdem ihr erklärt habt, wer ihr seit, werdet ihr auf eine Audienz
|
||||
gebeten.
|
||||
"
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 1
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 2
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
@@ -6,9 +6,9 @@ import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
import Mathlib
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 3
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
@@ -6,9 +6,9 @@ import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
import Mathlib
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 4
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 5
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import TestGame.ToBePorted
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 6
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import Adam.Levels.Function.L01_Function
|
||||
import Adam.Levels.Function.L02_Let
|
||||
import Adam.Levels.Function.L03_Piecewise
|
||||
import Adam.Levels.Function.L04_Injective
|
||||
import Adam.Levels.Function.L05_Injective
|
||||
import Adam.Levels.Function.L06_Injective
|
||||
import Adam.Levels.Function.L07_Surjective
|
||||
import Adam.Levels.Function.L08_Bijective
|
||||
import Adam.Levels.Function.L09_Inverse
|
||||
import Adam.Levels.Function.L11_Inverse
|
||||
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Title "Abbildungen"
|
||||
|
||||
Introduction "
|
||||
Auf der Suche nach dem Buch der Urbilder landet ihr auf einem kleinen Mond, der bis auf
|
||||
eine Insel komplett mit Wasser bedeckt zu sein scheint.
|
||||
|
||||
Auf der Insel seht ihr verschiedene große und kleine Behausungen, manche aus Stroh und Holz,
|
||||
vereinzelte aus Lehm.
|
||||
|
||||
Planlos geht ihr zum ersten Haus bei dem jemand vorne außen sitzt.
|
||||
"
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 1
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 2
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 3
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 4
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 5
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 6
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 7
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 8
|
||||
|
||||
@@ -33,6 +33,6 @@ Hint : Bijective (fun (n : ℤ) ↦ n + 1) =>
|
||||
|
||||
Conclusion
|
||||
"Zufrieden drückt euch der Gelehrte eine neue Fackel in die Hand und
|
||||
zeigt euch den Weg nach draussen."
|
||||
zeigt euch den Weg nach draußen."
|
||||
|
||||
NewDefinition Bijective
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 9
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 10
|
||||
|
||||
+15
-15
@@ -1,18 +1,18 @@
|
||||
import TestGame.Levels.Implication.L01_Intro
|
||||
import TestGame.Levels.Implication.L02_Revert
|
||||
import TestGame.Levels.Implication.L03_Apply
|
||||
import TestGame.Levels.Implication.L04_Apply
|
||||
import TestGame.Levels.Implication.L05_Apply
|
||||
import TestGame.Levels.Implication.L06_Iff
|
||||
import TestGame.Levels.Implication.L07_Rw
|
||||
import TestGame.Levels.Implication.L08_Iff
|
||||
import TestGame.Levels.Implication.L09_Iff
|
||||
import TestGame.Levels.Implication.L10_Apply
|
||||
import TestGame.Levels.Implication.L11_ByCases
|
||||
import TestGame.Levels.Implication.L12_Rw
|
||||
import TestGame.Levels.Implication.L13_Summary
|
||||
import Adam.Levels.Implication.L01_Intro
|
||||
import Adam.Levels.Implication.L02_Revert
|
||||
import Adam.Levels.Implication.L03_Apply
|
||||
import Adam.Levels.Implication.L04_Apply
|
||||
import Adam.Levels.Implication.L05_Apply
|
||||
import Adam.Levels.Implication.L06_Iff
|
||||
import Adam.Levels.Implication.L07_Rw
|
||||
import Adam.Levels.Implication.L08_Iff
|
||||
import Adam.Levels.Implication.L09_Iff
|
||||
import Adam.Levels.Implication.L10_Apply
|
||||
import Adam.Levels.Implication.L11_ByCases
|
||||
import Adam.Levels.Implication.L12_Rw
|
||||
import Adam.Levels.Implication.L13_Summary
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Title "Aussagenlogik 2"
|
||||
|
||||
@@ -28,7 +28,7 @@ aber niemand von den Einwohnern wusste was davon...
|
||||
erzählen…
|
||||
|
||||
Und damit leitet Robo den Landeanflug ein. Implis scheint ein riesiger Tagbau zu sein auf
|
||||
dem nach allem möglichen gegraben wird. Überall seht ihr Förderbänder kreuz und queer.
|
||||
dem nach allem möglichen gegraben wird. Überall seht ihr Förderbänder kreuz und quer.
|
||||
|
||||
Das Operationsteam begrüsst euch freundlich und lädt zum Essen im Kommandoturm.
|
||||
"
|
||||
+4
-3
@@ -1,9 +1,9 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Tauto
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 1
|
||||
|
||||
@@ -18,7 +18,8 @@ Statement (A B : Prop) (hb : B) : A → (A ∧ B) := by
|
||||
Hint "**Du**: Einen Moment, das ist eine Implikation (`\\to`),
|
||||
also `A` impliziert `A und B`, soweit so gut, also eine Tautologie.
|
||||
|
||||
**Robo**: Die scheinen hier `tauto` auch nicht zu verstehen.
|
||||
**Robo**: Du hast recht, eigentlich könnte man `tauto` sagen,
|
||||
aber das scheinen die hier tauto nicht zu verstehen.
|
||||
Implikationen kannst du aber mit `intro h` angehen."
|
||||
intro hA
|
||||
Hint "**Du**: Jetzt habe ich also angenommen, dass `A` wahr ist und muss `A ∧ B` zeigen,
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 2
|
||||
|
||||
+3
-10
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 3
|
||||
|
||||
@@ -11,17 +11,10 @@ Introduction
|
||||
"
|
||||
Sein Kollege zieht eine Linie unter deinen Beweis, schreibt ein durchgestrichenes ~`revert`~
|
||||
hin und gibt dir das Blatt wieder.
|
||||
`revert` ist aber nur selten der richtige Weg.
|
||||
|
||||
Im vorigen Beispiel würde man besser die Implikation $A \\Rightarrow B$ *anwenden*, also
|
||||
sagen \"Es genügt $A$ zu zeigen, denn $A \\Rightarrow B$\" und danach $A$ beweisen.
|
||||
|
||||
Wenn man eine Implikation `(g : A → B)` in den Annahmen hat, bei welcher die Konsequenz
|
||||
(also $B$) mit dem Goal übereinstimmt, kann man `apply g` genau dies machen.
|
||||
"
|
||||
|
||||
Statement (A B : Prop) (hA : A) (h : A → B) : B := by
|
||||
Hint "**Robo**: Du hast natürlich recht, normalerweise ist es viel schöner mit
|
||||
Hint "**Robo**: Da hat er natürlich recht, normalerweise ist es viel schöner mit
|
||||
`apply {h}` die Implikation anzuwenden."
|
||||
apply h
|
||||
Hint "**Du**: Und jetzt genügt es also `A` zu zeigen."
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 4
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 5
|
||||
|
||||
@@ -8,7 +8,7 @@ Title "Implikation"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Selbstsicher folgt ihr den Anweisungen und geht nach draussen zum
|
||||
Selbstsicher folgt ihr den Anweisungen und geht nach draußen zum
|
||||
defekten Kontrollelement. Dieses zeigt ein kompliziertes Diagram:
|
||||
$$
|
||||
\\begin{CD}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 6
|
||||
|
||||
@@ -37,7 +37,7 @@ hier bei `(h : A ↔ B)` heissen sie `h.mp` und `h.mpr`.
|
||||
**Operationsleiter**: \"Modulo Ponens\" ist ein lokaler Begriff hier,
|
||||
aber das ist doch nicht wichtig.
|
||||
|
||||
**Robo**: Und das \"r\" in `mpr` stünde für \"reverse\" weils die Rückrichtung ist.
|
||||
**Robo**: Und das \"r\" in `mpr` stünde für \"reverse\" weil's die Rückrichtung ist.
|
||||
"
|
||||
|
||||
NewTactic constructor
|
||||
+4
-2
@@ -1,9 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Init.Data.ToString
|
||||
-- #check List UInt8
|
||||
|
||||
Game "TestGame"
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 7
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 8
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 9
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 10
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 11
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib.Logic.Basic
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 12
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 13
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import Adam.Levels.Induction.L01_Induction
|
||||
|
||||
Game "Adam"
|
||||
World "Induction"
|
||||
Title "Übungen Induktions"
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Induction"
|
||||
Level 1
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import Adam.Levels.Inequality.L01_LE
|
||||
import Adam.Levels.Inequality.L02_Pos
|
||||
import Adam.Levels.Inequality.L03_Linarith
|
||||
import Adam.Levels.Inequality.L04_Linarith
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Title "Ungleichung"
|
||||
|
||||
Introduction "
|
||||
Später erinnerst du dich gar nicht mehr wo und wann du diese Unterhaltung hattest, geschweige
|
||||
denn mit wem. Vielleicht war es ein Traum, oder eine Erscheinung. Vielleicht war es
|
||||
auch nur eines Abends über einer Runde Getränke.
|
||||
|
||||
Aber auf jedenfall hast du irgendwo gelernt, was du nun weisst.
|
||||
"
|
||||
@@ -0,0 +1,34 @@
|
||||
import Adam.Metadata
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 1
|
||||
|
||||
Title "Kleinergleich"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*(Gesrpäch)*
|
||||
|
||||
**Robo** (*lallend*, oder war's fröhlich proklamierend?):
|
||||
…und deshalb sind `≥` und `>` eigentlich nur Notationen für `≤`,
|
||||
welches man übrigens `\\le` schreibt, was für Less-Equal (also Kleinergleich) steht…
|
||||
|
||||
**Du**: Wir haben's verstanden, man benützt also Standartmässig lieber `≤` und `<`,
|
||||
aber damit weiß ich eh nichts anzufangen.
|
||||
|
||||
**dritte Person**: Komm schon, das kannst du ja sicher:
|
||||
"
|
||||
|
||||
Statement
|
||||
(n m : ℕ) : m < n ↔ m.succ ≤ n := by
|
||||
Hint "**Robo**: Du Narr! Das ist doch eine Kuriosität, dass `m < n` auf `ℕ` per Definition
|
||||
als `m + 1 ≤ n` definiert ist!
|
||||
|
||||
**dritte Person**: Du verdirbst den Witz! Ich wollte ihn doch nur testen."
|
||||
rfl
|
||||
|
||||
OnlyTactic rfl
|
||||
|
||||
Conclusion "**Du**: Ha. ha… Na aber jetzt mal ehrlich, könnt ihr mir ein bisschen mehr
|
||||
erzählen?"
|
||||
@@ -0,0 +1,53 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 2
|
||||
|
||||
Title "Kleinergleich"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*weitere Person*: …ich sag dir, eine positive Zahl kann man sowohl mit `0 < n`
|
||||
als auch `n ≠ 0` darstellen.
|
||||
|
||||
*Robo*: Und da gibts leider keinen Standard dazu.
|
||||
|
||||
**weitere Person*: Ja und, da kann man ja einfach mit `Nat.pos_iff_ne_zero`
|
||||
wechseln. Wart mal, wieso galt das nochmals…
|
||||
"
|
||||
|
||||
Statement Nat.pos_iff_ne_zero (n : ℕ) : 0 < n ↔ n ≠ 0 := by
|
||||
Hint "**Robo** (*flüsternd*): Wenn du ein bisschen schwere Maschinerie auffahren willst,
|
||||
um in zu beeindrucken, hab ich was. Mach doch eine Fallunterscheidung ob `n` Null ist
|
||||
oder nicht!
|
||||
|
||||
**Du** (*flüsternd*): Und wie geht das?
|
||||
|
||||
**Robo** (*laut und selbstsicher*): Wir fangen mit `rcases n` an!"
|
||||
rcases n
|
||||
Hint "**Du**: Hmm, das muss man doch vereinfachen können.
|
||||
|
||||
**Robo** (*flüsternd*): Zweiter pompöser Auftritt: sag einfach `simp` und lass das alles
|
||||
automatisch geschehen."
|
||||
simp
|
||||
Hint "**Du**: Und hier fang ich wohl am besten an wie ich das schon kenne."
|
||||
constructor
|
||||
intro
|
||||
simp
|
||||
intro
|
||||
Hint "**Robo**: Warte! Den Rest geb ich dir als Lemma: `Nat.suc_pos`."
|
||||
apply Nat.succ_pos
|
||||
|
||||
NewTactic simp
|
||||
NewLemma Nat.succ_pos
|
||||
DisabledLemma Nat.pos_iff_ne_zero
|
||||
|
||||
Conclusion "**Du**: Oh `simp` ist ja echt nicht schlecht…
|
||||
|
||||
Die andere Person scheint beeindruckt, hat aber gleichzeitig auch das Bedürfnis, Dich aus
|
||||
der Reserve zu locken."
|
||||
@@ -0,0 +1,26 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Linarith
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 3
|
||||
|
||||
Title "Linarith"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**dritte Person**: Nah wenn wir so spielen:
|
||||
"
|
||||
|
||||
Statement (n : ℕ) (h : 2 ≤ n) : n ≠ 0 := by
|
||||
Hint "**Du**: `simp` geht hier nicht, was mir ja auch einläuchtet.
|
||||
|
||||
**Robo**: Ist auch keine Vereinfachung, die du machen willst. Stattdessen,
|
||||
`linarith` kann lineare Gleichungen und Ungleichungen lösen. Das ist das Powertool
|
||||
in der hinsicht."
|
||||
linarith
|
||||
|
||||
NewTactic linarith
|
||||
NewLemma Nat.pos_iff_ne_zero
|
||||
|
||||
Conclusion "**Du**: Naja so beeindruckend war das jetzt auch noch nicht."
|
||||
@@ -0,0 +1,29 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Linarith
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 4
|
||||
|
||||
Title "Linarith"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Robo**: Die Taktik kann aber noch viel mehr.
|
||||
|
||||
**weitere Person**: Hier, probier mal!
|
||||
|
||||
$$
|
||||
\\begin{aligned}
|
||||
5 * y &\\le 35 - 2 * x \\\\
|
||||
2 * y &\\le x + 3
|
||||
\\end{aligned}
|
||||
$$
|
||||
"
|
||||
|
||||
Statement (x y : ℤ) (h₂ : 5 * y ≤ 35 - 2 * x) (h₃ : 2 * y ≤ x + 3) : y ≤ 5 := by
|
||||
linarith
|
||||
|
||||
Conclusion "**Du**: Boah, das ist schon gar nicht schlecht.
|
||||
|
||||
Und damit endet auch Deine Erinnerung und wer weiss was du anschließend gemacht hast…"
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 1
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import Adam.Levels.Lean.L01_Type
|
||||
import Adam.Levels.Lean.L02_Universe
|
||||
import Adam.Levels.Lean.L03_ImplicitArguments
|
||||
import Adam.Levels.Lean.L04_InstanceArguments
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Title "Lean"
|
||||
|
||||
Introduction
|
||||
"Während ihr weiter durch Täler, über Geröllhalden und zwischen monumentalen Steintürmen
|
||||
umherzieht, fragst Du eines Tages Robo.
|
||||
|
||||
**Du**: Sag mal, hast du dir je Gedanken dazu gemacht, wie du eigentlich funktionierts?
|
||||
|
||||
**Robo**: Was meinst du, wie ich funktioniere? Ich bin halt… ich…
|
||||
|
||||
**Du**: Ja schon, aber was woher weisst du denn alles was du weisst?
|
||||
|
||||
**Robo**: Das kann ich dir sagen. Früher habe ich viele Datenträger verschlungen,
|
||||
und dadurch gelernt.
|
||||
|
||||
**Du**: Ob so eine Diskette wohl lecker schmeckt? Egal, ich hab ein paar Fragen zu deinem
|
||||
Lean-Modul.
|
||||
|
||||
**Robo**: Na dann nur zu!"
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Level 1
|
||||
|
||||
Title "Typen"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du**: Also, wieso schreib ich denn sowohl `(n : ℕ)` für eine natürliche Zahl wie
|
||||
auch `(h : A ∧ ¬ B)` für eine Aussage?
|
||||
|
||||
**Robo**: Alles in Lean sind Objekte von einem *Typen*, man nennt das auch
|
||||
\"dependent type theory\". Rechts vom `:` steht immer der Typ der dieses Objekt hat.
|
||||
|
||||
**Du**: Verstehe, dann war `ℕ` der Typ der natürlichen Zahlen, `Prop` der Typ
|
||||
aller logischen Aussagen, und so weiter. Un wenn `R` einfach irgendein Typ ist, dann…
|
||||
|
||||
**Robot: …würdest du das als `(R : Type)` schreiben.
|
||||
|
||||
**Du**: Also sind Typen ein bisschen jene Grundlage, die in meinem Studium die
|
||||
Mengen eingenommen haben?
|
||||
|
||||
**Robo**: Genau. Ein Ring ist dann zum Beispiel als `(R : Type) [Ring R]` definiert,
|
||||
also als Typen, auf dem eine Ringstruktur besteht.
|
||||
|
||||
**Robo**: Hier ein Beispiel. Die Taktik `ring` funktioniert in jedem Typen, der
|
||||
genügend Struktur definiert hat, zum Beispiel in einem kommutativen Ring:
|
||||
"
|
||||
|
||||
Statement (R : Type) [CommRing R] (a b : R) : a + b = b + a := by
|
||||
ring
|
||||
|
||||
Conclusion "**Robo**: `[CommRing R]` nennt man übrigens eine Instanz und die
|
||||
eckigen Klammern sagen Lean, dass es automatisch suchen soll, ob es so eine Instanz
|
||||
findet, wenn man ein Lemma anwenden will."
|
||||
@@ -0,0 +1,44 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Level 2
|
||||
|
||||
Title "Universen"
|
||||
|
||||
Introduction
|
||||
"**Du**: Aber wenn alles Typen sind, welcher Typ hat dann `Type`?
|
||||
|
||||
**Robo**: `Type 1` und dieser hat Typ `Type 2`, etc.
|
||||
|
||||
**Robo**: Die Zahl nennt man *Universum*. Manchmal führt man Universen explizit
|
||||
mit `universum u` ein, öfter siehst du `(R : Type _)`, was einfach ein Platzhalter
|
||||
für irgend ein Universum ist.
|
||||
|
||||
**Du**: Das klingt ein bisschen nach Mengentheoretische Probleme, die man normalerweise
|
||||
ignoriert.
|
||||
|
||||
**Robo**: Genau! Deshalb schreibt man eigentlich immer einfach `Type _` und ist glücklich.
|
||||
Spezifischer muss man erst werden wenn man sowas wie Kategorientheorie anschaut, wo
|
||||
man die Universen tatsächlich kontrollieren muss.
|
||||
|
||||
**Du**: Oke, hier rein, da raus. Aber hast du mir noch eine Aufgabe?
|
||||
"
|
||||
|
||||
universe u
|
||||
|
||||
Statement
|
||||
(R : Type u) [CommRing R] (a b : R) : a + b = b + a := by
|
||||
Hint "**Robo**: Naja, Aufgaben zu Universen sind nicht so natürlich,
|
||||
aber vorige Aufgabe würde man eigentlich besser so schreiben, da
|
||||
kannst du mindestens das Uniersum beobachten."
|
||||
ring
|
||||
|
||||
Conclusion "**Du**: Na dann. Aber gut dass ich's mal gesehen hab."
|
||||
|
||||
-- Hint (R : Type) (h : CommRing R) (a : R) (b : R) : a + b = b + a =>
|
||||
-- ""
|
||||
@@ -0,0 +1,71 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
import Adam.ToBePorted
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Level 3
|
||||
|
||||
Title "Implizite Argumente"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du**: Was mich aber mehr beschäftigt, ist, dass Lemmas manchmal viel mehr Argumente
|
||||
haben als ich hinschreiben muss.
|
||||
|
||||
**Robo**: Lean kann manche Argumente aus dem Kontext erschliessen. Hast du zum Beispiel
|
||||
ein Lemma von vorhin
|
||||
|
||||
```
|
||||
lemma Fin.sum_univ_castSucc {β : Type _} [AddCommMonoid β] {n : ℕ} (f : Fin (n + 1) → β) :
|
||||
∑ i : Fin (n + 1), f i = ∑ i : Fin n, f (↑Fin.castSucc.toEmbedding i) + f (Fin.last n) := by
|
||||
sorry
|
||||
```
|
||||
|
||||
dann reicht es ja Lean `f` zu geben und daraus kann es herausfinden, was die anderen
|
||||
(`β`, `n`) sein müssen.
|
||||
|
||||
**Robo**: Solche *implizite Argumente* markiert man dann mit `{_ : _}` während
|
||||
*explizite Arumente* mit `(_ : _)` markiert werden.
|
||||
|
||||
**Du**: Dann könnte ich also einfach `Fin.sum_univ_castSucc f` schreiben?
|
||||
|
||||
**Robo**: Genau!
|
||||
|
||||
**Du**: Und was war dann das `(n := m + 1)` vorhin genau?
|
||||
|
||||
**Robo**: Damit kann man im Aussnahmefall die impliziten Argumente doch angeben. Hier haben wir
|
||||
gesagt, es soll für das Argument `n` den Term `m + 1` einsetzen. Hier mach das doch noch einmal
|
||||
unter weniger Stress:
|
||||
"
|
||||
|
||||
open BigOperators
|
||||
|
||||
Statement (m : ℕ) : ∑ i : Fin (m + 1), (i : ℕ) + (m + 1) = ∑ i : Fin (Nat.succ m + 1), ↑i := by
|
||||
Branch
|
||||
rw [Fin.sum_univ_castSucc]
|
||||
Hint "**Robo**: Siehst du, ohne die Hilfe macht es das Falsche. Deshalb muss man hier
|
||||
explizit mit `Fin.sum_univ_castSucc (n := m + 1)` nachhelfen."
|
||||
rw [Fin.sum_univ_castSucc]
|
||||
Hint "**Robo**: Na klar, in dem Beispiel kannst du einfach weiter umschreiben bis es
|
||||
nicht mehr geht, aber das war nicht der Punkt…"
|
||||
rw [Fin.sum_univ_castSucc]
|
||||
Hint "**Robo**: Na klar, in dem Beispiel kannst du einfach weiter umschreiben bis es
|
||||
nicht mehr geht, aber das war nicht der Punkt…"
|
||||
rfl
|
||||
rw [Fin.sum_univ_castSucc (n := m + 1)]
|
||||
rfl
|
||||
|
||||
OnlyTactic rw rfl
|
||||
|
||||
Conclusion "**Du**: Gibt es auch noch ander Methoden implizite Argumente anzugeben.
|
||||
|
||||
**Robo** `@Fin.sum_univ_castSucc` würde *alle* Argumente explizit machen,
|
||||
aber das ist unparktischer, weil man dann irgendwie
|
||||
`@Fin.sum_univ_castSucc _ _ (m + 1)` schreiben müsste.
|
||||
|
||||
**Du**: Ah und ich sehe der `_` ist überall in Lean ein Platzhalter, der automatisch
|
||||
gefüllt wird."
|
||||
@@ -0,0 +1,57 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
import Adam.ToBePorted
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Level 4
|
||||
|
||||
Title "Instanz-Argumente"
|
||||
|
||||
Introduction
|
||||
"**Du**: Also nochmals als Zusammenfassung, dann gibt es 3 Arten von Argumenten,
|
||||
explizite mit `()`, implizite mit `{}` und Instanzen mit `[]`?
|
||||
|
||||
**Robo**: Korrekt. Instanzen sind damit auch Implizite Argumente. Der Unterschied
|
||||
zwischen `{}` und `[]` ist also *wie* Lean diese füllt.
|
||||
|
||||
**Du**: Verstehe, bei den ersten sucht es logisch nach einer richtigen Möglichkeit,
|
||||
beim zweiten geht's durch alle Instanzen, die es kennt.
|
||||
|
||||
|
||||
**Robo**: Funktioniert hier bei mir nicht, aber wenn du ausserhalb eines Beweises
|
||||
`#synth Ring ℤ` in ein Dokument schreibt, zeigt dir Lean, ob es eine Instanz finden kann.
|
||||
|
||||
**Du**: Ich glaube das macht alles Sinn.
|
||||
|
||||
**Robo**: Hier, mach nochmals das Gleiche wie vorhin aber mit @-Syntax um das zu
|
||||
verinnerlichen:
|
||||
"
|
||||
|
||||
open BigOperators
|
||||
|
||||
Statement (m : ℕ) :
|
||||
∑ i : Fin (m + 1), (i : ℕ) + (m + 1) = ∑ i : Fin (Nat.succ m + 1), ↑i := by
|
||||
Hint "*Robo*: Schreibe `rw [@Fin.sum_univ_castSucc _ _ (m + 1)]`
|
||||
anstatt `rw [Fin.sum_univ_castSucc (n := m + 1)]`!"
|
||||
rw [@Fin.sum_univ_castSucc _ _ (m + 1)]
|
||||
rfl
|
||||
|
||||
OnlyTactic rw rfl
|
||||
|
||||
Conclusion "
|
||||
**Du**: Danke Robo!
|
||||
|
||||
Um zwei weitere Ecken und plötzlich steht ihr wieder vor dem Golem, dem ihr schon begegnet seit.
|
||||
Dieser lädt euch zum Abendmahl ein. Ihr erfährt, dass er ganz gerne liest und er zeigt euch
|
||||
sein neustes Buch, das er leider nicht lesen kann. Nich tnur ist es der zweite Band einer Serie
|
||||
(der Erste hat offensichtlich was mit \"Urbildern\" zu tun), sondern ist es auch in einem
|
||||
Dialekt geschrieben, der anscheinend nur auf einem Nachbarsmond gesprochen wird.
|
||||
|
||||
Ihr beschliesst dem herzlichen Golem zu helfen und beiden Monden einen Besuch abzustatten,
|
||||
sowohl um den Dialekt zu lernen, wie auch in der Bibliothek auf dem anderen Mond nach dem
|
||||
ersten Band zu suchen.
|
||||
"
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 9
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Nat2"
|
||||
Level 3
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Nat2"
|
||||
Level 5
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
@@ -21,7 +21,7 @@ lemma even_square (n : ℕ) : even n → even (n ^ 2) := by
|
||||
|
||||
def prime (n : ℕ) : Prop := (2 ≤ n) ∧ ∀ a b, n = a * b → a = 1 ∨ b = 1
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Nat"
|
||||
Level 4
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
-- -- INCORPORATED
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 1
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Levels.LinearAlgebra.L01_Module
|
||||
import Adam.Levels.LinearAlgebra.L02_VectorNotation
|
||||
import Adam.Levels.LinearAlgebra.L03_VectorNotation
|
||||
import Adam.Levels.LinearAlgebra.L04_Submodule
|
||||
import Adam.Levels.LinearAlgebra.L05_Submodule
|
||||
import Adam.Levels.LinearAlgebra.L06_Span
|
||||
import Adam.Levels.LinearAlgebra.L07_Span
|
||||
import Adam.Levels.LinearAlgebra.L08_GeneratingSet
|
||||
|
||||
import Adam.Levels.LinearAlgebra.M01_LinearMap
|
||||
import Adam.Levels.LinearAlgebra.M02_LinearIndep
|
||||
import Adam.Levels.LinearAlgebra.M04_Basis
|
||||
|
||||
import Adam.Levels.LinearAlgebra.N01_Span
|
||||
import Adam.Levels.LinearAlgebra.N02_Span
|
||||
import Adam.Levels.LinearAlgebra.N03_Idempotent
|
||||
import Adam.Levels.LinearAlgebra.N04_Idempotent
|
||||
import Adam.Levels.LinearAlgebra.N05_Sum
|
||||
import Adam.Levels.LinearAlgebra.N06_Sum
|
||||
import Adam.Levels.LinearAlgebra.N07_Prod
|
||||
import Adam.Levels.LinearAlgebra.N08_Prod
|
||||
import Adam.Levels.LinearAlgebra.N09_Prod
|
||||
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Title "Vektorraum"
|
||||
|
||||
Introduction "Hier lernst du die Grundlagen zur linearen Algebra.
|
||||
|
||||
Vektorräume sind in Lean etwas algemeiner definiert als dies normalerweise in
|
||||
einer Einführungsvorlesung antrifft: Man definiert ein \"Modul\" (Plural: Moduln)
|
||||
über einem Ring. Ein Modul über einem *Körper* wird dann auch \"Vektorraum\" genannt.
|
||||
"
|
||||
|
||||
Game "Adam"
|
||||
World "Basis"
|
||||
Title "Lineare Abbildungen"
|
||||
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Title "Mehr Vektorräume"
|
||||
@@ -0,0 +1,106 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Basic -- definiert `module`
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
import Adam.StructInstWithHoles
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 1
|
||||
|
||||
Title "Module"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Konkret heisst das:
|
||||
|
||||
Sei `R` ein Ring. Ein `R`-Modul ist eine kommutative Gruppe `(V, +)` zusammen mit
|
||||
einer Abbildung `• : R × V → V` (Skalarmultiplitation genannt), die folgende
|
||||
Eigenschaften beliebige `(r s : R)` und `(v w : V)`erfüllt:
|
||||
- `r • (v + w) = r • v + r • w`
|
||||
- `(r + s) • v = r • v + s • v`
|
||||
- `(r * s) • v = r • s • v`
|
||||
- `1 • r = r`
|
||||
- `0 • v = 0`
|
||||
- `r • 0 = 0`
|
||||
|
||||
"
|
||||
|
||||
-- Bemerkungen:
|
||||
-- 1) Über einem `[field R]` sind die letzten beiden Eigenschaften überflüssig, diese kann
|
||||
-- man beweisen, wenn man Cancellation (`a₁ + x = a₂ + x → a₁ = a₂`) hat. In einem generellen
|
||||
-- Ring, muss das aber nicht gegeben sein (siehe Nullteiler).
|
||||
-- 2) Die nötigen Annahmen um ein Modul in Lean zu erhalten sind tatsächlich noch etwas lockerer,
|
||||
-- so muss `R` nicht ganz ein Ring sein (nur `[Semiring R]`) und
|
||||
-- `V` muss nicht ganz eine kommutative Gruppe sein (nur `[add_comm_monoid V]`).
|
||||
-- Einen abstrakten Vektorraum definiert man wie folgt:
|
||||
-- `variables {R V : Type*} [field R] [add_comm_monoid V] [module R V]`
|
||||
|
||||
-- Wenn man hingegen konkret zeigen will, dass ein existierendes Objekt ein Vektorraum ist,
|
||||
-- kann man eine einsprechende Instanz wie folgt definieren:
|
||||
|
||||
-- ```
|
||||
-- instance Q_module : Module ℚ ℝ :=
|
||||
-- { smul := λa r, ↑a * r
|
||||
-- smul_zero := _
|
||||
-- zero_smul := _
|
||||
-- one_smul := _
|
||||
-- smul_add := _
|
||||
-- add_smul := _
|
||||
-- mul_smul := _ }
|
||||
-- ```
|
||||
-- Man muss also angeben, welche Skalarmultiplikation man gerne hätte
|
||||
-- (`smul`. In unserem Fall sagen wir einfach, diese soll Multiplikation in `ℝ` sein.)
|
||||
-- und dazu jegliche Beweise, dass die Skalarmultiplikation sich mit der Ringstruktur verträgt.
|
||||
-- Im nachfolgenden beweisen wir die Eigenschaften einzeln.
|
||||
|
||||
Statement
|
||||
"Zeige, dass $\\mathbb{R}$ ein $\\mathbb{Q}$-Modul ist."
|
||||
: Module ℚ ℝ := by
|
||||
Hint "**Robo**: Als erstes willst du die Stuktur `Modul` aufteilen in einzelne Beweise.
|
||||
Der Syntax dafür ist:
|
||||
|
||||
```
|
||||
refine \{ ?..! }
|
||||
```
|
||||
"
|
||||
refine { ?..! }
|
||||
· Hint "**Robo**: Hier musst du die Skalarmultiplikation angeben.
|
||||
Benutze dafür `exact fun (a : ℚ) (r : ℝ) => ↑a * r`."
|
||||
exact fun (a : ℚ) (r : ℝ) => ↑a * r
|
||||
· Hint "**Robo**: Jetzt musst du alle eigenschaften eines $\\mathbb\{Q}$-Moduls zeigen,
|
||||
das sind also 6 einzelne Goals."
|
||||
intro b
|
||||
Hint "**Robo**: Mit `change (1 : ℚ) * {b} = {b}` kannst du das Goal umschreiben, damit
|
||||
dann andere Taktiken besser damit arbeiten können."
|
||||
change (1 : ℚ) * b = b
|
||||
Hint "**Robo**: Den Teil kannst du mit `simp` beweisen."
|
||||
simp
|
||||
· intro x y b
|
||||
Hint "**Robo**: Benutze `change` um `•` durch `*` zu ersetzen."
|
||||
Hint (hidden := true) "**Robo**: Explizit `change ({x} * {y} : ℚ) * {b} = {x} * ({y} * {b})`"
|
||||
change (x * y : ℚ) * b = x * (y * b)
|
||||
Hint "**Robo**: Mit `simp` und `ring` kannst du den Rest beweisen."
|
||||
simp
|
||||
ring
|
||||
· intro a
|
||||
simp
|
||||
· intro a x y
|
||||
Hint (hidden := true) "**Robo**: Explizit `change {a} * ({x} + {y}) = {a} * {x} + {a} * {y}`"
|
||||
change a * (x + y) = a * x + a * y
|
||||
ring
|
||||
· intro r s x
|
||||
Hint (hidden := true) "**Robo**: Explizit
|
||||
`change ({r} + {s} : ℚ) * {x} = {r} * {x} + {s} * {x}`"
|
||||
change (r + s : ℚ) * x = r * x + s * x
|
||||
simp
|
||||
ring
|
||||
· intro a
|
||||
Hint (hidden := true) "**Robo**: Explizit `change (0 : ℚ) * {a} = 0`"
|
||||
change (0 : ℚ) * a = 0
|
||||
simp
|
||||
|
||||
NewTactic refine exact change
|
||||
+8
-24
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Pi -- definiert `Module ℚ (fin 2 → ℚ)`
|
||||
@@ -7,7 +7,7 @@ import Mathlib.Tactic.FinCases
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 2
|
||||
|
||||
@@ -15,30 +15,14 @@ Title "Konkrete Vektorräume"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Häufig in der linearen Algebra hat man ganz einfach Vektoren über `ℚ` oder `ℝ`
|
||||
und möchte diese explizit definieren.
|
||||
|
||||
Reele Vektorräume definiert man in Lean am besten als Funktion von einem Indexset.
|
||||
|
||||
So ist `Fin 2` eine Menge, die nur `0` und `1` enthält
|
||||
und `ℚ²` wird als `Fin 2 → ℚ` definiert. Hier machen wir uns eine
|
||||
lokale notation dafür:
|
||||
Den $\\mathbb{Q}$-Vektorraum $\\mathbb{Q}^3$ definiert man am besten mit
|
||||
der lokalen Notation
|
||||
|
||||
```
|
||||
notation `ℚ²` := Fin 2 → ℚ
|
||||
local notation `ℚ³` := Fin 3 → ℚ
|
||||
```
|
||||
|
||||
Das mag auf den ersten Blick etwas unintuitiv erscheinen, hat aber den Vorteil,
|
||||
dass man die ganze
|
||||
Infrastruktur für Funktionen einfach direkt für Vektoren und
|
||||
Matrizen mitgebrauchen kann.
|
||||
|
||||
Wir können uns auch noch ein paar andere standardmässige `ℚ`-Vektorräume definieren.
|
||||
|
||||
```
|
||||
notation \"ℚ³\" => Fin 3 → ℚ
|
||||
notation \"ℚ^(\" n \")\" => (Fin n) → ℚ
|
||||
```
|
||||
Dabei ist `Fin 3` die Indexmenge $\\{0, 1, 2\\}$.
|
||||
|
||||
Die schreibweise für einen Vektor ist `![ _, _ ]`. Zu beachten ist,
|
||||
dass man bei Zahlen explizit einen Typ angeben muss, sonst denkt sich
|
||||
@@ -61,8 +45,8 @@ Dann eine Vektorgleichung komponentenweise aufteilt.
|
||||
Für jede Komponente kann man dann mit `simp` und `ring` weiterkommen.
|
||||
"
|
||||
|
||||
notation "ℚ³" => Fin 3 → ℚ
|
||||
notation "ℚ^(" n ")" => (Fin n) → ℚ
|
||||
local notation "ℚ³" => Fin 3 → ℚ
|
||||
local notation "ℚ^(" n ")" => (Fin n) → ℚ
|
||||
|
||||
Statement
|
||||
""
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Pi -- definiert `Module ℚ (fin 2 → ℚ)`
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
import Mathlib.Tactic.FinCases
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 3
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 4
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 5
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
@@ -8,7 +8,7 @@ import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 6
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
@@ -10,7 +10,7 @@ import Mathlib.LinearAlgebra.Span
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 7
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
@@ -8,7 +8,7 @@ import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module"
|
||||
Level 8
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.LinearMap -- definiert `→ₗ`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Basis"
|
||||
Level 1
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.LinearMap -- definiert `→ₗ`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
-- import Mathlib.LinearAlgebra.Finsupp
|
||||
import Mathlib.Algebra.BigOperators.Basic -- default
|
||||
-- import Mathlib.LinearAlgebra.LinearIndependent
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Basis"
|
||||
Level 2
|
||||
|
||||
Title "Lineare Unabhängigkeit"
|
||||
|
||||
namespace Ex_LinIndep
|
||||
|
||||
scoped notation "ℝ²" => Fin 2 → ℝ
|
||||
|
||||
Introduction
|
||||
"
|
||||
"
|
||||
|
||||
Statement
|
||||
"Zeige, dass `![1, 0], ![1, 1]` linear unabhängig über `ℝ` sind."
|
||||
: LinearIndependent ℝ ![(![1, 0] : ℝ²), ![1, 1]] := by
|
||||
Hint "`rw [Fintype.linearIndependent_iff]`"
|
||||
rw [Fintype.linearIndependent_iff]
|
||||
Hint "`intros c h`"
|
||||
intros c h
|
||||
Hint "BUG: `simp at h` does not work :("
|
||||
simp at h -- doesn't work
|
||||
sorry
|
||||
|
||||
-- rw [Fintype.linearIndependent_iff]
|
||||
-- intros c h
|
||||
-- simp at h
|
||||
-- intros i
|
||||
-- fin_cases i
|
||||
-- swap
|
||||
-- { exact h.2 }
|
||||
-- { have h' := h.1
|
||||
-- rw [h.2, add_zero] at h'
|
||||
-- exact h'}
|
||||
|
||||
end Ex_LinIndep
|
||||
@@ -0,0 +1,32 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Basis"
|
||||
Level 4
|
||||
|
||||
Title "Basis"
|
||||
|
||||
namespace Ex_Basis
|
||||
|
||||
scoped notation "ℝ²" => Fin 2 → ℝ
|
||||
|
||||
open Submodule
|
||||
|
||||
Introduction
|
||||
"
|
||||
|
||||
"
|
||||
|
||||
lemma exercise1 : LinearIndependent ℝ ![(![1, 0] : ℝ²), ![1, 1]] := sorry
|
||||
|
||||
lemma exercise2 : ⊤ ≤ span ℝ (Set.range ![(![1, 0] : Fin 2 → ℝ), ![1, 1]]) := sorry
|
||||
|
||||
Statement : Basis (Fin 2) ℝ ℝ² := by
|
||||
apply Basis.mk
|
||||
apply exercise1
|
||||
apply exercise2
|
||||
|
||||
end Ex_Basis
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
@@ -8,7 +8,7 @@ import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 1
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
@@ -11,7 +11,7 @@ import Mathlib
|
||||
|
||||
open Submodule
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 2
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Basic
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 3
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Basic
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 4
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
open Submodule
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 5
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
open Submodule
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 6
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 7
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
@@ -6,7 +6,7 @@ import Mathlib.LinearAlgebra.Span
|
||||
|
||||
universe u
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 8
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Module2"
|
||||
Level 9
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import Adam.Levels.Numbers.L01_PNat
|
||||
import Adam.Levels.Numbers.L02_PNat
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import TestGame.Metadata
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "TestGame"
|
||||
Game "Adam"
|
||||
World "Numbers"
|
||||
Level 1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user