22# Ecran SSD1327 128x128, 4-bit greyscale
33# Incliner gauche/droite pour déplacer, secouer pour tourner
44# Bouton A pour hard drop
5-
6- from machine import I2C , SPI , Pin
7- from time import ticks_ms , sleep_ms
5+
6+ import random
7+ from time import sleep_ms , ticks_ms
8+
89import ssd1327
910from ism330dl import ISM330DL
10- import random
11-
11+ from machine import I2C , SPI , Pin
12+
1213# === Ecran ===
1314spi = SPI (1 )
1415dc = Pin ("DATA_COMMAND_DISPLAY" )
1516res = Pin ("RST_DISPLAY" )
1617cs = Pin ("CS_DISPLAY" )
1718display = ssd1327 .WS_OLED_128X128_SPI (spi , dc , res , cs )
18-
19+
1920# === IMU ===
2021i2c = I2C (1 )
2122imu = ISM330DL (i2c )
22-
23+
2324# === Boutons ===
2425BTN_A = Pin ("A_BUTTON" , Pin .IN , Pin .PULL_UP )
2526BTN_B = Pin ("B_BUTTON" , Pin .IN , Pin .PULL_UP )
26-
27+
2728# === Parametres du jeu ===
2829COLS = 10
2930ROWS = 20
3334TILT_THRESH = 0.35 # seuil inclinaison (g)
3435SHAKE_THRESH = 1.8 # seuil secousse (g)
3536MOVE_DELAY = 180 # ms entre deux deplacements lateraux
36- SHAKE_COOLDOWN = 400 # ms entre deux rotations
37-
37+ SHAKE_COOLDOWN = 400 # ms entre deux rotations
38+
3839# === Couleurs (0-15) ===
3940COL_BG = 0
4041COL_GRID = 1
4142COL_BORDER = 8
4243COL_TEXT = 15
4344COL_GHOST = 3
44-
45+
4546# Couleurs des pieces (1-15)
4647PIECE_COLORS = [0 , 12 , 14 , 11 , 13 , 10 , 9 , 15 ]
47-
48+
4849# === Pieces Tetris (tetrominoes) ===
4950# Format : liste de rotations, chaque rotation = liste de (row, col)
5051PIECES = [
5152 # I
52- [[(0 ,0 ),(0 ,1 ),(0 ,2 ),(0 ,3 )],
53- [(0 ,0 ),(1 ,0 ),(2 ,0 ),(3 ,0 )]],
53+ [[(0 , 0 ), (0 , 1 ), (0 , 2 ), (0 , 3 )],
54+ [(0 , 0 ), (1 , 0 ), (2 , 0 ), (3 , 0 )]],
5455 # O
55- [[(0 ,0 ),(0 ,1 ),(1 ,0 ),(1 ,1 )]],
56+ [[(0 , 0 ), (0 , 1 ), (1 , 0 ), (1 , 1 )]],
5657 # T
57- [[(0 ,1 ),(1 ,0 ),(1 ,1 ),(1 ,2 )],
58- [(0 ,0 ),(1 ,0 ),(2 ,0 ),(1 ,1 )], # corrigé
59- [(1 ,0 ),(1 ,1 ),(1 ,2 ),(0 ,1 )],
60- [(0 ,1 ),(1 ,1 ),(2 ,1 ),(1 ,0 )]],
58+ [[(0 , 1 ), (1 , 0 ), (1 , 1 ), (1 , 2 )],
59+ [(0 , 0 ), (1 , 0 ), (2 , 0 ), (1 , 1 )], # corrigé
60+ [(1 , 0 ), (1 , 1 ), (1 , 2 ), (0 , 1 )],
61+ [(0 , 1 ), (1 , 1 ), (2 , 1 ), (1 , 0 )]],
6162 # S
62- [[(0 ,1 ),(0 ,2 ),(1 ,0 ),(1 ,1 )],
63- [(0 ,0 ),(1 ,0 ),(1 ,1 ),(2 ,1 )]],
63+ [[(0 , 1 ), (0 , 2 ), (1 , 0 ), (1 , 1 )],
64+ [(0 , 0 ), (1 , 0 ), (1 , 1 ), (2 , 1 )]],
6465 # Z
65- [[(0 ,0 ),(0 ,1 ),(1 ,1 ),(1 ,2 )],
66- [(0 ,1 ),(1 ,0 ),(1 ,1 ),(2 ,0 )]],
66+ [[(0 , 0 ), (0 , 1 ), (1 , 1 ), (1 , 2 )],
67+ [(0 , 1 ), (1 , 0 ), (1 , 1 ), (2 , 0 )]],
6768 # J
68- [[(0 ,0 ),(1 ,0 ),(1 ,1 ),(1 ,2 )],
69- [(0 ,0 ),(0 ,1 ),(1 ,0 ),(2 ,0 )],
70- [(1 ,0 ),(1 ,1 ),(1 ,2 ),(0 ,2 )],
71- [(0 ,1 ),(1 ,1 ),(2 ,0 ),(2 ,1 )]],
69+ [[(0 , 0 ), (1 , 0 ), (1 , 1 ), (1 , 2 )],
70+ [(0 , 0 ), (0 , 1 ), (1 , 0 ), (2 , 0 )],
71+ [(1 , 0 ), (1 , 1 ), (1 , 2 ), (0 , 2 )],
72+ [(0 , 1 ), (1 , 1 ), (2 , 0 ), (2 , 1 )]],
7273 # L
73- [[(0 ,2 ),(1 ,0 ),(1 ,1 ),(1 ,2 )],
74- [(0 ,0 ),(1 ,0 ),(2 ,0 ),(2 ,1 )],
75- [(1 ,0 ),(1 ,1 ),(1 ,2 ),(0 ,0 )],
76- [(0 ,0 ),(0 ,1 ),(1 ,1 ),(2 ,1 )]],
74+ [[(0 , 2 ), (1 , 0 ), (1 , 1 ), (1 , 2 )],
75+ [(0 , 0 ), (1 , 0 ), (2 , 0 ), (2 , 1 )],
76+ [(1 , 0 ), (1 , 1 ), (1 , 2 ), (0 , 0 )],
77+ [(0 , 0 ), (0 , 1 ), (1 , 1 ), (2 , 1 )]],
7778]
78-
79+
7980# === Etat du jeu ===
8081grid = [[0 ] * COLS for _ in range (ROWS )]
8182score = 0
8283level = 1
8384lines_cleared = 0
8485game_over = False
85-
86+
8687piece_type = 0
8788piece_rot = 0
8889piece_row = 0
8990piece_col = 0
9091next_type = 0
91-
92+
9293last_fall = 0
9394last_move = 0
9495last_shake = 0
9596fall_interval = 600
96-
97+
98+
9799def new_piece ():
98100 global piece_type , piece_rot , piece_row , piece_col , next_type , game_over
99101 piece_type = next_type
@@ -103,109 +105,118 @@ def new_piece():
103105 piece_col = COLS // 2 - 2
104106 if not valid_pos (piece_row , piece_col , piece_rot ):
105107 game_over = True
106-
108+
109+
107110def get_cells (row , col , rot , ptype = None ):
108111 if ptype is None :
109112 ptype = piece_type
110113 return [(row + r , col + c ) for r , c in PIECES [ptype ][rot % len (PIECES [ptype ])]]
111-
114+
115+
112116def valid_pos (row , col , rot , ptype = None ):
113117 for r , c in get_cells (row , col , rot , ptype ):
114118 if r < 0 or r >= ROWS or c < 0 or c >= COLS :
115119 return False
116120 if grid [r ][c ]:
117121 return False
118122 return True
119-
123+
124+
120125def lock_piece ():
121126 global score , lines_cleared , level , fall_interval
122127 color = PIECE_COLORS [piece_type + 1 ]
123128 for r , c in get_cells (piece_row , piece_col , piece_rot ):
124129 if 0 <= r < ROWS and 0 <= c < COLS :
125130 grid [r ][c ] = color
126-
131+
127132 # Effacer les lignes completes
128133 full = [r for r in range (ROWS ) if all (grid [r ])]
129134 for r in full :
130135 del grid [r ]
131136 grid .insert (0 , [0 ] * COLS )
132-
137+
133138 n = len (full )
134139 lines_cleared += n
135140 score += [0 , 100 , 300 , 500 , 800 ][n ] * level
136141 level = lines_cleared // 10 + 1
137142 fall_interval = max (100 , 600 - (level - 1 ) * 50 )
138-
143+
144+
139145def ghost_row ():
140146 r = piece_row
141147 while valid_pos (r + 1 , piece_col , piece_rot ):
142148 r += 1
143149 return r
144-
150+
151+
145152def draw_cell (row , col , color ):
146153 x = GRID_X + col * CELL
147154 y = GRID_Y + row * CELL
148155 for dy in range (CELL - 1 ):
149156 for dx in range (CELL - 1 ):
150157 display .pixel (x + dx , y + dy , color )
151-
158+
159+
152160def draw_hline (x , y , w , color ):
153161 for i in range (w ):
154162 display .pixel (x + i , y , color )
155-
163+
164+
156165def draw_vline (x , y , h , color ):
157166 for i in range (h ):
158167 display .pixel (x , y + i , color )
159-
168+
169+
160170def draw_rect_outline (x , y , w , h , color ):
161171 draw_hline (x , y , w , color )
162172 draw_hline (x , y + h , w , color )
163173 draw_vline (x , y , h , color )
164174 draw_vline (x + w , y , h , color )
165-
175+
176+
166177def draw_screen ():
167178 display .fill (COL_BG )
168-
179+
169180 # Bordure grille
170181 draw_rect_outline (GRID_X - 1 , GRID_Y - 1 ,
171182 COLS * CELL + 1 , ROWS * CELL + 1 , COL_BORDER )
172-
183+
173184 # Grille de fond
174185 for r in range (ROWS ):
175186 for c in range (COLS ):
176187 if grid [r ][c ]:
177188 draw_cell (r , c , grid [r ][c ])
178-
189+
179190 # Ghost piece
180191 gr = ghost_row ()
181192 if gr != piece_row :
182193 for r , c in get_cells (gr , piece_col , piece_rot ):
183194 if 0 <= r < ROWS and 0 <= c < COLS :
184195 draw_cell (r , c , COL_GHOST )
185-
196+
186197 # Piece courante
187198 color = PIECE_COLORS [piece_type + 1 ]
188199 for r , c in get_cells (piece_row , piece_col , piece_rot ):
189200 if 0 <= r < ROWS and 0 <= c < COLS :
190201 draw_cell (r , c , color )
191-
202+
192203 # === Panneau droite ===
193204 px = GRID_X + COLS * CELL + 4
194205 py = GRID_Y
195-
206+
196207 # Score
197208 display .text ("SCR" , px , py , COL_TEXT )
198209 s = str (score )
199210 display .text (s [:5 ], px , py + 10 , 14 )
200-
211+
201212 # Level
202213 display .text ("LVL" , px , py + 25 , COL_TEXT )
203214 display .text (str (level ), px , py + 35 , 14 )
204-
215+
205216 # Lines
206217 display .text ("LNS" , px , py + 50 , COL_TEXT )
207218 display .text (str (lines_cleared ), px , py + 60 , 14 )
208-
219+
209220 # Next piece
210221 display .text ("NXT" , px , py + 75 , COL_TEXT )
211222 ncells = get_cells (0 , 0 , 0 , next_type )
@@ -215,17 +226,19 @@ def draw_screen():
215226 for dy in range (CELL - 2 ):
216227 for dx in range (CELL - 2 ):
217228 display .pixel (nx + dx , ny + dy , PIECE_COLORS [next_type + 1 ])
218-
229+
219230 display .show ()
220-
231+
232+
221233def draw_game_over ():
222234 display .fill (0 )
223235 display .text ("GAME" , 35 , 45 , 15 )
224236 display .text ("OVER" , 35 , 57 , 15 )
225237 display .text (f"SCR:{ score } " , 20 , 75 , 10 )
226238 display .text ("B=restart" , 15 , 95 , 7 )
227239 display .show ()
228-
240+
241+
229242def draw_start ():
230243 display .fill (0 )
231244 display .text ("TETRIS" , 28 , 30 , 15 )
@@ -234,7 +247,8 @@ def draw_start():
234247 display .text ("A=drop" , 25 , 79 , 10 )
235248 display .text ("A to start" , 14 , 100 , 7 )
236249 display .show ()
237-
250+
251+
238252def reset_game ():
239253 global grid , score , level , lines_cleared , game_over
240254 global last_fall , last_move , last_shake , fall_interval , next_type
@@ -249,39 +263,40 @@ def reset_game():
249263 last_fall = ticks_ms ()
250264 last_move = ticks_ms ()
251265 last_shake = ticks_ms ()
252-
266+
267+
253268# === Ecran de démarrage ===
254269draw_start ()
255270while BTN_A .value () == 1 :
256271 sleep_ms (50 )
257272sleep_ms (200 )
258-
273+
259274# === Init jeu ===
260275reset_game ()
261-
276+
262277# === Boucle principale ===
263278while True :
264279 now = ticks_ms ()
265-
280+
266281 if game_over :
267282 draw_game_over ()
268283 while BTN_B .value () == 1 :
269284 sleep_ms (50 )
270285 sleep_ms (200 )
271286 reset_game ()
272287 continue
273-
288+
274289 # Lecture IMU
275290 ax , ay , az = imu .acceleration_g ()
276-
291+
277292 # Secousse → rotation
278293 magnitude = (ax * ax + ay * ay + az * az ) ** 0.5
279294 if magnitude > SHAKE_THRESH and (now - last_shake ) > SHAKE_COOLDOWN :
280295 new_rot = (piece_rot + 1 ) % len (PIECES [piece_type ])
281296 if valid_pos (piece_row , piece_col , new_rot ):
282297 piece_rot = new_rot
283298 last_shake = now
284-
299+
285300 # Inclinaison → deplacement lateral
286301 if (now - last_move ) > MOVE_DELAY :
287302 if ay > TILT_THRESH :
@@ -292,7 +307,7 @@ def reset_game():
292307 if valid_pos (piece_row , piece_col - 1 , piece_rot ):
293308 piece_col -= 1
294309 last_move = now
295-
310+
296311 # Bouton A → hard drop
297312 if BTN_A .value () == 0 :
298313 while valid_pos (piece_row + 1 , piece_col , piece_rot ):
@@ -301,15 +316,15 @@ def reset_game():
301316 new_piece ()
302317 last_fall = now
303318 sleep_ms (150 )
304-
319+
305320 # Bouton B → rotation douce
306321 if BTN_B .value () == 0 and (now - last_shake ) > SHAKE_COOLDOWN :
307322 new_rot = (piece_rot + 1 ) % len (PIECES [piece_type ])
308323 if valid_pos (piece_row , piece_col , new_rot ):
309324 piece_rot = new_rot
310325 last_shake = now
311326 sleep_ms (150 )
312-
327+
313328 # Chute automatique
314329 if (now - last_fall ) > fall_interval :
315330 if valid_pos (piece_row + 1 , piece_col , piece_rot ):
@@ -318,7 +333,6 @@ def reset_game():
318333 lock_piece ()
319334 new_piece ()
320335 last_fall = now
321-
336+
322337 draw_screen ()
323338 sleep_ms (30 )
324-
0 commit comments