11import pgzrun
22import polars as pl
3+ import csv
34import os
45from pgzero .keyboard import keys
56
67# ───────────────── CONFIG ─────────────────
7- TITLE = "Cyber Quiz Polars Edition "
8+ TITLE = "Cyber Quiz"
89WIDTH = 900
910HEIGHT = 600
1011TEMPO_DOMANDA = 15
2021TEXT_MAIN = (255 , 255 , 255 )
2122
2223# ───────────────── STATO ─────────────────
23- lista_domande = [] # Qui finira il nostro mazzo rimescolato
24+ lista_domande = [] # Qui finirà il nostro mazzo rimescolato
2425domanda_corrente = None
2526indice_domande = 0
2627contatore_totale = 0
3536
3637# Box
3738question_box = Rect (50 , 90 , 800 , 150 )
38- answer_boxes = [Rect (50 , 300 , 380 , 110 ), Rect (470 , 300 , 380 , 110 ),
39- Rect (50 , 430 , 380 , 110 ), Rect (470 , 430 , 380 , 110 )]
39+ answer_boxes = [
40+ Rect (50 , 300 , 380 , 110 ),
41+ Rect (470 , 300 , 380 , 110 ),
42+ Rect (50 , 430 , 380 , 110 ),
43+ Rect (470 , 430 , 380 , 110 ),
44+ ]
4045timer_bar_box = Rect (50 , 260 , 800 , 12 )
4146
47+
4248# ───────────────── LOGICA DATI CON POLARS ─────────────────
4349def carica_e_mischia ():
4450 global lista_domande , contatore_totale
@@ -71,31 +77,36 @@ def prossima_domanda():
7177
7278# ───────────────── SALVATAGGIO RISPOSTE ─────────────────
7379def init_file_risposte ():
74- """Crea il file risposte con header se non esiste."""
80+ """Crea il file risposte con header se non esiste (usando csv) ."""
7581 if not os .path .exists (NOME_FILE_RISPOSTE ):
76- df = pl .DataFrame ({
77- "nome_utente" : pl .Series ([], dtype = pl .Utf8 ),
78- "id_domanda" : pl .Series ([], dtype = pl .Int64 ),
79- "numero_risposta_fornita" : pl .Series ([], dtype = pl .Int64 ),
80- "tempo_risposta" : pl .Series ([], dtype = pl .Int64 ),
81- })
82- df .write_csv (NOME_FILE_RISPOSTE )
83-
84-
85- def salva_risposta (nome , id_dom , numero_risposta , tempo_risposta ):
82+ with open (NOME_FILE_RISPOSTE , mode = "w" , newline = "" , encoding = "utf-8" ) as f :
83+ writer = csv .writer (f )
84+ writer .writerow (
85+ [
86+ "nome_utente" ,
87+ "id_domanda" ,
88+ "numero_risposta_fornita" ,
89+ "tempo_risposta" ,
90+ ]
91+ )
92+
93+
94+ def salva_risposta (nome , id_domanda , numero_risposta , tempo_risposta ):
95+ """Append della risposta al CSV (una riga). id_domanda può essere None -> scriviamo vuoto."""
8696 init_file_risposte ()
8797
88- nuova_riga = pl .DataFrame ({
89- "nome_utente" : [str (nome )],
90- "id_domanda" : [int (id_dom )],
91- "numero_risposta_fornita" : [int (numero_risposta )],
92- "tempo_risposta" : [int (tempo_risposta )],
93- })
98+ # Normalizziamo i valori per sicurezza
99+ nome_s = str (nome ) if nome is not None else ""
100+ id_s = "" if id_domanda is None else str (id_domanda )
101+ num_s = str (int (numero_risposta )) if numero_risposta is not None else ""
102+ tempo_s = str (int (tempo_risposta )) if tempo_risposta is not None else ""
94103
95- # Append leggendo + concatenando (approccio semplice e robusto)
96- df_esistente = pl .read_csv (NOME_FILE_RISPOSTE )
97- df_finale = pl .concat ([df_esistente , nuova_riga ])
98- df_finale .write_csv (NOME_FILE_RISPOSTE )([nome , id_dom , numero_risposta , tempo_risposta ])
104+ try :
105+ with open (NOME_FILE_RISPOSTE , mode = "a" , newline = "" , encoding = "utf-8" ) as f :
106+ writer = csv .writer (f )
107+ writer .writerow ([nome_s , id_s , num_s , tempo_s ])
108+ except Exception as e :
109+ print (f"Errore salvataggio risposta: { e } " )
99110
100111
101112# ───────────────── DISEGNO ─────────────────
@@ -109,37 +120,76 @@ def draw():
109120
110121 # Se siamo nella fase di inserimento nickname
111122 if entering_name :
112- screen .draw .text ("Benvenuto a Cyber Quiz!" , center = (WIDTH // 2 , 120 ), fontsize = 48 , color = COLOR_ACCENT )
113- screen .draw .text ("Inserisci il tuo nickname e premi ENTER per iniziare:" , center = (WIDTH // 2 , 180 ), fontsize = 28 , color = TEXT_MAIN )
123+ screen .draw .text (
124+ "Benvenuto a Cyber Quiz!" ,
125+ center = (WIDTH // 2 , 120 ),
126+ fontsize = 48 ,
127+ color = COLOR_ACCENT ,
128+ )
129+ screen .draw .text (
130+ "Inserisci il tuo nickname e premi ENTER per iniziare:" ,
131+ center = (WIDTH // 2 , 180 ),
132+ fontsize = 28 ,
133+ color = TEXT_MAIN ,
134+ )
114135
115136 # box input
116137 input_box = Rect (WIDTH // 2 - 300 , 230 , 600 , 60 )
117138 draw_styled_rect (input_box , COLOR_CARD )
118139 display_name = nome_utente if nome_utente != "" else "(digita qui...)"
119- screen .draw .text (display_name , center = input_box .center , fontsize = 36 , color = TEXT_MAIN )
140+ screen .draw .text (
141+ display_name , center = input_box .center , fontsize = 36 , color = TEXT_MAIN
142+ )
120143 return
121144
122145 if game_over :
123- screen .draw .text (f"SESSIONE FINITA\n Punteggio: { punteggio } /{ contatore_totale } " ,
124- center = (WIDTH // 2 , HEIGHT // 2 ), fontsize = 50 , color = COLOR_ACCENT )
146+ screen .draw .text (
147+ f"SESSIONE FINITA\n Punteggio: { punteggio } /{ contatore_totale } " ,
148+ center = (WIDTH // 2 , HEIGHT // 2 ),
149+ fontsize = 50 ,
150+ color = COLOR_ACCENT ,
151+ )
125152 return
126153
127154 # Info
128- screen .draw .text (f"GIOCATORE: { nome_utente } " , (50 , 20 ), color = COLOR_ACCENT , fontsize = 22 )
129- screen .draw .text (f"DOMANDA { indice_domande } /{ contatore_totale } " , (50 , 50 ), color = COLOR_ACCENT , fontsize = 22 )
130- screen .draw .text (f"PUNTI: { punteggio } " , (WIDTH - 150 , 20 ), color = TEXT_MAIN , fontsize = 25 )
155+ screen .draw .text (
156+ f"GIOCATORE: { nome_utente } " , (50 , 20 ), color = COLOR_ACCENT , fontsize = 22
157+ )
158+ screen .draw .text (
159+ f"DOMANDA { indice_domande } /{ contatore_totale } " ,
160+ (50 , 50 ),
161+ color = COLOR_ACCENT ,
162+ fontsize = 22 ,
163+ )
164+ screen .draw .text (
165+ f"PUNTI: { punteggio } " , (WIDTH - 150 , 20 ), color = TEXT_MAIN , fontsize = 25
166+ )
131167
132168 # Box Domanda
133169 draw_styled_rect (question_box , COLOR_CARD )
134170 if domanda_corrente :
135- screen .draw .textbox (str (domanda_corrente .get ('domanda' , '' )) , question_box .inflate (- 40 , - 40 ), color = TEXT_MAIN )
171+ screen .draw .textbox (
172+ str (domanda_corrente .get ("domanda" , "" )),
173+ question_box .inflate (- 40 , - 40 ),
174+ color = TEXT_MAIN ,
175+ )
136176 else :
137- screen .draw .textbox ("Caricamento..." , question_box .inflate (- 40 , - 40 ), color = TEXT_MAIN )
177+ screen .draw .textbox (
178+ "Caricamento..." , question_box .inflate (- 40 , - 40 ), color = TEXT_MAIN
179+ )
138180
139181 # Timer Progressivo
140182 percent = secondi_mancanti / TEMPO_DOMANDA if TEMPO_DOMANDA > 0 else 0
141183 screen .draw .filled_rect (timer_bar_box , COLOR_SHADOW )
142- 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 )
184+ screen .draw .filled_rect (
185+ Rect (
186+ timer_bar_box .x ,
187+ timer_bar_box .y ,
188+ int (timer_bar_box .w * percent ),
189+ timer_bar_box .h ,
190+ ),
191+ COLOR_ACCENT ,
192+ )
143193
144194 # Risposte
145195 for i in range (4 ):
@@ -148,7 +198,11 @@ def draw():
148198 is_hover = box .collidepoint (mouse_pos )
149199 draw_styled_rect (box , (60 , 60 , 90 ) if is_hover else COLOR_CARD )
150200 if domanda_corrente :
151- screen .draw .textbox (str (domanda_corrente .get (chiave , '' )), box .inflate (- 20 , - 20 ), color = TEXT_MAIN )
201+ screen .draw .textbox (
202+ str (domanda_corrente .get (chiave , "" )),
203+ box .inflate (- 20 , - 20 ),
204+ color = TEXT_MAIN ,
205+ )
152206
153207
154208# ───────────────── INPUT & TIMER ─────────────────
@@ -169,20 +223,25 @@ def on_mouse_down(pos):
169223 # tempo di risposta = tempo passato dalla visualizzazione (tempo iniziale - secondi_mancanti)
170224 tempo_risposta = TEMPO_DOMANDA - secondi_mancanti
171225 # Troviamo un id per la domanda: preferiamo campi 'id_domanda' o 'id', altrimenti usiamo l'indice attuale
172- id_dom = None
226+ id_domanda = None
173227 if domanda_corrente is not None :
174- id_dom = domanda_corrente .get ('id_domanda' ) if 'id_domanda' in domanda_corrente else domanda_corrente .get ('id' )
175- if id_dom is None :
176- id_dom = indice_domande
228+ # se è salvato come stringa nel CSV, manteniamo la stringa (salveremo come testo)
229+ id_domanda = (
230+ domanda_corrente .get ("id_domanda" )
231+ if "id_domanda" in domanda_corrente
232+ else domanda_corrente .get ("id" )
233+ )
234+ if id_domanda is None :
235+ id_domanda = indice_domande
177236
178237 numero_risposta = i + 1
179238
180239 # Salviamo la risposta nel CSV
181- salva_risposta (nome_utente , id_dom , numero_risposta , tempo_risposta )
240+ salva_risposta (nome_utente , id_domanda , numero_risposta , tempo_risposta )
182241
183242 # Controlliamo correttezza (forziamo a stringa)
184243 try :
185- if str (numero_risposta ) == str (domanda_corrente .get (' corretta' )):
244+ if str (numero_risposta ) == str (domanda_corrente .get (" corretta" )):
186245 punteggio += 1
187246 except Exception :
188247 pass
@@ -221,19 +280,23 @@ def tick():
221280 secondi_mancanti -= 1
222281 else :
223282 # se finisce il tempo, salviamo una risposta vuota/timeout
224- # id domanda
225- id_dom = None
283+ id_domanda = None
226284 if domanda_corrente is not None :
227- id_dom = domanda_corrente .get ('id_domanda' ) if 'id_domanda' in domanda_corrente else domanda_corrente .get ('id' )
228- if id_dom is None :
229- id_dom = indice_domande
285+ id_domanda = (
286+ domanda_corrente .get ("id_domanda" )
287+ if "id_domanda" in domanda_corrente
288+ else domanda_corrente .get ("id" )
289+ )
290+ if id_domanda is None :
291+ id_domanda = indice_domande
230292 # numero_risposta 0 per timeout
231- salva_risposta (nome_utente , id_dom , 0 , TEMPO_DOMANDA )
293+ salva_risposta (nome_utente , id_domanda , 0 , TEMPO_DOMANDA )
232294 prossima_domanda ()
233295
234296
235297# ───────────────── CONTROLLO START / RESTART ─────────────────
236298
299+
237300def start_game ():
238301 global entering_name , nome_utente
239302 entering_name = False
@@ -246,6 +309,7 @@ def start_game():
246309 except Exception :
247310 pass
248311
312+
249313# AVVIO: non carichiamo automaticamente le domande, aspettiamo il nickname
250314init_file_risposte ()
251315pgzrun .go ()
0 commit comments