1+ import pgzrun
2+ import polars as pl
3+ import random
4+
5+ # ───────────────── CONFIG ─────────────────
6+ TITLE = "Cyber Quiz Polars Edition"
7+ WIDTH = 900
8+ HEIGHT = 600
9+ TEMPO_DOMANDA = 15
10+ NOME_FILE_CSV = "domande.csv"
11+
12+ # ───────────────── COLORI ─────────────────
13+ COLOR_BG = (10 , 10 , 25 )
14+ COLOR_CARD = (30 , 30 , 50 )
15+ COLOR_ACCENT = (0 , 255 , 200 )
16+ COLOR_DANGER = (255 , 45 , 85 )
17+ COLOR_SHADOW = (5 , 5 , 15 )
18+ TEXT_MAIN = (255 , 255 , 255 )
19+
20+ # ───────────────── STATO ─────────────────
21+ lista_domande = [] # Qui finira il nostro mazzo rimescolato
22+ domanda_corrente = None
23+ indice_domande = 0
24+ contatore_totale = 0
25+ punteggio = 0
26+ secondi_mancanti = TEMPO_DOMANDA
27+ game_over = False
28+ mouse_pos = (0 , 0 )
29+
30+ # Box
31+ question_box = Rect (50 , 90 , 800 , 150 )
32+ answer_boxes = [Rect (50 , 300 , 380 , 110 ), Rect (470 , 300 , 380 , 110 ),
33+ Rect (50 , 430 , 380 , 110 ), Rect (470 , 430 , 380 , 110 )]
34+ timer_bar_box = Rect (50 , 260 , 800 , 12 )
35+
36+ # ───────────────── LOGICA DATI CON POLARS ─────────────────
37+ def carica_e_mischia ():
38+ global lista_domande , contatore_totale
39+ try :
40+ # Leggiamo il CSV con Polars
41+ 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
45+ df_shuffled = df .sample (fraction = 1.0 , shuffle = True )
46+
47+ # Convertiamo in una lista di dizionari per facilitare l'estrazione nel gioco
48+ lista_domande = df_shuffled .to_dicts ()
49+ contatore_totale = len (lista_domande )
50+
51+ except Exception as e :
52+ print (f"Errore nel caricamento dati: { e } " )
53+
54+ def prossima_domanda ():
55+ global domanda_corrente , indice_domande , secondi_mancanti , game_over
56+
57+ if len (lista_domande ) > 0 :
58+ indice_domande += 1
59+ # .pop(0) prende la prima domanda e la RIMUOVE dalla lista -> Mai ripetizioni
60+ domanda_corrente = lista_domande .pop (0 )
61+ secondi_mancanti = TEMPO_DOMANDA
62+ else :
63+ game_over = True
64+
65+ # ───────────────── DISEGNO ─────────────────
66+ def draw_styled_rect (rect , color ):
67+ screen .draw .filled_rect (Rect (rect .x + 4 , rect .y + 4 , rect .w , rect .h ), COLOR_SHADOW )
68+ screen .draw .filled_rect (rect , color )
69+
70+ def draw ():
71+ screen .fill (COLOR_BG )
72+ if game_over :
73+ screen .draw .text (f"SESSIONE FINITA\n Punteggio: { punteggio } /{ contatore_totale } " ,
74+ center = (WIDTH // 2 , HEIGHT // 2 ), fontsize = 50 , color = COLOR_ACCENT )
75+ return
76+
77+ # 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 )
80+
81+ # Box Domanda
82+ draw_styled_rect (question_box , COLOR_CARD )
83+ screen .draw .textbox (domanda_corrente ['domanda' ], question_box .inflate (- 40 ,- 40 ), color = TEXT_MAIN )
84+
85+ # Timer Progressivo
86+ percent = secondi_mancanti / TEMPO_DOMANDA
87+ screen .draw .filled_rect (timer_bar_box , COLOR_SHADOW )
88+ 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 )
89+
90+ # Risposte
91+ for i in range (4 ):
92+ box = answer_boxes [i ]
93+ chiave = f"risposta{ i + 1 } "
94+ is_hover = box .collidepoint (mouse_pos )
95+ 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 )
97+
98+ # ───────────────── INPUT & TIMER ─────────────────
99+ def on_mouse_move (pos ):
100+ global mouse_pos
101+ mouse_pos = pos
102+
103+ def on_mouse_down (pos ):
104+ global punteggio
105+ if game_over : return
106+
107+ for i , box in enumerate (answer_boxes ):
108+ 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
112+ prossima_domanda ()
113+
114+ def tick ():
115+ global secondi_mancanti
116+ if not game_over :
117+ if secondi_mancanti > 0 :
118+ secondi_mancanti -= 1
119+ else :
120+ prossima_domanda ()
121+
122+ # AVVIO
123+ carica_e_mischia ()
124+ prossima_domanda ()
125+ clock .schedule_interval (tick , 1.0 )
126+ pgzrun .go ()
0 commit comments