Skip to content

Commit d6c487c

Browse files
committed
014 Tetris
1 parent 9ec2a53 commit d6c487c

File tree

4 files changed

+341
-1
lines changed

4 files changed

+341
-1
lines changed

013_Posegame.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ python game.py
161161
将代码保存为game.py,然后在控制台运行:
162162

163163
```
164-
python minesweeper.py
164+
python game.py
165165
```
166166

167167
![挑战13](images/013_posegame.png)

014_Tetris.md

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
# 14 Tetris
2+
3+
## Requirements
4+
5+
1. Run the code in console using command line.
6+
2. It'll open a Python window to play the Tetris game.
7+
8+
## What can we practice in this project?
9+
10+
- Turtle
11+
- Class/Object
12+
- 2D list
13+
14+
## A reference code
15+
16+
```python
17+
from turtle import *
18+
from random import randint, choice
19+
20+
SHAPES = [
21+
[[1, 1, 1, 1]],
22+
23+
[[1],
24+
[1],
25+
[1],
26+
[1]],
27+
28+
[[0, 0, 1],
29+
[1, 1, 1]],
30+
31+
[[1, 0, 0],
32+
[1, 1, 1]],
33+
34+
[[0, 1, 1],
35+
[1, 1, 0]],
36+
37+
[[1, 1, 0],
38+
[0, 1, 1]],
39+
40+
[[1, 1],
41+
[1, 1]],
42+
43+
[[0, 1, 0],
44+
[1, 1, 1]]
45+
]
46+
47+
48+
class Block():
49+
def __init__(self, grid):
50+
"""
51+
初始化
52+
:param grid: 游戏grid
53+
"""
54+
self.grid = grid
55+
self.color = randint(1, 7)
56+
self.shape = choice(SHAPES)
57+
self.i = 0
58+
self.j = 5
59+
self.width = len(self.shape[0])
60+
self.height = len(self.shape)
61+
62+
def fill(self):
63+
"""
64+
将方块数据填充到grid中
65+
"""
66+
for i in range(self.height):
67+
for j in range(self.width):
68+
if self.shape[i][j] == 1:
69+
self.grid[self.i + i][self.j + j] = self.color
70+
71+
def erase(self):
72+
"""
73+
从grid中擦除方块
74+
"""
75+
for i in range(self.height):
76+
for j in range(self.width):
77+
if self.shape[i][j] == 1:
78+
self.grid[self.i + i][self.j + j] = 0
79+
80+
def move_left(self):
81+
"""
82+
向左移动一格
83+
"""
84+
if self.j > 0:
85+
for row in range(self.height):
86+
for col in range(self.width):
87+
if self.shape[row][col] == 1:
88+
if self.grid[self.i + row][self.j + col - 1] != 0:
89+
return False
90+
break
91+
92+
self.erase()
93+
self.j -= 1
94+
self.fill()
95+
96+
def move_right(self):
97+
"""
98+
向右移动一格
99+
"""
100+
if self.j + self.width < len(self.grid[0]):
101+
for row in range(self.height):
102+
for col in range(self.width - 1, -1, -1):
103+
if self.shape[row][col] == 1:
104+
if self.grid[self.i + row][self.j + col + 1] != 0:
105+
return False
106+
break
107+
108+
self.erase()
109+
self.j += 1
110+
self.fill()
111+
112+
def move_down(self):
113+
"""
114+
快速下移
115+
"""
116+
i = self.i
117+
while self.check_down(i):
118+
i += 1
119+
self.erase()
120+
self.i = i
121+
self.fill()
122+
123+
def check_down(self, i):
124+
"""
125+
判断方块在i行时是否可以下落
126+
"""
127+
if i + self.height >= len(self.grid):
128+
return False
129+
for col in range(self.width):
130+
for row in range(self.height - 1, -1, -1):
131+
if self.shape[row][col] == 1:
132+
if self.grid[i + row + 1][self.j + col] != 0:
133+
return False
134+
break
135+
return True
136+
137+
def can_fall(self):
138+
"""
139+
判断方块是否可以下落
140+
"""
141+
return self.check_down(self.i)
142+
143+
def rotate(self):
144+
"""
145+
旋转
146+
"""
147+
rotated = []
148+
for j in range(len(self.shape[0])):
149+
new_row = []
150+
for i in range(len(self.shape) - 1, -1, -1):
151+
new_row.append(self.shape[i][j])
152+
rotated.append(new_row)
153+
154+
for i in range(len(rotated)):
155+
for j in range(len(rotated[0])):
156+
if rotated[i][j] == 1:
157+
# 如果旋转后,有任何位置超过边界,则不能旋转
158+
if self.i + i >= len(self.grid) or self.j + j >= len(self.grid[0]):
159+
return
160+
# 如果旋转后的位置有方块了,则不能旋转
161+
if self.grid[self.i + i][self.j + j] != 0 and (i not in range(len(self.shape)) or j not in range(
162+
len(self.shape[0]))):
163+
return
164+
self.erase()
165+
self.shape = rotated
166+
self.height = len(self.shape)
167+
self.width = len(self.shape[0])
168+
self.fill()
169+
170+
171+
gz = 32
172+
WIDTH = 12
173+
HEIGHT = 24
174+
COLORS = ("black", "red", "orange", "yellow", "green", "cyan", "blue", "purple")
175+
176+
grid = [[0 for col in range(WIDTH)] for row in range(HEIGHT)]
177+
178+
title("Tetris 俄罗斯方块")
179+
bgcolor("lightgreen")
180+
shapesize(1.5)
181+
tracer(False)
182+
speed(0)
183+
shape("square")
184+
up()
185+
186+
score = 0
187+
score_pen = Turtle()
188+
score_pen.ht()
189+
score_pen.up()
190+
score_pen.goto(0, HEIGHT / 2 * gz)
191+
score_pen.down()
192+
score_pen.write("分数:{}".format(score), font=("", 20, ""), align="center")
193+
194+
block_pen = Turtle()
195+
block_pen.speed(0)
196+
block_pen.shapesize(1.5)
197+
block_pen.shape("square")
198+
block_pen.up()
199+
block_pen.ht()
200+
201+
202+
def draw_next_block(block):
203+
block_pen.clear()
204+
block_pen.color(COLORS[block.color])
205+
for i in range(len(block.shape)):
206+
for j in range(len(block.shape[0])):
207+
if block.shape[i][j] == 1:
208+
block_pen.goto(WIDTH / 2 * gz + 50 + j * gz, HEIGHT / 2 * gz - 50 - i * gz)
209+
block_pen.stamp()
210+
211+
212+
def draw_grid():
213+
clear()
214+
for row in range(len(grid)):
215+
for col in range(len(grid[row])):
216+
goto(-WIDTH / 2 * gz + col * gz, HEIGHT / 2 * gz - row * gz - 20)
217+
color(COLORS[grid[row][col]])
218+
stamp()
219+
220+
221+
def check_grid():
222+
"""
223+
检查是否要消除满格的行
224+
"""
225+
global score
226+
for i in range(HEIGHT):
227+
is_full = True
228+
for j in range(WIDTH):
229+
if grid[i][j] == 0:
230+
is_full = False
231+
break
232+
if is_full:
233+
score += 10
234+
score_pen.clear()
235+
score_pen.write("分数:{}".format(score), font=("", 20, ""), align="center")
236+
grid.pop(i)
237+
grid.insert(0, [0 for x in range(WIDTH)])
238+
239+
240+
blocks = []
241+
block1 = Block(grid)
242+
block2 = Block(grid)
243+
blocks.append(block1)
244+
blocks.append(block2)
245+
draw_next_block(block2)
246+
247+
248+
def left():
249+
blocks[0].move_left()
250+
251+
252+
def right():
253+
blocks[0].move_right()
254+
255+
256+
def down():
257+
blocks[0].move_down()
258+
259+
260+
def rotate():
261+
blocks[0].rotate()
262+
263+
264+
onkey(left, "Left")
265+
onkey(right, "Right")
266+
onkey(rotate, "Up")
267+
onkey(down, "Down")
268+
listen()
269+
270+
271+
def run():
272+
b = blocks[0]
273+
if b.can_fall():
274+
b.erase()
275+
b.i += 1
276+
b.fill()
277+
else:
278+
if b.i == 0:
279+
b.fill()
280+
draw_grid()
281+
goto(0, 0)
282+
color("white")
283+
write("游戏结束", font=("", 50, ""), align="center")
284+
return
285+
check_grid()
286+
blocks.pop(0)
287+
block = Block(grid)
288+
blocks.append(block)
289+
draw_next_block(blocks[1])
290+
291+
draw_grid()
292+
update()
293+
ontimer(run, 400)
294+
295+
296+
run()
297+
done()
298+
299+
300+
```
301+
302+
## Run the demo
303+
304+
Please save the Python as game.py and run it in console:
305+
306+
```
307+
python game.py
308+
```
309+
310+
![挑战14](images/tetris.png)
311+
312+
----
313+
314+
# 俄罗斯方块
315+
316+
## 项目需求
317+
318+
- 直接在控制台使用命令行运行
319+
- 运行之后出现俄罗斯方块小游戏
320+
321+
## 项目练习
322+
323+
- Turtle
324+
- Class/Object
325+
- 2D list
326+
327+
## 项目参考代码
328+
329+
## 测试运行
330+
331+
将代码保存为game.py,然后在控制台运行:
332+
333+
```
334+
python game.py
335+
```
336+
337+
![挑战14](images/tetris.png)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/012_Mine
4545

4646
## 013 Pose game
4747
https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/013_Posegame.md
48+
49+
## 014 Tetris game
50+
https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/014_Tetris.md

images/tetris.png

91.7 KB
Loading

0 commit comments

Comments
 (0)