-
Notifications
You must be signed in to change notification settings - Fork 0
/
tetris.py
204 lines (172 loc) · 6.1 KB
/
tetris.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import graphic
import utime
from tetromino import Tetromino, tetrominos
import control
from music import Musics
class Score:
def __init__(self):
self.score = 0
self.rows = 0
def add_score(self, level, rows):
self.rows += rows
if rows == 1:
self.score += 40 * (level + 1)
elif rows == 2:
self.score += 100 * (level + 1)
elif rows == 3:
self.score += 300 * (level + 1)
elif rows == 4:
self.score += 1200 * (level + 1)
class Game:
game_map: list[list] = None
tetromino: Tetromino = None
controller: control.Controller
score: Score
game_over: bool
pause: bool
move_down_event: control.DelayEvent
musics: Musics
def __init__(self, display):
self.rows = 30
self.cols = 10
self.wall_width = 1
self.bottom_wall_width = 2
self.display = display
self.speed = 100
self.level = self.speed//100
self.update_map = self.iter_tetromino_area(self.update_map)
self.collide_detect = self.iter_tetromino_area(self.collide_detect)
self.get_full_map = self.iter_tetromino_area(self.get_full_map)
self.move_down_event = control.DelayEvent(self.speed*3, self.move_down)
def iter_tetromino_area(self, action):
def func(game_map):
x = self.tetromino.length
k = x
pos_x = self.tetromino.pos_x
pos_y = self.tetromino.pos_y
tetromino_array = \
tetrominos[self.tetromino.tetromino_type][self.tetromino.orient]
if x > pos_y + 1:
k = pos_y + 1
if x + pos_x > self.cols:
x -= 1
for i in range(x):
for j in range(k):
if action(tetromino_array, pos_y-j, pos_x+i, -j-1, i, game_map):
return True
return func
def update_map(self, tetromino_array, j, i, tetromino_y,
tetromino_x, game_map):
game_map[j][i] += \
tetromino_array[tetromino_y][tetromino_x]
def collide_detect(self, tetromino_array, j, i, tetromino_y,
tetromino_x, game_map):
if game_map[j][i] != 0 and tetromino_array[tetromino_y][tetromino_x] != 0:
return True
def get_full_map(self, tetromino_array, j, i, tetromino_y,
tetromino_x, game_map):
if tetromino_array[tetromino_y][tetromino_x] != 0:
game_map[j][i] = tetromino_array[tetromino_y][tetromino_x]
def move_down(self):
self.tetromino.pos_y += 1
if self.collide_detect(self.game_map):
self.tetromino.pos_y -= 1
self.update_map(self.game_map)
self.detect_and_remove_line()
self.add_tetromino()
return False
return True
def move_right(self):
self.tetromino.pos_x += 1
if self.collide_detect(self.game_map):
self.tetromino.pos_x -= 1
def move_left(self):
self.tetromino.pos_x -= 1
if self.collide_detect(self.game_map):
self.tetromino.pos_x += 1
def rotate(self):
pre_orient = self.tetromino.orient
if pre_orient == self.tetromino.type_variants - 1:
self.tetromino.orient = -1
self.tetromino.orient += 1
if self.collide_detect(self.game_map):
self.tetromino.orient = pre_orient
def drop(self):
while self.move_down():
self.fresh_lcd()
def detect_and_remove_line(self):
row = 0
for i in range(self.rows-2):
line_sum = 0
for j in range(1, self.cols-1):
if self.game_map[i][j] != 0:
line_sum += 1
if line_sum == self.cols-2:
self.remove_line(i)
row += 1
self.score.add_score(self.level, row)
if row > 0:
self.celebrate()
def remove_line(self, row_num: int):
for i in range(row_num, 0, -1):
for j in range(1, self.cols - 1):
self.game_map[i][j] = self.game_map[i-1][j]
for j in range(1, self.cols - 1):
self.game_map[0][j] = 0
def celebrate(self):
graphic.draw_num(self.score.score, graphic.score_pos_settings)
graphic.draw_num(self.score.rows, graphic.rows_pos_settings)
graphic.draw_img(celebrate=True)
self.musics.tick(True)
def add_tetromino(self):
self.tetromino = Tetromino(self.cols)
if self.collide_detect(self.game_map):
self.game_over = True
def init_map(self):
game_map = \
[[0 for col in range(self.cols)] for row in range(self.rows)]
# draw wall
for i in range(self.rows):
game_map[i][0] = 8
game_map[i][-1] = 8
for j in range(self.cols):
game_map[-2][j] = 8
game_map[-1][j] = 8
return game_map
def init_game(self):
self.game_map = self.init_map()
self.add_tetromino()
self.game_over = False
self.pause = False
self.score = Score()
graphic.init_graphic(self.display, self.rows, self.cols)
def fresh_lcd(self):
full_map = [i.copy() for i in self.game_map]
self.get_full_map(full_map)
graphic.diff_draw(full_map)
del full_map
def set_controller(self, controller):
self.controller = controller
def set_musics(self, musics: Musics):
self.musics = musics
def start_game(self):
self.init_game()
self.musics.resume()
def pause_game(self):
self.pause = not self.pause
if self.pause:
self.musics.pause()
else:
self.musics.resume()
def run(self):
self.init_game()
while True:
if self.game_over:
self.musics.pause()
while not self.game_over and not self.pause:
utime.sleep_ms(1)
self.move_down_event.tick()
self.musics.tick()
self.controller.run()
self.fresh_lcd()
graphic.draw_img()