1+ import random
2+ import pgzrun
3+
4+ # --- Finestra ---
5+ WIDTH = 700
6+ HEIGHT = 500
7+ TITLE = "MEMO"
8+
9+ # --- Layout ---
10+ COLONNE = 6
11+ CARTA_W = 80
12+ CARTA_H = 110
13+ SPAZIO_X = 20
14+ SPAZIO_Y = 30
15+ MARGINE_X = (WIDTH - COLONNE * CARTA_W - (COLONNE - 1 ) * SPAZIO_X ) // 2
16+ MARGINE_Y = 110
17+
18+ # --- Colori delle 6 coppie ---
19+ COLORI = [
20+ (220 , 60 , 60 ), # rosso
21+ ( 60 , 160 , 220 ), # azzurro
22+ ( 60 , 200 , 100 ), # verde
23+ (230 , 180 , 40 ), # giallo
24+ (180 , 80 , 220 ), # viola
25+ (230 , 120 , 40 ), # arancione
26+ ]
27+
28+ # --- Palette UI ---
29+ SFONDO = (30 , 30 , 40 )
30+ CARTA_COPERTA = (60 , 65 , 90 )
31+ CARTA_BORDO = (90 , 95 , 130 )
32+ BIANCO = (255 , 255 , 255 )
33+ GRIGIO = (180 , 180 , 200 )
34+ TESTO_TITOLO = (200 , 210 , 255 )
35+ VERDE_OK = ( 80 , 220 , 130 )
36+ ROSSO_ERR = (220 , 80 , 80 )
37+
38+ DURATA_MOSTRA = 2 # secondi prima di nascondere le carte sbagliate (usato da clock.schedule)
39+
40+ # =============================================================
41+ # Struttura carta: lista [colore_idx, scoperta, trovata, x, y]
42+ # colore_idx : int – indice in COLORI
43+ # scoperta : bool – temporaneamente visibile
44+ # trovata : bool – coppia indovinata, resta visibile
45+ # x, y : int – angolo superiore sinistro della carta
46+ # =============================================================
47+
48+ def crea_carte ():
49+ indici = list (range (6 )) * 2
50+ random .shuffle (indici )
51+ carte = []
52+ for i , idx_col in enumerate (indici ):
53+ riga = i // COLONNE
54+ col = i % COLONNE
55+ x = MARGINE_X + col * (CARTA_W + SPAZIO_X )
56+ y = MARGINE_Y + riga * (CARTA_H + SPAZIO_Y )
57+ carte .append ([idx_col , False , False , x , y ])
58+ return carte
59+
60+
61+ # --- Stato globale ---
62+ carte = crea_carte ()
63+ errori = 0
64+ selezionate = [] # indici delle carte scelte nel turno corrente (max 2)
65+ attesa_hide = False
66+ partita_vinta = False
67+
68+ # =============================================================
69+ # Disegno
70+ # =============================================================
71+
72+ def draw ():
73+ screen .fill (SFONDO )
74+
75+ # Titolo
76+ screen .draw .text ("MEMO" , topleft = (28 , 16 ),
77+ fontsize = 42 , color = TESTO_TITOLO , bold = True )
78+
79+ # Contatore errori
80+ col_err = ROSSO_ERR if errori > 0 else GRIGIO
81+ screen .draw .text (f"Errori: { errori } " , topleft = (200 , 26 ),
82+ fontsize = 24 , color = col_err )
83+
84+ # Suggerimento tasto spazio (solo durante il gioco)
85+ if partita_vinta :
86+ screen .draw .text ("SPAZIO = nuova partita" , topright = (WIDTH - 20 , 26 ),
87+ fontsize = 18 , color = GRIGIO )
88+
89+ # Carte
90+ for carta in carte :
91+ disegna_carta (carta )
92+
93+ # Schermata di vittoria
94+ if partita_vinta :
95+ screen .draw .filled_rect (Rect (0 , 0 , WIDTH , HEIGHT ), (20 , 20 , 35 ))
96+ screen .draw .text ("Hai vinto!" ,
97+ center = (WIDTH // 2 , HEIGHT // 2 - 35 ),
98+ fontsize = 48 , color = VERDE_OK , bold = True )
99+ screen .draw .text (f"Completato con { errori } errori" ,
100+ center = (WIDTH // 2 , HEIGHT // 2 + 15 ),
101+ fontsize = 26 , color = BIANCO )
102+ screen .draw .text ("Premi SPAZIO per giocare ancora" ,
103+ center = (WIDTH // 2 , HEIGHT // 2 + 55 ),
104+ fontsize = 18 , color = GRIGIO )
105+
106+
107+ def disegna_carta (carta ):
108+ idx_col , scoperta , trovata , x , y = carta
109+ r = Rect (x , y , CARTA_W , CARTA_H )
110+
111+ if scoperta or trovata :
112+ colore = COLORI [idx_col ]
113+ screen .draw .filled_rect (r , colore )
114+ bordo = tuple (min (255 , c + 70 ) for c in colore )
115+ screen .draw .rect (r , bordo )
116+ if trovata :
117+ screen .draw .rect (r , VERDE_OK )
118+ else :
119+ screen .draw .filled_rect (r , CARTA_COPERTA )
120+ screen .draw .rect (r , CARTA_BORDO )
121+ # Puntini decorativi sul retro
122+ for dr in range (3 ):
123+ for dc in range (3 ):
124+ px = x + CARTA_W // 4 + dc * (CARTA_W // 4 )
125+ py = y + CARTA_H // 5 + dr * (CARTA_H // 4 )
126+ screen .draw .filled_circle ((px , py ), 3 , CARTA_BORDO )
127+
128+
129+ # =============================================================
130+ # Logica
131+ # =============================================================
132+
133+ def nascondi_carte ():
134+ """Chiamata da clock.schedule dopo DURATA_MOSTRA secondi."""
135+ global attesa_hide
136+ for idx in selezionate :
137+ carte [idx ][1 ] = False # nascondi la carta
138+ selezionate .clear ()
139+ attesa_hide = False
140+
141+
142+ def on_key_down (key ):
143+ global errori , attesa_hide , selezionate , partita_vinta , carte
144+
145+ if key == keys .SPACE and partita_vinta :
146+ clock .unschedule (nascondi_carte )
147+ carte = crea_carte ()
148+ errori = 0
149+ selezionate = []
150+ attesa_hide = False
151+ partita_vinta = False
152+
153+
154+ def on_mouse_down (pos ):
155+ global errori , attesa_hide , selezionate , partita_vinta , carte
156+
157+ mx , my = pos
158+
159+ # Ignora clic durante attesa o a partita vinta
160+ if attesa_hide or partita_vinta :
161+ return
162+
163+ idx = indice_carta_sotto (mx , my )
164+ if idx == - 1 :
165+ return
166+
167+ carta = carte [idx ]
168+ # Ignora carte già trovate, già scoperte o già selezionate
169+ if carta [2 ] or carta [1 ] or idx in selezionate :
170+ return
171+
172+ carta [1 ] = True # scopri la carta
173+ selezionate .append (idx )
174+
175+ if len (selezionate ) == 2 :
176+ idx_a , idx_b = selezionate
177+ if carte [idx_a ][0 ] == carte [idx_b ][0 ]:
178+ # Coppia corretta: segna come trovata
179+ carte [idx_a ][2 ] = True
180+ carte [idx_b ][2 ] = True
181+ selezionate = []
182+ if all (c [2 ] for c in carte ):
183+ partita_vinta = True
184+ else :
185+ # Coppia sbagliata: incrementa errori e programma il nascondimento
186+ errori += 1
187+ attesa_hide = True
188+ clock .schedule (nascondi_carte , DURATA_MOSTRA )
189+
190+
191+ def indice_carta_sotto (mx , my ):
192+ """Restituisce l'indice della carta sotto il cursore, -1 se nessuna."""
193+ for i , carta in enumerate (carte ):
194+ _ , _ , _ , x , y = carta
195+ if x <= mx <= x + CARTA_W and y <= my <= y + CARTA_H :
196+ return i
197+ return - 1
198+
199+ # Avvia il game loop di Pygame Zero
200+ pgzrun .go ()
0 commit comments