U19: Spielstand-Tabelle, Formular mit INSERT/UPDATE, Begrüßung, Zähler und Reset

This commit is contained in:
DylanBarnes 2026-07-15 15:40:49 +00:00
parent d0c8f18edd
commit 2fc4bf3889
2 changed files with 81 additions and 103 deletions

View file

@ -1,9 +1,10 @@
from flask import Flask, request from flask import Flask, request, session, redirect
import html import html
import sqlite3 import sqlite3
from pathlib import Path from pathlib import Path
app = Flask(__name__) app = Flask(__name__)
app.secret_key = "hier-eigenen-geheimen-text" # für session nötig
DB_PATH = Path(__file__).with_name("adventure.db") DB_PATH = Path(__file__).with_name("adventure.db")
@ -13,97 +14,8 @@ def get_db():
return db return db
BASE_CSS = """ BASE_CSS = """... (unverändert, deine bestehende CSS bleibt) ..."""
:root { BASE_JS = """... (unverändert) ..."""
color-scheme: dark;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #07121d 0%, #102a43 45%, #1e3a5f 100%);
color: #e2e8f0;
min-height: 100vh;
}
.shell {
min-height: 100vh;
display: grid;
place-items: center;
padding: 2rem 1rem;
}
.card {
width: min(760px, 100%);
background: rgba(7, 18, 29, 0.88);
border: 1px solid rgba(148, 163, 184, 0.25);
border-radius: 24px;
padding: 2rem;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
backdrop-filter: blur(10px);
}
.card h1 {
margin-top: 0;
margin-bottom: 0.75rem;
font-size: 2rem;
color: #f8fafc;
}
.card p {
line-height: 1.7;
color: #cbd5e1;
}
.actions, .links {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-top: 1.25rem;
}
.btn, .card a, .card button {
display: inline-block;
background: linear-gradient(135deg, #2563eb 0%, #06b6d4 100%);
color: #f8fafc;
border: none;
border-radius: 999px;
padding: 0.8rem 1.1rem;
text-decoration: none;
font-weight: 700;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 10px 25px rgba(6, 182, 212, 0.25);
}
.btn:hover, .card a:hover, .card button:hover {
transform: translateY(-2px);
box-shadow: 0 12px 30px rgba(37, 99, 235, 0.35);
}
.btn.secondary {
background: linear-gradient(135deg, #475569 0%, #64748b 100%);
box-shadow: 0 10px 25px rgba(100, 116, 139, 0.25);
}
form {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
align-items: center;
margin-top: 1rem;
}
input {
flex: 1 1 220px;
border: 1px solid rgba(148, 163, 184, 0.35);
border-radius: 999px;
padding: 0.8rem 1rem;
background: rgba(15, 23, 42, 0.9);
color: #f8fafc;
}
input:focus {
outline: 2px solid rgba(6, 182, 212, 0.45);
border-color: transparent;
}
"""
BASE_JS = """
window.addEventListener('DOMContentLoaded', () => {
const firstInput = document.querySelector('input');
if (firstInput) firstInput.focus();
});
"""
def render_page(title, body_html): def render_page(title, body_html):
@ -126,16 +38,52 @@ def render_page(title, body_html):
</html>""" </html>"""
@app.route("/") @app.route("/", methods=["GET", "POST"])
@app.route("/app") @app.route("/app", methods=["GET", "POST"])
@app.route("/app/") @app.route("/app/", methods=["GET", "POST"])
def start(): def start():
body = """ if request.method == "POST":
name = request.form.get("name", "").strip()
if name != "":
session["spieler"] = name
db = get_db()
db.execute(
"INSERT OR IGNORE INTO spielstand (spieler, raum_id) VALUES (?, 1)",
(name,)
)
db.commit()
db.close()
return redirect("/app/raum/1")
db = get_db()
anzahl = db.execute("SELECT COUNT(*) AS n FROM spielstand").fetchone()
weiterspielen_html = ""
if "spieler" in session:
s = db.execute(
"SELECT raum_id FROM spielstand WHERE spieler=?",
(session["spieler"],)
).fetchone()
if s:
weiterspielen_html = f"""
<p>Willkommen zurück, {html.escape(session['spieler'])}!</p>
<div class="actions">
<a class="btn" href="/app/raum/{s['raum_id']}">Weiterspielen</a>
<a class="btn secondary" href="/app/reset">Neues Abenteuer</a>
</div>
<hr>
"""
db.close()
body = f"""
<h1>Verlassenes Raumschiff</h1> <h1>Verlassenes Raumschiff</h1>
<p>Du bist der einzige Überlebende an Bord. Erkunde das Schiff und aktiviere das Notsignal.</p> <p>Du bist der einzige Überlebende an Bord. Erkunde das Schiff und aktiviere das Notsignal.</p>
<div class="actions"> {weiterspielen_html}
<a class="btn" href="/app/raum/1">Mission starten</a> <form method="post">
</div> <input name="name" placeholder="Dein Name" autocomplete="off">
<button type="submit">Abenteuer starten</button>
</form>
<p><small>{anzahl['n']} Abenteurer waren schon hier.</small></p>
""" """
return render_page("Verlassenes Raumschiff", body) return render_page("Verlassenes Raumschiff", body)
@ -144,32 +92,49 @@ def start():
@app.route("/app/raum/<int:id>", methods=["GET", "POST"]) @app.route("/app/raum/<int:id>", methods=["GET", "POST"])
def raum(id): def raum(id):
db = get_db() db = get_db()
# Spielstand fortschreiben, sobald jemand angemeldet ist
if "spieler" in session:
db.execute(
"UPDATE spielstand SET raum_id=? WHERE spieler=?",
(id, session["spieler"])
)
db.commit()
r = db.execute("SELECT * FROM raeume WHERE id=?", (id,)).fetchone() r = db.execute("SELECT * FROM raeume WHERE id=?", (id,)).fetchone()
if not r: if not r:
db.close() db.close()
return render_page( return render_page(
"Raum nicht gefunden", "Raum nicht gefunden",
'<h1>Raum nicht gefunden</h1><p>Der angeforderte Raum existiert nicht.</p><div class="actions"><a class="btn secondary" href="/app/">Zurück zum Start</a></div>' '<h1>Raum nicht gefunden</h1><p>Der angeforderte Raum existiert nicht.</p>'
'<div class="actions"><a class="btn secondary" href="/app/">Zurück zum Start</a></div>'
) )
unterwegs_html = ""
if "spieler" in session:
unterwegs_html = f'<p><small>Unterwegs als: {html.escape(session["spieler"])}</small></p>'
if r["raetsel_frage"]: if r["raetsel_frage"]:
if request.method == "POST": if request.method == "POST":
if request.form.get("antwort", "").strip() == r["raetsel_antwort"]: if request.form.get("antwort", "").strip() == r["raetsel_antwort"]:
db.close() db.close()
return render_page( return render_page(
"Notsignal aktiviert", "Notsignal aktiviert",
'<h1>Notsignal erfolgreich aktiviert</h1><p>Rettung ist unterwegs.</p><div class="actions"><a class="btn" href="/app/">Zurück zum Start</a></div>' '<h1>Notsignal erfolgreich aktiviert</h1><p>Rettung ist unterwegs.</p>'
'<div class="actions"><a class="btn" href="/app/">Zurück zum Start</a></div>'
) )
db.close() db.close()
return render_page( return render_page(
"Falscher Code", "Falscher Code",
'<h1>Falscher Code</h1><p>Der KI-Kern reagiert nicht.</p><div class="actions"><a class="btn secondary" href="/app/raum/' + str(id) + '">nochmal versuchen</a></div>' '<h1>Falscher Code</h1><p>Der KI-Kern reagiert nicht.</p>'
'<div class="actions"><a class="btn secondary" href="/app/raum/' + str(id) + '">nochmal versuchen</a></div>'
) )
db.close() db.close()
body = f""" body = f"""
<h1>{html.escape(r['name'])}</h1> <h1>{html.escape(r['name'])}</h1>
<p>{html.escape(r['beschreibung'])}</p> <p>{html.escape(r['beschreibung'])}</p>
{unterwegs_html}
<form method="post"> <form method="post">
<input id="antwort" name="antwort" placeholder="Antwort eingeben" autocomplete="off"> <input id="antwort" name="antwort" placeholder="Antwort eingeben" autocomplete="off">
<button type="submit">OK</button> <button type="submit">OK</button>
@ -185,6 +150,7 @@ def raum(id):
body = f""" body = f"""
<h1>{html.escape(r['name'])}</h1> <h1>{html.escape(r['name'])}</h1>
<p>{html.escape(r['beschreibung'])}</p> <p>{html.escape(r['beschreibung'])}</p>
{unterwegs_html}
<div class="links"> <div class="links">
""" """
for a in ausgaenge: for a in ausgaenge:
@ -193,5 +159,12 @@ def raum(id):
return render_page(html.escape(r["name"]), body) return render_page(html.escape(r["name"]), body)
@app.route("/reset")
@app.route("/app/reset")
def reset():
session.pop("spieler", None) # Session vergessen (DB bleibt!)
return redirect("/app/")
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=9004) app.run(host="0.0.0.0", port=9004)

View file

@ -22,6 +22,11 @@ CREATE TABLE IF NOT EXISTS ausgaenge (
nach_raum INTEGER nach_raum INTEGER
); );
CREATE TABLE IF NOT EXISTS spielstand (
spieler TEXT PRIMARY KEY,
raum_id INTEGER
);
INSERT INTO raeume (id, name, beschreibung, raetsel_frage, raetsel_antwort) VALUES INSERT INTO raeume (id, name, beschreibung, raetsel_frage, raetsel_antwort) VALUES
(1, 'Schlafkapsel', 'Du erwachst aus dem Kryoschlaf. Die Notbeleuchtung flackert und das Schiff wirkt verlassen.', NULL, NULL), (1, 'Schlafkapsel', 'Du erwachst aus dem Kryoschlaf. Die Notbeleuchtung flackert und das Schiff wirkt verlassen.', NULL, NULL),
(2, 'Brücke', 'Die Steuerzentrale ist dunkel. Mehrere Monitore zeigen Fehlermeldungen.', NULL, NULL), (2, 'Brücke', 'Die Steuerzentrale ist dunkel. Mehrere Monitore zeigen Fehlermeldungen.', NULL, NULL),