Skip to content

Commit 51a6399

Browse files
committed
add nickname
1 parent 661f3e4 commit 51a6399

File tree

1 file changed

+139
-28
lines changed

1 file changed

+139
-28
lines changed

game05_1/quiz.py

Lines changed: 139 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import pgzrun
22
import polars as pl
3-
import random
3+
import os
4+
from pgzero.keyboard import keys
45

56
# ───────────────── CONFIG ─────────────────
67
TITLE = "Cyber Quiz Polars Edition"
78
WIDTH = 900
89
HEIGHT = 600
910
TEMPO_DOMANDA = 15
1011
NOME_FILE_CSV = "domande.csv"
12+
NOME_FILE_RISPOSTE = "risposte.csv"
1113

1214
# ───────────────── COLORI ─────────────────
1315
COLOR_BG = (10, 10, 25)
1416
COLOR_CARD = (30, 30, 50)
15-
COLOR_ACCENT = (0, 255, 200)
17+
COLOR_ACCENT = (0, 255, 200)
1618
COLOR_DANGER = (255, 45, 85)
1719
COLOR_SHADOW = (5, 5, 15)
1820
TEXT_MAIN = (255, 255, 255)
@@ -27,6 +29,10 @@
2729
game_over = False
2830
mouse_pos = (0, 0)
2931

32+
# Nickname / iniziale stato di inserimento
33+
entering_name = True
34+
nome_utente = ""
35+
3036
# Box
3137
question_box = Rect(50, 90, 800, 150)
3238
answer_boxes = [Rect(50, 300, 380, 110), Rect(470, 300, 380, 110),
@@ -39,21 +45,21 @@ def carica_e_mischia():
3945
try:
4046
# Leggiamo il CSV con Polars
4147
df = pl.read_csv(NOME_FILE_CSV)
42-
43-
# Rimescoliamo l'intero DataFrame.
44-
# shuffle=True con fraction=1.0 ci restituisce tutto il DF in ordine casuale
48+
49+
# Rimescoliamo l'intero DataFrame. shuffle=True con fraction=1.0
4550
df_shuffled = df.sample(fraction=1.0, shuffle=True)
46-
47-
# Convertiamo in una lista di dizionari per facilitare l'estrazione nel gioco
51+
52+
# Convertiamo in una lista di dizionari
4853
lista_domande = df_shuffled.to_dicts()
4954
contatore_totale = len(lista_domande)
50-
55+
5156
except Exception as e:
5257
print(f"Errore nel caricamento dati: {e}")
5358

59+
5460
def prossima_domanda():
5561
global domanda_corrente, indice_domande, secondi_mancanti, game_over
56-
62+
5763
if len(lista_domande) > 0:
5864
indice_domande += 1
5965
# .pop(0) prende la prima domanda e la RIMUOVE dalla lista -> Mai ripetizioni
@@ -62,65 +68,170 @@ def prossima_domanda():
6268
else:
6369
game_over = True
6470

71+
72+
# ───────────────── SALVATAGGIO RISPOSTE ─────────────────
73+
def init_file_risposte():
74+
"""Crea il file risposte con header se non esiste."""
75+
if not os.path.exists(NOME_FILE_RISPOSTE):
76+
with open(NOME_FILE_RISPOSTE, mode='w', newline='', encoding='utf-8') as f:
77+
writer = csv.writer(f)
78+
writer.writerow(["nome_utente", "id_domanda", "numero_risposta_fornita", "tempo_risposta"])
79+
80+
81+
def salva_risposta(nome, id_dom, numero_risposta, tempo_risposta):
82+
init_file_risposte()
83+
with open(NOME_FILE_RISPOSTE, mode='a', newline='', encoding='utf-8') as f:
84+
writer = csv.writer(f)
85+
writer.writerow([nome, id_dom, numero_risposta, tempo_risposta])
86+
87+
6588
# ───────────────── DISEGNO ─────────────────
6689
def draw_styled_rect(rect, color):
67-
screen.draw.filled_rect(Rect(rect.x+4, rect.y+4, rect.w, rect.h), COLOR_SHADOW)
90+
screen.draw.filled_rect(Rect(rect.x + 4, rect.y + 4, rect.w, rect.h), COLOR_SHADOW)
6891
screen.draw.filled_rect(rect, color)
6992

93+
7094
def draw():
7195
screen.fill(COLOR_BG)
96+
97+
# Se siamo nella fase di inserimento nickname
98+
if entering_name:
99+
screen.draw.text("Benvenuto a Cyber Quiz!", center=(WIDTH // 2, 120), fontsize=48, color=COLOR_ACCENT)
100+
screen.draw.text("Inserisci il tuo nickname e premi ENTER per iniziare:", center=(WIDTH // 2, 180), fontsize=28, color=TEXT_MAIN)
101+
102+
# box input
103+
input_box = Rect(WIDTH // 2 - 300, 230, 600, 60)
104+
draw_styled_rect(input_box, COLOR_CARD)
105+
display_name = nome_utente if nome_utente != "" else "(digita qui...)"
106+
screen.draw.text(display_name, center=input_box.center, fontsize=36, color=TEXT_MAIN)
107+
return
108+
72109
if game_over:
73-
screen.draw.text(f"SESSIONE FINITA\nPunteggio: {punteggio}/{contatore_totale}",
74-
center=(WIDTH//2, HEIGHT//2), fontsize=50, color=COLOR_ACCENT)
110+
screen.draw.text(f"SESSIONE FINITA\nPunteggio: {punteggio}/{contatore_totale}",
111+
center=(WIDTH // 2, HEIGHT // 2), fontsize=50, color=COLOR_ACCENT)
75112
return
76113

77114
# Info
78-
screen.draw.text(f"DOMANDA {indice_domande}/{contatore_totale}", (50, 20), color=COLOR_ACCENT, fontsize=25)
79-
screen.draw.text(f"PUNTI: {punteggio}", (WIDTH-150, 20), color=TEXT_MAIN, fontsize=25)
115+
screen.draw.text(f"GIOCATORE: {nome_utente}", (50, 20), color=COLOR_ACCENT, fontsize=22)
116+
screen.draw.text(f"DOMANDA {indice_domande}/{contatore_totale}", (50, 50), color=COLOR_ACCENT, fontsize=22)
117+
screen.draw.text(f"PUNTI: {punteggio}", (WIDTH - 150, 20), color=TEXT_MAIN, fontsize=25)
80118

81119
# Box Domanda
82120
draw_styled_rect(question_box, COLOR_CARD)
83-
screen.draw.textbox(domanda_corrente['domanda'], question_box.inflate(-40,-40), color=TEXT_MAIN)
121+
if domanda_corrente:
122+
screen.draw.textbox(str(domanda_corrente.get('domanda', '')) , question_box.inflate(-40, -40), color=TEXT_MAIN)
123+
else:
124+
screen.draw.textbox("Caricamento...", question_box.inflate(-40, -40), color=TEXT_MAIN)
84125

85126
# Timer Progressivo
86-
percent = secondi_mancanti / TEMPO_DOMANDA
127+
percent = secondi_mancanti / TEMPO_DOMANDA if TEMPO_DOMANDA > 0 else 0
87128
screen.draw.filled_rect(timer_bar_box, COLOR_SHADOW)
88129
screen.draw.filled_rect(Rect(timer_bar_box.x, timer_bar_box.y, int(timer_bar_box.w * percent), timer_bar_box.h), COLOR_ACCENT)
89130

90131
# Risposte
91132
for i in range(4):
92133
box = answer_boxes[i]
93-
chiave = f"risposta{i+1}"
134+
chiave = f"risposta{i + 1}"
94135
is_hover = box.collidepoint(mouse_pos)
95136
draw_styled_rect(box, (60, 60, 90) if is_hover else COLOR_CARD)
96-
screen.draw.textbox(str(domanda_corrente[chiave]), box.inflate(-20, -20), color=TEXT_MAIN)
137+
if domanda_corrente:
138+
screen.draw.textbox(str(domanda_corrente.get(chiave, '')), box.inflate(-20, -20), color=TEXT_MAIN)
139+
97140

98141
# ───────────────── INPUT & TIMER ─────────────────
99142
def on_mouse_move(pos):
100143
global mouse_pos
101144
mouse_pos = pos
102145

146+
103147
def on_mouse_down(pos):
104148
global punteggio
105-
if game_over: return
149+
if entering_name:
150+
return
151+
if game_over:
152+
return
106153

107154
for i, box in enumerate(answer_boxes):
108155
if box.collidepoint(pos):
109-
# Polars può leggere i numeri come int, quindi forziamo a stringa per il confronto
110-
if str(i + 1) == str(domanda_corrente['corretta']):
111-
punteggio += 1
156+
# tempo di risposta = tempo passato dalla visualizzazione (tempo iniziale - secondi_mancanti)
157+
tempo_risposta = TEMPO_DOMANDA - secondi_mancanti
158+
# Troviamo un id per la domanda: preferiamo campi 'id_domanda' o 'id', altrimenti usiamo l'indice attuale
159+
id_dom = None
160+
if domanda_corrente is not None:
161+
id_dom = domanda_corrente.get('id_domanda') if 'id_domanda' in domanda_corrente else domanda_corrente.get('id')
162+
if id_dom is None:
163+
id_dom = indice_domande
164+
165+
numero_risposta = i + 1
166+
167+
# Salviamo la risposta nel CSV
168+
salva_risposta(nome_utente, id_dom, numero_risposta, tempo_risposta)
169+
170+
# Controlliamo correttezza (forziamo a stringa)
171+
try:
172+
if str(numero_risposta) == str(domanda_corrente.get('corretta')):
173+
punteggio += 1
174+
except Exception:
175+
pass
176+
112177
prossima_domanda()
113178

179+
180+
def on_key_down(key):
181+
global nome_utente, entering_name, game_over
182+
183+
# Durante l'inserimento del nickname
184+
if entering_name:
185+
# BACKSPACE
186+
if key == keys.BACKSPACE:
187+
nome_utente = nome_utente[:-1]
188+
return
189+
# ENTER -> iniziare se nome non vuoto
190+
if key == keys.RETURN or key == keys.KP_ENTER:
191+
if nome_utente.strip() != "":
192+
start_game()
193+
return
194+
# SOLO caratteri stampabili (singolo carattere nel nome della key)
195+
try:
196+
ch = key.name
197+
except Exception:
198+
ch = None
199+
if ch and len(ch) == 1:
200+
nome_utente += ch
201+
return
202+
114203
def tick():
115204
global secondi_mancanti
116-
if not game_over:
205+
if not game_over and not entering_name:
117206
if secondi_mancanti > 0:
118207
secondi_mancanti -= 1
119208
else:
209+
# se finisce il tempo, salviamo una risposta vuota/timeout
210+
# id domanda
211+
id_dom = None
212+
if domanda_corrente is not None:
213+
id_dom = domanda_corrente.get('id_domanda') if 'id_domanda' in domanda_corrente else domanda_corrente.get('id')
214+
if id_dom is None:
215+
id_dom = indice_domande
216+
# numero_risposta 0 per timeout
217+
salva_risposta(nome_utente, id_dom, 0, TEMPO_DOMANDA)
120218
prossima_domanda()
121219

122-
# AVVIO
123-
carica_e_mischia()
124-
prossima_domanda()
125-
clock.schedule_interval(tick, 1.0)
126-
pgzrun.go()
220+
221+
# ───────────────── CONTROLLO START ─────────────────
222+
223+
def start_game():
224+
global entering_name, nome_utente
225+
entering_name = False
226+
# Carichiamo e avviamo
227+
carica_e_mischia()
228+
prossima_domanda()
229+
# Avviamo il tick (se non già avviato). È sicuro chiamarlo più volte su pgzero: evitiamo duplicati
230+
try:
231+
clock.schedule_interval(tick, 1.0)
232+
except Exception:
233+
pass
234+
235+
# AVVIO: non carichiamo automaticamente le domande, aspettiamo il nickname
236+
init_file_risposte()
237+
pgzrun.go()

0 commit comments

Comments
 (0)