Mã nguồn
1
2import cv2
3import numpy as np
4from random import choice
5
6def getColor():
7 lstColor = [[255,64,64],[255,165,0],[255,244,79],[102,255,0],[172,229,238],[148,87,235],[148,87,235],[241,156,187]]
8 return choice(lstColor)
9
10def getInfo(piece):
11 if piece == "":
12 coords = np.array([[0, 0]])
13 elif piece == "I":
14 coords = np.array([[0, 3], [0, 4], [0, 5], [0, 6]])
15 elif piece == "T":
16 coords = np.array([[1, 3], [1, 4], [1, 5], [0, 4]])
17 elif piece == "L":
18 coords = np.array([[1, 3], [1, 4], [1, 5], [0, 5]])
19 elif piece == "J":
20 coords = np.array([[1, 3], [1, 4], [1, 5], [0, 3]])
21 elif piece == "S":
22 coords = np.array([[1, 5], [1, 4], [0, 3], [0, 4]])
23 elif piece == "Z":
24 coords = np.array([[1, 3], [1, 4], [0, 4], [0, 5]])
25 else:
26 coords = np.array([[0, 4], [0, 5], [1, 4], [1, 5]])
27
28 return coords, getColor()
29
30def display(board, coords, color, next_info, held_info, score, SPEED):
31 # Generates the display
32
33 border = np.uint8(127 - np.zeros([20, 1, 3]))
34 border_ = np.uint8(127 - np.zeros([1, 23, 3]))
35
36 dummy = board.copy()
37 dummy[coords[:,0], coords[:,1]] = color
38
39 right = np.uint8(np.zeros([20, 10, 3]))
40 right[next_info[0][:,0] + 2, next_info[0][:,1]] = next_info[1]
41
42 dummy = np.concatenate(( border, dummy, border, right, border), 1)
43 dummy = np.concatenate((border_, dummy, border_), 0)
44 dummy = dummy.repeat(20, 0).repeat(20, 1)
45 dummy = cv2.putText(dummy, str(score), (325, 150), cv2.FONT_HERSHEY_DUPLEX, 1, [0, 0, 255], 2)
46
47 # Instructions for the player
48 index_pos = 300
49 x_index_pos = 300
50 dummy = cv2.putText(dummy, "A - left", (x_index_pos, index_pos), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 234])
51 dummy = cv2.putText(dummy, "D - right", (x_index_pos, index_pos+25), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 234])
52 dummy = cv2.putText(dummy, "S - drain", (x_index_pos, index_pos+50), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 234])
53 dummy = cv2.putText(dummy, "W - rotate", (x_index_pos, index_pos+75), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 234])
54 # dummy = cv2.putText(dummy, "J - rotate left", (45, 300), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
55 # dummy = cv2.putText(dummy, "L - rotate right", (45, 325), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
56 # dummy = cv2.putText(dummy, "I - hold", (45, 350), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
57
58 cv2.imshow("Tetris", dummy)
59 key = cv2.waitKey(int(1000/SPEED))
60
61 return key
62
63def getNextPiece():
64 next_piece = choice(["O", "I", "S", "Z", "L", "J", "T"])
65
66 return next_piece
67
68SPEED = 1 # Controls the speed of the tetris pieces
69
70# Make a board
71
72board = np.uint8(np.zeros([20, 10, 3]))
73
74# Initialize some variables
75
76quit = False
77place = False
78drop = False
79switch = False
80held_piece = ""
81flag = 0
82score = 0
83next_piece =""
84current_piece = ""
85# All the tetris pieces
86
87
88
89if __name__ == "__main__":
90 next_piece = getNextPiece()
91 while not quit:
92 # Check if user wants to swap held and current pieces
93 if switch:
94 # swap held_piece and current_piece
95 held_piece, current_piece = current_piece, held_piece
96 switch = False
97 else:
98 # Generates the next piece and updates the current piece
99 current_piece = next_piece
100 next_piece = getNextPiece()
101
102 if flag > 0:
103 flag -= 1
104
105 # Determines the color and position of the current, next, and held pieces
106
107 held_info = getInfo(held_piece)
108
109 next_info = getInfo(next_piece)
110
111 coords, color = getInfo(current_piece)
112 if current_piece == "I":
113 top_left = [-2, 3]
114
115 if not np.all(board[coords[:,0], coords[:,1]] == 0):
116 break
117
118 while True:
119 # Shows the board and gets the key press
120 key = display(board, coords, color, next_info, held_info, score, SPEED)
121 # Create a copy of the position
122 dummy = coords.copy()
123 print("speed ",SPEED, "key ",key," ", ord("s"))
124
125 if key == ord("s"):
126 drop = True
127
128 elif key == ord("a"):
129 # Moves the piece left if it isn't against the left wall
130 if np.min(coords[:,1]) > 0:
131 coords[:,1] -= 1
132 if current_piece == "I":
133 top_left[1] -= 1
134 elif key == ord("d"):
135 # Moves the piece right if it isn't against the right wall
136 if np.max(coords[:,1]) < 9:
137 coords[:,1] += 1
138 if current_piece == "I":
139 top_left[1] += 1
140 # elif key == ord("j") or key == ord("l"):
141 # # Rotation mechanism
142 # # arr is the array of nearby points which get rotated and pov is the indexes of the blocks within arr
143
144 # if current_piece != "I" and current_piece != "O":
145 # if coords[1,1] > 0 and coords[1,1] < 9:
146 # arr = coords[1] - 1 + np.array([[[x, y] for y in range(3)] for x in range(3)])
147 # pov = coords - coords[1] + 1
148
149 # elif current_piece == "I":
150 # # The straight piece has a 4x4 array, so it needs seperate code
151
152 # arr = top_left + np.array([[[x, y] for y in range(4)] for x in range(4)])
153 # pov = np.array([np.where(np.logical_and(arr[:,:,0] == pos[0], arr[:,:,1] == pos[1])) for pos in coords])
154 # pov = np.array([k[0] for k in np.swapaxes(pov, 1, 2)])
155
156 # # Rotates the array and repositions the piece to where it is now
157
158 # if current_piece != "O":
159 # if key == ord("j"):
160 # arr = np.rot90(arr, -1)
161 # else:
162 # arr = np.rot90(arr)
163 # coords = arr[pov[:,0], pov[:,1]]
164
165 elif key == ord("w"):
166 # Rotation mechanism
167 # arr is the array of nearby points which get rotated and pov is the indexes of the blocks within arr
168
169 if current_piece != "I" and current_piece != "O":
170 if coords[1,1] > 0 and coords[1,1] < 9:
171 arr = coords[1] - 1 + np.array([[[x, y] for y in range(3)] for x in range(3)])
172 pov = coords - coords[1] + 1
173
174 elif current_piece == "I":
175 # The straight piece has a 4x4 array, so it needs seperate code
176
177 arr = top_left + np.array([[[x, y] for y in range(4)] for x in range(4)])
178 pov = np.array([np.where(np.logical_and(arr[:,:,0] == pos[0], arr[:,:,1] == pos[1])) for pos in coords])
179 pov = np.array([k[0] for k in np.swapaxes(pov, 1, 2)])
180
181 # Rotates the array and repositions the piece to where it is now
182
183 if current_piece != "O":
184 if key == ord("j"):
185 arr = np.rot90(arr, -1)
186 else:
187 arr = np.rot90(arr)
188 coords = arr[pov[:,0], pov[:,1]]
189 # Hard drop set to true
190 # drop = True
191 # elif key == ord("i"):
192 # # Goes out of the loop and tells the program to switch held and current pieces
193 # if flag == 0:
194 # if held_piece == "":
195 # held_piece = current_piece
196 # else:
197 # switch = True
198 # flag = 2
199 # break
200 elif key == 8 or key == 27:
201 quit = True
202 break
203
204 # Checks if the piece is overlapping with other pieces or if it's outside the board, and if so, changes the position to the position before anything happened
205
206 if np.max(coords[:,0]) < 20 and np.min(coords[:,0]) >= 0:
207 if not (current_piece == "I" and (np.max(coords[:,1]) >= 10 or np.min(coords[:,1]) < 0)):
208 if not np.all(board[coords[:,0], coords[:,1]] == 0):
209 coords = dummy.copy()
210 else:
211 coords = dummy.copy()
212 else:
213 coords = dummy.copy()
214
215 if drop:
216 # Every iteration of the loop moves the piece down by 1 and if the piece is resting on the ground or another piece, then it stops and places it
217
218 while not place:
219 if np.max(coords[:,0]) != 19:
220 # Checks if the piece is resting on something
221 for pos in coords:
222 if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
223 place = True
224 break
225 else:
226 # If the position of the piece is at the ground level, then it places
227 place = True
228
229 if place:
230 break
231
232 # Keeps going down and checking when the piece needs to be placed
233
234 coords[:,0] += 1
235
236 if current_piece == "I":
237 top_left[0] += 1
238
239 drop = False
240
241 else:
242 # Checks if the piece needs to be placed
243 if np.max(coords[:,0]) != 19:
244 for pos in coords:
245 if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
246 place = True
247 break
248 else:
249 place = True
250
251 if place:
252 # Places the piece where it is on the board
253 for pos in coords:
254 board[tuple(pos)] = color
255
256 # Resets place to False
257 place = False
258 break
259
260 # Moves down by 1
261
262 coords[:,0] += 1
263 if current_piece == "I":
264 top_left[0] += 1
265
266 # Clears lines and also counts how many lines have been cleared and updates the score
267
268 lines = 0
269
270 for line in range(20):
271 if np.all([np.any(pos != 0) for pos in board[line]]):
272 lines += 1
273 board[1:line+1] = board[:line]
274
275
276 score += lines*10
Mã nguồn này được kế thừa từ bài viết https://www.learnopencv.com/tetris-with-opencv-python/ và mình có modify lại theo sở thích cá nhân của mình. Còn một số bug mà mình chưa fix hết. Bạn đọc nào ghé ngang có đóng góp gì thì để lại comment giúp mình hen.
Comments