Merge branch 'main' of github.com:leanprover-community/lean4game
commit
572be60c65
@ -1,164 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lean Game Server</title>
|
||||
<link rel="stylesheet" href="frontpage.css">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.css" integrity="sha384-3UiQGuEI4TTMaFmGIZumfRPtfKQ3trwQE2JgosJxCnGmQpL/lJdjpcHkaaFwHlcI" crossorigin="anonymous">
|
||||
|
||||
<!-- The loading of KaTeX is deferred to speed up page rendering -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.js" integrity="sha384-G0zcxDFp5LWZtDuRMnBkk3EphCK1lhEf4UEyEM693ka574TZGwo4IWwS6QLzM/2t" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- To automatically render math in text elements, include the auto-render extension: -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
|
||||
onload="renderMathInElement(document.body);"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Lean Game Server</h1>
|
||||
|
||||
<p>Welcome to the Lean Game Server where you can find interactive learning
|
||||
games about <a target="_blank" href="https://leanprover-community.github.io/">Lean</a>.<p>
|
||||
|
||||
<div class="game-list">
|
||||
|
||||
<div class="game" onclick="location.href='#/game/adam';" style="cursor: pointer;">
|
||||
<div class="wrapper">
|
||||
<div class="title">Formaloversum</div>
|
||||
<div class="short-description">Erkunde das Leansche Universum mit deinem Robo,
|
||||
welcher dir bei der Verständigung mit den Formalosophen zur Seite steht.
|
||||
</div>
|
||||
<img class="image" src="data/formaloversum.png" alt="">
|
||||
<div class="long description">
|
||||
<p>Dieses Spiel führt die Grundlagen zur Beweisführung in Lean ein und schneidet danach
|
||||
verschiedene Bereiche des Bachelorstudiums an.</p>
|
||||
|
||||
<p>(Das Spiel befindet sich noch in der Entstehungsphase.)</p>
|
||||
|
||||
<p>Das Spiel wurde im Rahmen des Projekts <a target="_blank" href="https://hhu-adam.github.io/">ADAM</a>
|
||||
an der HHU in Düsseldorf
|
||||
entwickelt.</p>
|
||||
</div>
|
||||
</div>
|
||||
<table class="info">
|
||||
<tr>
|
||||
<td title="consider playing these games first.">Prerequisites</td>
|
||||
<td>-</td>
|
||||
<!-- <td>
|
||||
<ul>
|
||||
<li>-</li>
|
||||
</ul>
|
||||
</td> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Worlds</td>
|
||||
<td>?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Levels</td>
|
||||
<td>?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Language</td>
|
||||
<td title="in German">🇩🇪</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="game" onclick="location.href='#/game/nng';" style="cursor: pointer;">
|
||||
<div class="wrapper">
|
||||
<div class="title">Natural Number Game</div>
|
||||
<div class="short-description">
|
||||
The classical introduction game for Lean.
|
||||
</div>
|
||||
<div class="image" src="data/formaloversum.png" alt=""></div>
|
||||
<div class="long description">
|
||||
<p>In this game you recreate the natural numbers
|
||||
\(\mathbb{N}\) from the Peano axioms, learning the basics
|
||||
about theorem proving in Lean.</p>
|
||||
|
||||
<p>This is a good first introduction to Lean!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<table class="info">
|
||||
<tr>
|
||||
<td title="consider playing these games first.">Prerequisites</td>
|
||||
<td>-</td>
|
||||
<!-- <td>
|
||||
<ul>
|
||||
<li>-</li>
|
||||
</ul>
|
||||
</td> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Worlds</td>
|
||||
<td>9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Levels</td>
|
||||
<td>72</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Language</td>
|
||||
<td title="in English">🇬🇧</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Adding new games</h2>
|
||||
<p>
|
||||
If you consider writing your own game, you should use the
|
||||
<a target="_blank" href="https://github.com/hhu-adam/NNG4">NNG Github Repo</a>
|
||||
as a template.
|
||||
</p>
|
||||
<p>
|
||||
There will be an option to load and run games through the server
|
||||
directly by specifying a URL, but this is still in development.
|
||||
</p>
|
||||
<p>
|
||||
To add games to this page, you should get in contact as
|
||||
games will need to be added manually.
|
||||
</p>
|
||||
|
||||
<h2>Impressum</h2>
|
||||
|
||||
<p>
|
||||
When running a game, 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 the game progress is stored in the
|
||||
browser as site data. The game progress is not saved on the server;
|
||||
if you delete your browser storage, it will be completely gone.
|
||||
</p>
|
||||
<p>Our server is located in Germany.</p>
|
||||
|
||||
<h3>Contact information</h3>
|
||||
<p>
|
||||
Jon Eugster<br>
|
||||
Mathematisches Institut der Heinrich-Heine-Universität Düsseldorf<br>
|
||||
Universitätsstr. 1<br>
|
||||
40225 Düsseldorf<br>
|
||||
Germany<br>
|
||||
<a target="_blank" href="https://www.math.hhu.de/en/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/jon-eugster">Contact Details</a>
|
||||
<p>
|
||||
<div class="github-link">
|
||||
<a target="_blank" href="https://github.com/leanprover-community/lean4game"
|
||||
title="View the lean game server on github">
|
||||
<svg height="32" aria-hidden="true" viewBox="0 0 16 16" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github v-align-middle">
|
||||
<path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Operate in the directory where this file is located
|
||||
cd $(dirname $0)
|
||||
|
||||
# Build Adam
|
||||
( rm -rf adam
|
||||
git clone https://github.com/hhu-adam/Robo adam/
|
||||
cd adam
|
||||
docker rmi adam:latest || true
|
||||
docker build \
|
||||
--rm -f Dockerfile -t adam:latest .
|
||||
)
|
||||
|
||||
# Build NNG
|
||||
( rm -rf nng
|
||||
git clone https://github.com/hhu-adam/NNG4 nng/
|
||||
cd nng
|
||||
docker rmi nng:latest || true
|
||||
docker build \
|
||||
--rm -f Dockerfile -t nng:latest .
|
||||
)
|
@ -0,0 +1,128 @@
|
||||
import { spawn } from 'child_process'
|
||||
import fs from 'fs';
|
||||
import request from 'request'
|
||||
import decompress from 'decompress'
|
||||
import requestProgress from 'request-progress'
|
||||
import { Octokit } from 'octokit';
|
||||
|
||||
const TOKEN = process.env.LEAN4GAME_GITHUB_TOKEN
|
||||
const octokit = new Octokit({
|
||||
auth: TOKEN
|
||||
})
|
||||
|
||||
const progress = {}
|
||||
|
||||
async function runProcess(id, cmd, args, cwd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ls = spawn(cmd, args, {cwd});
|
||||
|
||||
ls.stdout.on('data', (data) => {
|
||||
progress[id].output += data.toString()
|
||||
});
|
||||
|
||||
ls.stderr.on('data', (data) => {
|
||||
progress[id].output += data.toString()
|
||||
});
|
||||
|
||||
ls.on('close', (code) => {
|
||||
resolve()
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
async function download(id, url, dest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// The options argument is optional so you can omit it
|
||||
requestProgress(request({
|
||||
url,
|
||||
headers: {
|
||||
'User-Agent': 'abentkamp',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'Authorization': 'Bearer '+TOKEN
|
||||
}
|
||||
}))
|
||||
.on('progress', function (state) {
|
||||
progress[id].output += `Downloaded ${Math.round(state.size.transferred/1024/1024)}MB\n`
|
||||
})
|
||||
.on('error', function (err) {
|
||||
reject(err)
|
||||
})
|
||||
.on('end', function () {
|
||||
resolve()
|
||||
})
|
||||
.pipe(fs.createWriteStream(dest));
|
||||
})
|
||||
}
|
||||
|
||||
async function doImport (owner, repo, id) {
|
||||
progress[id].output += `Import starting in a few seconds...\n`
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
let artifactId = null
|
||||
try {
|
||||
const artifacts = await octokit.request('GET /repos/{owner}/{repo}/actions/artifacts', {
|
||||
owner,
|
||||
repo,
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
})
|
||||
// choose latest artifact
|
||||
const artifact = artifacts.data.artifacts
|
||||
.reduce((acc, cur) => acc.created_at < cur.created_at ? cur : acc)
|
||||
artifactId = artifact.id
|
||||
const url = artifact.archive_download_url
|
||||
if (!fs.existsSync("tmp")){
|
||||
fs.mkdirSync("tmp");
|
||||
}
|
||||
progress[id].output += `Download from ${url}\n`
|
||||
await download(id, url, `tmp/artifact_${artifactId}.zip`)
|
||||
progress[id].output += `Download finished.\n`
|
||||
progress[id].output += `Unpacking ZIP.\n`
|
||||
const files = await decompress(`tmp/artifact_${artifactId}.zip`, `tmp/artifact_${artifactId}`)
|
||||
if (files.length != 1) { throw Error(`Unexpected number of files in ZIP: ${files.length}`) }
|
||||
progress[id].output += `Unpacking TAR.\n`
|
||||
const files_inner = await decompress(`tmp/artifact_${artifactId}/${files[0].path}`, `tmp/artifact_${artifactId}_inner`)
|
||||
let manifest = fs.readFileSync(`tmp/artifact_${artifactId}_inner/manifest.json`);
|
||||
manifest = JSON.parse(manifest);
|
||||
if (manifest.length !== 1) {
|
||||
throw `Unexpected manifest: ${JSON.stringify(manifest)}`
|
||||
}
|
||||
manifest[0].RepoTags = [`github-${owner}:${repo}`]
|
||||
fs.writeFileSync(`tmp/artifact_${artifactId}_inner/manifest.json`, JSON.stringify(manifest));
|
||||
await runProcess(id, "tar", ["-cvf", `../archive_${artifactId}.tar`, "."], `tmp/artifact_${artifactId}_inner/`)
|
||||
await runProcess(id, "docker", ["load", "-i", `tmp/archive_${artifactId}.tar`])
|
||||
progress[id].done = true
|
||||
progress[id].output += `Done.\n`
|
||||
} catch (e) {
|
||||
progress[id].output += `Error: ${e.toString()}\n${e.stack}`
|
||||
} finally {
|
||||
if (artifactId) {
|
||||
fs.rmSync(`tmp/artifact_${artifactId}.zip`, {force: true, recursive: true});
|
||||
fs.rmSync(`tmp/artifact_${artifactId}`, {force: true, recursive: true});
|
||||
fs.rmSync(`tmp/artifact_${artifactId}_inner`, {force: true, recursive: true});
|
||||
fs.rmSync(`tmp/archive_${artifactId}.tar`, {force: true, recursive: true});
|
||||
}
|
||||
progress[id].done = true
|
||||
}
|
||||
}
|
||||
|
||||
export const importTrigger = (req, res) => {
|
||||
const owner = req.params.owner
|
||||
const repo = req.params.repo
|
||||
const id = req.params.owner + '/' + req.params.repo
|
||||
if(!/^[\w.-]+\/[\w.-]+$/.test(id)) { res.send(`Invalid repo name ${id}`); return }
|
||||
|
||||
if(!progress[id] || progress[id].done) {
|
||||
progress[id] = {output: "", done: false}
|
||||
doImport(owner, repo, id)
|
||||
}
|
||||
|
||||
res.redirect(`/import/status/${owner}/${repo}`)
|
||||
}
|
||||
|
||||
export const importStatus = (req, res) => {
|
||||
const owner = req.params.owner
|
||||
const repo = req.params.repo
|
||||
const id = req.params.owner + '/' + req.params.repo
|
||||
res.send(`<html><head><meta http-equiv="refresh" content="5"></head><body><pre>${progress[id]?.output ?? "Nothing here."}</pre></body></html>`)
|
||||
}
|
Loading…
Reference in New Issue