add show answer
This commit is contained in:
parent
985a70abf3
commit
6fc98c48d9
28
app.py
28
app.py
@ -53,7 +53,8 @@ def host():
|
|||||||
games[secret] = {
|
games[secret] = {
|
||||||
'players': {}, 'order': [],
|
'players': {}, 'order': [],
|
||||||
'current_q': 0, 'answered': [],
|
'current_q': 0, 'answered': [],
|
||||||
'started': False, 'finished': False
|
'started': False, 'finished': False,
|
||||||
|
'revealed': False
|
||||||
}
|
}
|
||||||
|
|
||||||
# build join URL + QR
|
# build join URL + QR
|
||||||
@ -256,6 +257,8 @@ def on_submit_answer(data):
|
|||||||
if not secret or secret not in games or pid not in games[secret]['players']:
|
if not secret or secret not in games or pid not in games[secret]['players']:
|
||||||
return
|
return
|
||||||
game = games[secret]
|
game = games[secret]
|
||||||
|
if game.get('revealed'):
|
||||||
|
return
|
||||||
if any(pid == p for p,_ in game['answered']):
|
if any(pid == p for p,_ in game['answered']):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -301,7 +304,22 @@ def on_rejoin_game():
|
|||||||
join_room('player')
|
join_room('player')
|
||||||
join_room(pid)
|
join_room(pid)
|
||||||
_send_sync_state(pid, game)
|
_send_sync_state(pid, game)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('show_answer')
|
||||||
|
def on_show_answer():
|
||||||
|
secret = session.get('secret')
|
||||||
|
if session.get('role') != 'host' or not secret or secret not in games:
|
||||||
|
return
|
||||||
|
game = games[secret]
|
||||||
|
game['revealed'] = True
|
||||||
|
# find the correct answer text for current question
|
||||||
|
correct = questions[game['current_q']]['correct']
|
||||||
|
# emit to host so they can display it
|
||||||
|
emit('answer_revealed', {'correct': correct}, room='host')
|
||||||
|
# emit to all players so they can highlight it
|
||||||
|
socketio.emit('answer_revealed', {'correct': correct}, room='player')
|
||||||
|
|
||||||
|
|
||||||
# helpers
|
# helpers
|
||||||
|
|
||||||
@ -337,6 +355,7 @@ def _send_sync_state(pid, game):
|
|||||||
|
|
||||||
def _send_question(secret):
|
def _send_question(secret):
|
||||||
game = games[secret]
|
game = games[secret]
|
||||||
|
game['revealed'] = False
|
||||||
q = questions[game['current_q']]
|
q = questions[game['current_q']]
|
||||||
# clear previous answers
|
# clear previous answers
|
||||||
game['answered'].clear()
|
game['answered'].clear()
|
||||||
@ -403,4 +422,9 @@ def _score_and_emit(secret):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# show own IP address
|
||||||
|
import socket
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
ip_address = socket.gethostbyname(hostname)
|
||||||
|
print(f"Running on http://{ip_address}:5000/")
|
||||||
socketio.run(app, host='0.0.0.0', port=5000)
|
socketio.run(app, host='0.0.0.0', port=5000)
|
||||||
@ -25,14 +25,15 @@
|
|||||||
<!-- Question & Current Leaderboard -->
|
<!-- Question & Current Leaderboard -->
|
||||||
<div id="host-question" style="display:none;">
|
<div id="host-question" style="display:none;">
|
||||||
<h2 id="qText" style="font-size:5rem;"></h2>
|
<h2 id="qText" style="font-size:5rem;"></h2>
|
||||||
<button id="nextBtn" class="btn btn-warning mt-3">Nächste Frage</button>
|
<div id="host-results" style="display:none; margin:20px;">
|
||||||
|
<ul id="perQ" class="list-group mb-3 text-center"></ul>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<button id="showAnswerBtn" class="btn btn-info">Antwort zeigen</button>
|
||||||
|
<button id="nextBtn" class="btn btn-warning" disabled>Nächste Frage</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Per-Question and Overall Results -->
|
|
||||||
<div id="host-results" style="display:none;">
|
|
||||||
<h4>Question Results</h4>
|
|
||||||
<ul id="perQ" class="list-group mb-3"></ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Final Top-10 Leaderboard -->
|
<!-- Final Top-10 Leaderboard -->
|
||||||
<div id="final-results" style="display:none;" class="mt-4">
|
<div id="final-results" style="display:none;" class="mt-4">
|
||||||
@ -90,6 +91,9 @@
|
|||||||
$('#qrContainer, #startBtn, #rosterHeader, #roster').hide();
|
$('#qrContainer, #startBtn, #rosterHeader, #roster').hide();
|
||||||
$('#host-question').show();
|
$('#host-question').show();
|
||||||
$('#qText').text(data.question);
|
$('#qText').text(data.question);
|
||||||
|
$('#host-results').hide();
|
||||||
|
$('#showAnswerBtn').prop({ disabled: false }).show();
|
||||||
|
$('#nextBtn').prop('disabled', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Overall leaderboard updates (max 5 rows)
|
// Overall leaderboard updates (max 5 rows)
|
||||||
@ -103,21 +107,31 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Per-question results
|
|
||||||
socket.on('question_leader', data => {
|
|
||||||
console.log('Question leader:', data.results);
|
|
||||||
$('#perQ').empty();
|
|
||||||
data.results.forEach(r => {
|
|
||||||
$('#perQ').append(`<li class="list-group-item">${r.name}: +${r.points}</li>`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Next question
|
// Next question
|
||||||
$('#nextBtn').off('click').on('click', () => {
|
$('#nextBtn').off('click').on('click', () => {
|
||||||
console.log('Next question clicked');
|
console.log('Next question clicked');
|
||||||
socket.emit('next_question');
|
socket.emit('next_question');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// when host clicks “Show Answer”
|
||||||
|
$('#showAnswerBtn').off('click').on('click', () => {
|
||||||
|
socket.emit('show_answer');
|
||||||
|
});
|
||||||
|
|
||||||
|
// once server confirms the answer is revealed
|
||||||
|
socket.on('answer_revealed', data => {
|
||||||
|
// display the correct answer on host screen
|
||||||
|
$('#perQ').empty();
|
||||||
|
$('#perQ').append(
|
||||||
|
`<li class="list-group-item list-group-item-success" style="font-size:5rem;">${data.correct}</li>`
|
||||||
|
);
|
||||||
|
$('#host-results').show();
|
||||||
|
|
||||||
|
// disable Show Answer button, enable Next
|
||||||
|
$('#showAnswerBtn').prop('disabled', true);
|
||||||
|
$('#nextBtn').prop('disabled', false);
|
||||||
|
});
|
||||||
|
|
||||||
// Show final top-10 when game_over arrives
|
// Show final top-10 when game_over arrives
|
||||||
socket.on('game_over', data => {
|
socket.on('game_over', data => {
|
||||||
if (data.board) {
|
if (data.board) {
|
||||||
|
|||||||
@ -3,12 +3,15 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<style>
|
<style>
|
||||||
.option.selected {
|
.option.selected {
|
||||||
background-color: #0d6efd; /* bootstrap “primary” bg */
|
background-color:rgb(110, 168, 255); /* bootstrap “primary” bg */
|
||||||
color: white;
|
color: black;
|
||||||
}
|
}
|
||||||
.option.disabled {
|
.option.disabled {
|
||||||
background-color: #6c757d; /* bootstrap “secondary” bg */
|
background-color:rgb(148, 148, 148); /* bootstrap “secondary” bg */
|
||||||
color: white;
|
color: black;
|
||||||
|
}
|
||||||
|
.option.correct {
|
||||||
|
border: 5px solid #198754 !important; /* bootstrap “success” green */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container" id="player-app">
|
<div class="container" id="player-app">
|
||||||
@ -93,6 +96,30 @@
|
|||||||
renderOptions(data.options, false);
|
renderOptions(data.options, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// when the right answer is revealed
|
||||||
|
socket.on('answer_revealed', data => {
|
||||||
|
$('.option').each(function() {
|
||||||
|
const $opt = $(this);
|
||||||
|
if ($opt.text() === data.correct) {
|
||||||
|
// highlight as correct with green outline
|
||||||
|
$opt
|
||||||
|
.addClass('correct')
|
||||||
|
.removeClass('btn-outline-primary disabled')
|
||||||
|
.prop('disabled', true);
|
||||||
|
} else {
|
||||||
|
// any un-clicked options become permanently disabled
|
||||||
|
if (!$opt.hasClass('selected')) {
|
||||||
|
$opt
|
||||||
|
.addClass('disabled')
|
||||||
|
.removeClass('btn-outline-primary btn-primary')
|
||||||
|
.prop('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Handle answer clicks
|
// Handle answer clicks
|
||||||
$(document).on('click', '.option', function() {
|
$(document).on('click', '.option', function() {
|
||||||
const $all = $('.option');
|
const $all = $('.option');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user