tetris.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import cv2
  2. import numpy as np
  3. from random import choice
  4. SPEED = 1 # Controls the speed of the tetris pieces
  5. # Make a board
  6. board = np.uint8(np.zeros([20, 10, 3]))
  7. # Initialize some variables
  8. quit = False
  9. place = False
  10. drop = False
  11. switch = False
  12. held_piece = ""
  13. flag = 0
  14. score = 0
  15. # All the tetris pieces
  16. next_piece = choice(["O", "I", "S", "Z", "L", "J", "T"])
  17. def get_info(piece):
  18. if piece == "I":
  19. coords = np.array([[0, 3], [0, 4], [0, 5], [0, 6]])
  20. color = [255, 155, 15]
  21. elif piece == "T":
  22. coords = np.array([[1, 3], [1, 4], [1, 5], [0, 4]])
  23. color = [138, 41, 175]
  24. elif piece == "L":
  25. coords = np.array([[1, 3], [1, 4], [1, 5], [0, 5]])
  26. color = [2, 91, 227]
  27. elif piece == "J":
  28. coords = np.array([[1, 3], [1, 4], [1, 5], [0, 3]])
  29. color = [198, 65, 33]
  30. elif piece == "S":
  31. coords = np.array([[1, 5], [1, 4], [0, 3], [0, 4]])
  32. color = [55, 15, 215]
  33. elif piece == "Z":
  34. coords = np.array([[1, 3], [1, 4], [0, 4], [0, 5]])
  35. color = [1, 177, 89]
  36. else:
  37. coords = np.array([[0, 4], [0, 5], [1, 4], [1, 5]])
  38. color = [2, 159, 227]
  39. return coords, color
  40. def display(board, coords, color, next_info, held_info, score, SPEED):
  41. # Generates the display
  42. border = np.uint8(127 - np.zeros([20, 1, 3]))
  43. border_ = np.uint8(127 - np.zeros([1, 34, 3]))
  44. dummy = board.copy()
  45. dummy[coords[:,0], coords[:,1]] = color
  46. right = np.uint8(np.zeros([20, 10, 3]))
  47. right[next_info[0][:,0] + 2, next_info[0][:,1]] = next_info[1]
  48. left = np.uint8(np.zeros([20, 10, 3]))
  49. left[held_info[0][:,0] + 2, held_info[0][:,1]] = held_info[1]
  50. dummy = np.concatenate((border, left, border, dummy, border, right, border), 1)
  51. dummy = np.concatenate((border_, dummy, border_), 0)
  52. dummy = dummy.repeat(20, 0).repeat(20, 1)
  53. dummy = cv2.putText(dummy, str(score), (520, 200), cv2.FONT_HERSHEY_DUPLEX, 1, [0, 0, 255], 2)
  54. # Instructions for the player
  55. dummy = cv2.putText(dummy, "A - move left", (45, 200), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  56. dummy = cv2.putText(dummy, "D - move right", (45, 225), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  57. dummy = cv2.putText(dummy, "S - move down", (45, 250), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  58. dummy = cv2.putText(dummy, "W - hard drop", (45, 275), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  59. dummy = cv2.putText(dummy, "J - rotate left", (45, 300), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  60. dummy = cv2.putText(dummy, "L - rotate right", (45, 325), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  61. dummy = cv2.putText(dummy, "I - hold", (45, 350), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
  62. cv2.imshow("Tetris", dummy)
  63. key = cv2.waitKey(int(1000/SPEED))
  64. return key
  65. if __name__ == "__main__":
  66. while not quit:
  67. # Check if user wants to swap held and current pieces
  68. if switch:
  69. # swap held_piece and current_piece
  70. held_piece, current_piece = current_piece, held_piece
  71. switch = False
  72. else:
  73. # Generates the next piece and updates the current piece
  74. current_piece = next_piece
  75. next_piece = choice(["I", "T", "L", "J", "Z", "S", "O"])
  76. if flag > 0:
  77. flag -= 1
  78. # Determines the color and position of the current, next, and held pieces
  79. if held_piece == "":
  80. held_info = np.array([[0, 0]]), [0, 0, 0]
  81. else:
  82. held_info = get_info(held_piece)
  83. next_info = get_info(next_piece)
  84. coords, color = get_info(current_piece)
  85. if current_piece == "I":
  86. top_left = [-2, 3]
  87. if not np.all(board[coords[:,0], coords[:,1]] == 0):
  88. break
  89. while True:
  90. # Shows the board and gets the key press
  91. key = display(board, coords, color, next_info, held_info, score, SPEED)
  92. # Create a copy of the position
  93. dummy = coords.copy()
  94. if key == ord("a"):
  95. # Moves the piece left if it isn't against the left wall
  96. if np.min(coords[:,1]) > 0:
  97. coords[:,1] -= 1
  98. if current_piece == "I":
  99. top_left[1] -= 1
  100. elif key == ord("d"):
  101. # Moves the piece right if it isn't against the right wall
  102. if np.max(coords[:,1]) < 9:
  103. coords[:,1] += 1
  104. if current_piece == "I":
  105. top_left[1] += 1
  106. elif key == ord("j") or key == ord("l"):
  107. # Rotation mechanism
  108. # arr is the array of nearby points which get rotated and pov is the indexes of the blocks within arr
  109. if current_piece != "I" and current_piece != "O":
  110. if coords[1,1] > 0 and coords[1,1] < 9:
  111. arr = coords[1] - 1 + np.array([[[x, y] for y in range(3)] for x in range(3)])
  112. pov = coords - coords[1] + 1
  113. elif current_piece == "I":
  114. # The straight piece has a 4x4 array, so it needs seperate code
  115. arr = top_left + np.array([[[x, y] for y in range(4)] for x in range(4)])
  116. pov = np.array([np.where(np.logical_and(arr[:,:,0] == pos[0], arr[:,:,1] == pos[1])) for pos in coords])
  117. pov = np.array([k[0] for k in np.swapaxes(pov, 1, 2)])
  118. # Rotates the array and repositions the piece to where it is now
  119. if current_piece != "O":
  120. if key == ord("j"):
  121. arr = np.rot90(arr, -1)
  122. else:
  123. arr = np.rot90(arr)
  124. coords = arr[pov[:,0], pov[:,1]]
  125. elif key == ord("w"):
  126. # Hard drop set to true
  127. drop = True
  128. elif key == ord("i"):
  129. # Goes out of the loop and tells the program to switch held and current pieces
  130. if flag == 0:
  131. if held_piece == "":
  132. held_piece = current_piece
  133. else:
  134. switch = True
  135. flag = 2
  136. break
  137. elif key == 8 or key == 27:
  138. quit = True
  139. break
  140. # 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
  141. if np.max(coords[:,0]) < 20 and np.min(coords[:,0]) >= 0:
  142. if not (current_piece == "I" and (np.max(coords[:,1]) >= 10 or np.min(coords[:,1]) < 0)):
  143. if not np.all(board[coords[:,0], coords[:,1]] == 0):
  144. coords = dummy.copy()
  145. else:
  146. coords = dummy.copy()
  147. else:
  148. coords = dummy.copy()
  149. if drop:
  150. # 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
  151. while not place:
  152. if np.max(coords[:,0]) != 19:
  153. # Checks if the piece is resting on something
  154. for pos in coords:
  155. if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
  156. place = True
  157. break
  158. else:
  159. # If the position of the piece is at the ground level, then it places
  160. place = True
  161. if place:
  162. break
  163. # Keeps going down and checking when the piece needs to be placed
  164. coords[:,0] += 1
  165. score += 1
  166. if current_piece == "I":
  167. top_left[0] += 1
  168. drop = False
  169. else:
  170. # Checks if the piece needs to be placed
  171. if np.max(coords[:,0]) != 19:
  172. for pos in coords:
  173. if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
  174. place = True
  175. break
  176. else:
  177. place = True
  178. if place:
  179. # Places the piece where it is on the board
  180. for pos in coords:
  181. board[tuple(pos)] = color
  182. # Resets place to False
  183. place = False
  184. break
  185. # Moves down by 1
  186. coords[:,0] += 1
  187. if key == ord("s"):
  188. score += 1
  189. if current_piece == "I":
  190. top_left[0] += 1
  191. # Clears lines and also counts how many lines have been cleared and updates the score
  192. lines = 0
  193. for line in range(20):
  194. if np.all([np.any(pos != 0) for pos in board[line]]):
  195. lines += 1
  196. board[1:line+1] = board[:line]
  197. if lines == 1:
  198. score += 40
  199. elif lines == 2:
  200. score += 100
  201. elif lines == 3:
  202. score += 300
  203. elif lines == 4:
  204. score += 1200