Xây Dựng Game Xếp Gạch Bằng Opencv Và Python

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