1# Tetris game for mPython
2# MIT license,Copyright (c) 2019 labplus@Tangliufeng
3
4from mpython import *
5import math
6import random, time
7
8class Brick():
9 def __init__(self, p_position):
10 self.position = p_position
11
12 def draw(self):
13
14 x = self.position[1] * brick_size
15 y = self.position[0] * brick_size
16 oled.fill_rect(brick_size * (field_height - 1) - x, y, brick_size, brick_size, 1)
17
18
19class Block():
20 def __init__(self, p_bricks_layout, p_direction):
21 self.bricks_layout = p_bricks_layout
22 self.direction = p_direction
23 self.init_position = (field_width // 2 - 2, 0)
24 self.cur_layout = self.bricks_layout[self.direction]
25 self.position = self.init_position
26 self.stopped = False
27 self.move_interval = 500
28 self.last_move = 0
29 self.bricks = []
30 for (x, y) in self.cur_layout:
31 self.bricks.append(Brick((self.position[0] + x, self.position[1] + y)))
32
33 def draw(self):
34 for brick in self.bricks:
35 brick.draw()
36
37 def isLegal(self, layout, position):
38 (x0, y0) = position
39 for (x, y) in layout:
40 if x + x0 < 0 or y + y0 < 0 or x + x0 >= field_width or y + y0 >= field_height:
41 return False
42 if field_map[y + y0][x + x0] != 0:
43 return False
44 return True
45
46 def left(self):
47 new_position = (self.position[0] - 1, self.position[1])
48 if self.isLegal(self.cur_layout, new_position):
49 self.position = new_position
50 self.refresh_bircks()
51
52 def right(self):
53 new_position = (self.position[0] + 1, self.position[1])
54 if self.isLegal(self.cur_layout, new_position):
55 self.position = new_position
56 self.refresh_bircks()
57
58 def down(self):
59 (x, y) = (self.position[0], self.position[1] + 1)
60 while self.isLegal(self.cur_layout, (x, y)):
61 self.position = (x, y)
62 self.refresh_bircks()
63 y += 1
64
65 def refresh_bircks(self):
66 for (brick, (x, y)) in zip(self.bricks, self.cur_layout):
67 brick.position = (self.position[0] + x, self.position[1] + y)
68
69 def stop(self):
70 global field_bricks
71 global score
72 self.stopped = True
73 ys = []
74 for brick in self.bricks:
75 field_bricks.append(brick)
76 (x, y) = brick.position
77 if y not in ys:
78 ys.append(y)
79 field_map[y][x] = 1
80
81 eliminate_count = 0
82 ys.sort()
83
84 for y in ys:
85 if 0 in field_map[y]:
86 continue
87 eliminate_count += 1
88 for fy in range(y, 0, -1):
89 field_map[fy] = field_map[fy - 1][:]
90 field_map[0] = [0 for i in range(field_width)]
91
92 tmp_field_bricks = []
93 for fb in field_bricks:
94 (fx, fy) = fb.position
95 if fy < y:
96 fb.position = (fx, fy + 1)
97 tmp_field_bricks.append(fb)
98 elif fy > y:
99 tmp_field_bricks.append(fb)
100 field_bricks = tmp_field_bricks
101 if eliminate_count == 1:
102 score += 1
103 elif eliminate_count == 2:
104 score += 2
105 elif eliminate_count == 3:
106 score += 4
107 elif eliminate_count == 4:
108 score += 6
109
110 def update(self, time):
111 self.draw()
112 if time - self.last_move >= self.move_interval:
113 new_position = (self.position[0], self.position[1] + 1)
114 if self.isLegal(self.cur_layout, new_position):
115 self.position = new_position
116 self.refresh_bircks()
117 self.last_move = time
118 else:
119 self.stop()
120
121 def rotate(self):
122 new_direction = (self.direction + 1) % len(self.bricks_layout)
123 new_layout = self.bricks_layout[new_direction]
124 if not self.isLegal(new_layout, self.position):
125 return
126 self.direction = new_direction
127 self.cur_layout = new_layout
128 for (brick, (x, y)) in zip(self.bricks, self.cur_layout):
129 brick.position = (self.position[0] + x, self.position[1] + y)
130 self.refresh_bircks()
131 self.draw()
132
133
134# 0: oooo
135# 1: oo
136# oo
137# 2: o
138# ooo
139# 3: o
140# oo
141# o
142# 4: o
143# oo
144# o
145# 5: ooo
146# o
147# 6: ooo
148# o
149bricks_layout_0 = (((0, 0), (0, 1), (0, 2), (0, 3)), ((0, 1), (1, 1), (2, 1), (3, 1)))
150bricks_layout_1 = (((1, 0), (2, 0), (1, 1), (2, 1)), )
151bricks_layout_2 = (
152 ((1, 0), (0, 1), (1, 1), (2, 1)),
153 ((0, 1), (1, 0), (1, 1), (1, 2)),
154 ((1, 2), (0, 1), (1, 1), (2, 1)),
155 ((2, 1), (1, 0), (1, 1), (1, 2)),
156)
157bricks_layout_3 = (
158 ((0, 1), (1, 1), (1, 0), (2, 0)),
159 ((0, 0), (0, 1), (1, 1), (1, 2)),
160)
161bricks_layout_4 = (
162 ((0, 0), (1, 0), (1, 1), (2, 1)),
163 ((1, 0), (1, 1), (0, 1), (0, 2)),
164)
165bricks_layout_5 = (
166 ((0, 0), (1, 0), (1, 1), (1, 2)),
167 ((0, 2), (0, 1), (1, 1), (2, 1)),
168 ((1, 0), (1, 1), (1, 2), (2, 2)),
169 ((2, 0), (2, 1), (1, 1), (0, 1)),
170)
171bricks_layout_6 = (
172 ((2, 0), (1, 0), (1, 1), (1, 2)),
173 ((0, 0), (0, 1), (1, 1), (2, 1)),
174 ((0, 2), (1, 2), (1, 1), (1, 0)),
175 ((2, 2), (2, 1), (1, 1), (0, 1)),
176)
177
178field_width, field_height = 16, 30
179brick_size = 4
180field_map = [[0 for i in range(field_width)] for i in range(field_height)]
181field_bricks = []
182score = 0
183running = True
184threshhold = 400
185
186
187def drawField():
188 for brick in field_bricks:
189 brick.draw()
190
191
192def getBlock():
193 block_type = random.randint(0, 6)
194 if block_type == 0:
195 return Block(bricks_layout_0, random.randint(0, len(bricks_layout_0) - 1))
196 elif block_type == 1:
197 return Block(bricks_layout_1, random.randint(0, len(bricks_layout_1) - 1))
198 elif block_type == 2:
199 return Block(bricks_layout_2, random.randint(0, len(bricks_layout_2) - 1))
200 elif block_type == 3:
201 return Block(bricks_layout_3, random.randint(0, len(bricks_layout_3) - 1))
202 elif block_type == 4:
203 return Block(bricks_layout_4, random.randint(0, len(bricks_layout_4) - 1))
204 elif block_type == 5:
205 return Block(bricks_layout_5, random.randint(0, len(bricks_layout_5) - 1))
206 elif block_type == 6:
207 return Block(bricks_layout_6, random.randint(0, len(bricks_layout_6) - 1))
208
209
210def run():
211 global running
212 btn_n_stat, btn_o_stat, btn_t_stat, btn_p_stat = [0] * 4
213
214 while running:
215
216 cur_block = getBlock()
217
218 if not cur_block.isLegal(cur_block.cur_layout, cur_block.position):
219 cur_block.draw()
220 running = False
221 continue
222
223 while not cur_block.stopped:
224
225 oled.fill(0)
226 ticks = time.ticks_ms()
227 cur_block.update(ticks)
228 drawField()
229 oled.show()
230
231 if touchPad_T.read() < threshhold and btn_t_stat == 0:
232 cur_block.rotate()
233 btn_t_stat = 1
234 elif touchPad_T.read() >= threshhold:
235 btn_t_stat = 0
236
237 if touchPad_P.read() < threshhold and btn_p_stat == 0:
238 cur_block.down()
239 btn_p_stat = 1
240 elif touchPad_P.read() >= threshhold:
241 btn_p_stat = 0
242
243 if touchPad_N.read() < threshhold and btn_n_stat == 0:
244 cur_block.left()
245 btn_n_stat = 1
246 elif touchPad_N.read() >= threshhold:
247 btn_n_stat = 0
248
249 if touchPad_O.read() < threshhold and btn_o_stat == 0:
250 cur_block.right()
251 btn_o_stat = 1
252 elif touchPad_O.read() >= threshhold:
253 btn_o_stat = 0
254 oled.fill(0)
255 oled.text('Game over!', 25, 20)
256 oled.text('Score:%d' % score, 25, 32)
257 oled.show()
258
259
260if __name__ == '__main__':
261 run()