Compare commits
3 Commits
d82d5a34c7
...
93f8563807
| Author | SHA1 | Date | |
|---|---|---|---|
| 93f8563807 | |||
| b3d4f4a198 | |||
| b4f7c8eae0 |
63
app.py
63
app.py
@ -70,36 +70,67 @@ def upload():
|
||||
secret = session.get('secret')
|
||||
if not secret or secret not in games:
|
||||
return redirect(url_for('host'))
|
||||
|
||||
game = games[secret]
|
||||
|
||||
# retrieve uploaded file
|
||||
file = request.files.get('file')
|
||||
if not file:
|
||||
return render_template('upload.html', error='Keine Datei ausgewählt')
|
||||
|
||||
# try to read Excel
|
||||
try:
|
||||
df = pd.read_excel(file)
|
||||
except Exception:
|
||||
return render_template('upload.html', error='Ungültige Excel-Datei')
|
||||
|
||||
# enforce maximum of 100 questions
|
||||
max_questions = 100
|
||||
if df.shape[0] > max_questions:
|
||||
return render_template(
|
||||
'upload.html',
|
||||
error=f'Maximal dürfen {max_questions} Fragen hochgeladen werden. Ihre Datei enthält {df.shape[0]}.')
|
||||
|
||||
# mandatory columns
|
||||
required = ['question','answer1','answer2','answer3','answer4','correct']
|
||||
if not all(col in df.columns for col in required):
|
||||
return render_template('upload.html', error=f'Fehler in Datei: Fehlende Spalten. Erforderlich: {required}')
|
||||
required = ['question', 'answer1', 'answer2', 'answer3', 'answer4', 'correct']
|
||||
missing = [col for col in required if col not in df.columns]
|
||||
if missing:
|
||||
return render_template(
|
||||
'upload.html',
|
||||
error=f"Fehler in Datei: Fehlende Spalte(n): {', '.join(missing)}"
|
||||
)
|
||||
|
||||
# validate that 'correct' references one of the answer columns
|
||||
if not df['correct'].isin(['answer1','answer2','answer3','answer4']).all():
|
||||
return render_template('upload.html', error='Fehler in Datei: Antwortspalte "correct" muss einen der Werte "answer1", "answer2", "answer3" oder "answer4" enthalten.')
|
||||
valid_keys = ['answer1', 'answer2', 'answer3', 'answer4']
|
||||
invalid_mask = ~df['correct'].isin(valid_keys)
|
||||
if invalid_mask.any():
|
||||
idx = invalid_mask.idxmax()
|
||||
excel_line = idx + 2 # Header is line 1
|
||||
bad_value = df.at[idx, 'correct']
|
||||
return render_template(
|
||||
'upload.html',
|
||||
error=(
|
||||
f'Fehler in Zeile {excel_line}: '
|
||||
f'"correct" enthält "{bad_value}", '
|
||||
f'muss einer der Werte {valid_keys} sein.'
|
||||
)
|
||||
)
|
||||
|
||||
# build per-game question list
|
||||
questions = []
|
||||
for _, row in df.iterrows():
|
||||
col = row['correct']
|
||||
questions.append({
|
||||
'question': row['question'],
|
||||
'options': [row[f'answer{i}'] for i in range(1,5)],
|
||||
'correct': row[col]
|
||||
'question': str(row['question']),
|
||||
'options': [str(row[f'answer{i}']) for i in range(1, 5)],
|
||||
'correct': str(row[col])
|
||||
})
|
||||
|
||||
game['questions'] = questions
|
||||
# once upload and validation succeeds, redirect to host view (which will show the QR)
|
||||
# redirect to host view, which will show the QR code
|
||||
return redirect(url_for('host'))
|
||||
|
||||
|
||||
@app.route('/new_game', methods=['POST'])
|
||||
def new_game():
|
||||
if session.get('role') != 'host':
|
||||
@ -402,7 +433,12 @@ def _send_question(secret):
|
||||
|
||||
def _score_and_emit(secret):
|
||||
game = games[secret]
|
||||
score_map = {1: 4, 2: 3, 3: 2, 4: 1}
|
||||
# Punkteverteilung:
|
||||
# 1. richtige Antwort → 5 Punkte
|
||||
# 2. richtige Antwort → 4 Punkte
|
||||
# 3. richtige Antwort → 3 Punkte
|
||||
# alle weiteren richtigen Antworten → 1 Punkt
|
||||
score_map = {1: 5, 2: 4, 3: 3}
|
||||
per_q = []
|
||||
|
||||
# grab the current question’s correct answer
|
||||
@ -414,9 +450,10 @@ def _score_and_emit(secret):
|
||||
prev_correct = sum(1 for p, a in game['answered'][:-1] if a == correct)
|
||||
rank = prev_correct + 1
|
||||
|
||||
# assign points only if this one is correct and within top‐4
|
||||
if ans == correct and rank <= 4:
|
||||
pts = score_map[rank]
|
||||
# assign points only if korrekt
|
||||
if ans == correct:
|
||||
# für Platz 1–3 nach Mapping, ab Platz 4 immer 1 Punkt
|
||||
pts = score_map.get(rank, 1)
|
||||
game['players'][pid]['score'] += pts
|
||||
per_q.append({
|
||||
'name': game['players'][pid]['name'],
|
||||
|
||||
@ -1,24 +1,73 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
<h1 class="mb-4">Fragebogen hochladen</h1>
|
||||
<h1 class="mb-4">Public Quiz</h1>
|
||||
|
||||
<!-- Download-Link zur Beispiel-Datei -->
|
||||
<div class="mb-3">
|
||||
<a href="{{ url_for('static', filename='questions_example.xlsx') }}" class="btn btn-outline-secondary">
|
||||
Beispiel-Excel-Datei herunterladen
|
||||
</a>
|
||||
</div>
|
||||
<!-- Einführung -->
|
||||
<p class="lead">
|
||||
Willkommen zum interaktiven Gruppenquiz! Lade deinen eigenen Fragebogen hoch und starte ein spannendes Live-Quiz.
|
||||
Deine Teilnehmer beantworten die Fragen schnell und wettbewerbsorientiert direkt über ihre Smartphones.
|
||||
</p>
|
||||
|
||||
<form action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Excel-Datei auswählen</label>
|
||||
<input class="form-control" type="file" id="file" name="file" accept=".xlsx,.xls">
|
||||
<!-- Punktevergabe -->
|
||||
<p>
|
||||
Schnelle und richtige Antworten werden mit mehr Punkten belohnt. Jeder Spieler hat pro Frage nur einen Versuch.
|
||||
Ein guter Mix aus Schnelligkeit und Genauigkeit zahlt sich aus!
|
||||
</p>
|
||||
<p class="text-muted">
|
||||
<strong>Hinweis:</strong> Die ersten drei richtigen Antworten erhalten höhere Punktwerte, alle weiteren richtigen Antworten bringen jeweils 1 Punkt.
|
||||
</p>
|
||||
<ul>
|
||||
<li>erste richtige Antwort → 5 Punkte</li>
|
||||
<li>zweite richtige Antwort → 4 Punkte</li>
|
||||
<li>dritte richtige Antwort → 3 Punkte</li>
|
||||
<li>jeder weitere richtige Antwort → 1 Punkt</li>
|
||||
</ul>
|
||||
|
||||
<p>Sobald die richtige Antwort für alle anzeigt wird, werden keine weiteren Punkte verteilt.</p>
|
||||
|
||||
<!-- Dateivorlage -->
|
||||
<h2 class="mb-4">Fragebogen erstellen</h2>
|
||||
<p>
|
||||
Nutze die <strong>Beispieldatei</strong> als Vorlage und trage deine Fragen sowie die Antwortoptionen ein.
|
||||
Deine Excel-Datei sollte folgende Spalten enthalten:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>question</code>: Text der Frage (z. B. „Wer baute die Arche?“)</li>
|
||||
<li><code>answer1</code> bis <code>answer4</code>: Vier Antwortmöglichkeiten</li>
|
||||
<li><code>correct</code>: Spaltenname der richtigen Antwort (<code>answer1</code>-<code>answer4</code>)</li>
|
||||
</ul>
|
||||
<p class="text-muted">
|
||||
Unterstützte Formate: <code>.xlsx</code>, <code>.xls</code>
|
||||
Maximal 100 Fragen!
|
||||
</p>
|
||||
|
||||
<!-- Download-Link zur Beispiel-Datei -->
|
||||
<div class="mb-4">
|
||||
<a href="{{ url_for('static', filename='questions_example.xlsx') }}" class="btn btn-warning">
|
||||
Beispieldatei Fragebogen (Excel)
|
||||
</a>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Hochladen</button>
|
||||
</form>
|
||||
|
||||
{% if error %}
|
||||
<div class="alert alert-danger mt-3">{{ error }}</div>
|
||||
{% endif %}
|
||||
<!-- Upload-Form -->
|
||||
<form action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Fragebogen hochladen</label>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
name="file"
|
||||
class="form-control"
|
||||
accept=".xlsx, .xls"
|
||||
required
|
||||
>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Spiel beginnen</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
<!-- Fehlermeldung -->
|
||||
{% if error %}
|
||||
<div class="alert alert-danger mt-3" role="alert">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user