11.2. 俄罗斯方块



完整代码
  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()