competitive_tetris.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #!/usr/bin/python3
  2. """
  3. Competitive tetris server
  4. """
  5. import random
  6. import pygame
  7. pygame.font.init()
  8. # GLOBALS VARS
  9. S_WIDTH = 800
  10. S_HEIGHT = 700
  11. PLAY_WIDTH = 300 # meaning 300 // 10 = 30 width per block
  12. PLAY_HEIGHT = 600 # meaning 600 // 20 = 30 height per block
  13. BLOCK_SIZE = 30
  14. TOP_LEFT_X = (S_WIDTH - PLAY_WIDTH) // 2
  15. TOP_LEFT_Y = S_HEIGHT - PLAY_HEIGHT
  16. # SHAPE FORMATS
  17. I = [['..........',
  18. '...0000...',
  19. '..........',
  20. '..........'],
  21. ['.....0....',
  22. '.....0....',
  23. '.....0....',
  24. '.....0....'],
  25. ['..........',
  26. '..........',
  27. '...0000...',
  28. '..........'],
  29. ['....0.....',
  30. '....0.....',
  31. '....0.....',
  32. '....0.....']]
  33. O = [['..........',
  34. '....00....',
  35. '....00....',
  36. '..........'],
  37. ['..........',
  38. '....00....',
  39. '....00....',
  40. '..........'],
  41. ['..........',
  42. '....00....',
  43. '....00....',
  44. '..........'],
  45. ['..........',
  46. '....00....',
  47. '....00....',
  48. '..........']]
  49. T = [['....0.....',
  50. '...000....',
  51. '..........',
  52. '..........'],
  53. ['....0.....',
  54. '....00....',
  55. '....0.....',
  56. '..........'],
  57. ['..........',
  58. '...000....',
  59. '....0.....',
  60. '..........'],
  61. ['....0.....',
  62. '...00.....',
  63. '....0.....',
  64. '..........']]
  65. S = [['....00....',
  66. '...00.....',
  67. '..........',
  68. '..........'],
  69. ['....0.....',
  70. '....00....',
  71. '.....0....',
  72. '..........'],
  73. ['..........',
  74. '....00....',
  75. '...00.....',
  76. '..........'],
  77. ['...0......',
  78. '...00.....',
  79. '....0.....',
  80. '..........']]
  81. Z = [['...00.....',
  82. '....00....',
  83. '..........',
  84. '..........'],
  85. ['.....0....',
  86. '....00....',
  87. '....0.....',
  88. '..........'],
  89. ['..........',
  90. '...00.....',
  91. '....00....',
  92. '..........'],
  93. ['....0.....',
  94. '...00.....',
  95. '...0......',
  96. '..........']]
  97. J = [['.....',
  98. '.0...',
  99. '.000.',
  100. '.....',
  101. '.....'],
  102. ['.....',
  103. '..00.',
  104. '..0..',
  105. '..0..',
  106. '.....'],
  107. ['.....',
  108. '.....',
  109. '.000.',
  110. '...0.',
  111. '.....'],
  112. ['.....',
  113. '..0..',
  114. '..0..',
  115. '.00..',
  116. '.....']]
  117. L = [['.....',
  118. '...0.',
  119. '.000.',
  120. '.....',
  121. '.....'],
  122. ['.....',
  123. '..0..',
  124. '..0..',
  125. '..00.',
  126. '.....'],
  127. ['.....',
  128. '.....',
  129. '.000.',
  130. '.0...',
  131. '.....'],
  132. ['.....',
  133. '.00..',
  134. '..0..',
  135. '..0..',
  136. '.....']]
  137. SHAPES = [S, Z, I, O, J, L, T]
  138. SHAPE_COLORS = [(0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 255, 0),
  139. (255, 165, 0), (0, 0, 255), (128, 0, 128)]
  140. # index 0 - 6 represent shape
  141. class Piece:
  142. def __init__(self, x, y, shape):
  143. self.x = x
  144. self.y = y
  145. self.shape = shape
  146. self.color = SHAPE_COLORS[SHAPES.index(shape)]
  147. self.rotation = 0
  148. def create_grid(locked_pos={}):
  149. grid = [[(0,0,0) for _ in range(10)] for _ in range(20)]
  150. for i in range(len(grid)):
  151. for j in range(len(grid[i])):
  152. if (j, i) in locked_pos:
  153. c = locked_pos[(j,i)]
  154. grid[i][j] = c
  155. return grid
  156. def convert_shape_format(shape):
  157. positions = []
  158. format = shape.shape[shape.rotation % len(shape.shape)]
  159. for i, line in enumerate(format):
  160. row = list(line)
  161. for j, column in enumerate(row):
  162. if column == '0':
  163. positions.append((shape.x + j, shape.y + i))
  164. for i, pos in enumerate(positions):
  165. positions[i] = (pos[0] - 2, pos[1] - 4)
  166. return positions
  167. def valid_space(shape, grid):
  168. accepted_pos = [[(j, i) for j in range(10) if grid[i][j] == (0,0,0)] for i in range(20)]
  169. accepted_pos = [j for sub in accepted_pos for j in sub]
  170. formatted = convert_shape_format(shape)
  171. for pos in formatted:
  172. if pos not in accepted_pos:
  173. if pos[1] > -1:
  174. return False
  175. return True
  176. def check_lost(positions):
  177. for pos in positions:
  178. x, y = pos
  179. if y < 1:
  180. return True
  181. return False
  182. def get_shape():
  183. return Piece(5, 0, random.choice(SHAPES))
  184. def draw_text_middle(surface, text, size, color):
  185. font = pygame.font.SysFont("comicsans", size, bold=True)
  186. label = font.render(text, 1, color)
  187. surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH /2 - (label.get_width()/2), TOP_LEFT_Y + PLAY_HEIGHT/2 - label.get_height()/2))
  188. def draw_grid(surface, grid):
  189. sx = TOP_LEFT_X
  190. sy = TOP_LEFT_Y
  191. for i in range(len(grid)):
  192. pygame.draw.line(surface, (128,128,128), (sx, sy + i*BLOCK_SIZE), (sx+PLAY_WIDTH, sy+ i*BLOCK_SIZE))
  193. for j in range(len(grid[i])):
  194. pygame.draw.line(surface, (128, 128, 128), (sx + j*BLOCK_SIZE, sy),(sx + j*BLOCK_SIZE, sy + PLAY_HEIGHT))
  195. def clear_rows(grid, locked):
  196. inc = 0
  197. for i in range(len(grid)-1, -1, -1):
  198. row = grid[i]
  199. if (0,0,0) not in row:
  200. inc += 1
  201. ind = i
  202. for j in range(len(row)):
  203. try:
  204. del locked[(j,i)]
  205. except:
  206. continue
  207. if inc > 0:
  208. for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
  209. x, y = key
  210. if y < ind:
  211. newKey = (x, y + inc)
  212. locked[newKey] = locked.pop(key)
  213. return inc
  214. def draw_next_shape(shape, surface):
  215. font = pygame.font.SysFont('comicsans', 30)
  216. label = font.render('Next Shape', 1, (255,255,255))
  217. sx = TOP_LEFT_X + PLAY_WIDTH + 50
  218. sy = TOP_LEFT_Y + PLAY_HEIGHT/2 - 100
  219. format = shape.shape[shape.rotation % len(shape.shape)]
  220. for i, line in enumerate(format):
  221. row = list(line)
  222. for j, column in enumerate(row):
  223. if column == '0':
  224. pygame.draw.rect(surface, shape.color, (sx + j*BLOCK_SIZE, sy + i*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 0)
  225. surface.blit(label, (sx + 10, sy - 30))
  226. def update_score(nscore):
  227. score = max_score()
  228. with open('scores.txt', 'w') as f:
  229. if int(score) > nscore:
  230. f.write(str(score))
  231. else:
  232. f.write(str(nscore))
  233. def max_score():
  234. with open('scores.txt', 'r') as f:
  235. lines = f.readlines()
  236. score = lines[0].strip()
  237. return score
  238. def draw_window(surface, grid, score=0, last_score = 0):
  239. surface.fill((0, 0, 0))
  240. pygame.font.init()
  241. font = pygame.font.SysFont('comicsans', 60)
  242. label = font.render('Tetris', 1, (255, 255, 255))
  243. surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH / 2 - (label.get_width() / 2), 30))
  244. # current score
  245. font = pygame.font.SysFont('comicsans', 30)
  246. label = font.render('Score: ' + str(score), 1, (255,255,255))
  247. sx = TOP_LEFT_X + PLAY_WIDTH + 50
  248. sy = TOP_LEFT_Y + PLAY_HEIGHT/2 - 100
  249. surface.blit(label, (sx + 20, sy + 160))
  250. # last score
  251. label = font.render('High Score: ' + last_score, 1, (255,255,255))
  252. sx = TOP_LEFT_X - 200
  253. sy = TOP_LEFT_Y + 200
  254. surface.blit(label, (sx + 20, sy + 160))
  255. for i in range(len(grid)):
  256. for j in range(len(grid[i])):
  257. pygame.draw.rect(surface, grid[i][j], (TOP_LEFT_X + j*BLOCK_SIZE, TOP_LEFT_Y + i*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 0)
  258. pygame.draw.rect(surface, (255, 0, 0), (TOP_LEFT_X, TOP_LEFT_Y, PLAY_WIDTH, PLAY_HEIGHT), 5)
  259. draw_grid(surface, grid)
  260. #pygame.display.update()
  261. def main(win): # *
  262. last_score = max_score()
  263. locked_positions = {}
  264. grid = create_grid(locked_positions)
  265. change_piece = False
  266. run = True
  267. current_piece = get_shape()
  268. next_piece = get_shape()
  269. clock = pygame.time.Clock()
  270. fall_time = 0
  271. fall_speed = 0.27
  272. level_time = 0
  273. score = 0
  274. while run:
  275. grid = create_grid(locked_positions)
  276. fall_time += clock.get_rawtime()
  277. level_time += clock.get_rawtime()
  278. clock.tick()
  279. if level_time/1000 > 5:
  280. level_time = 0
  281. if level_time > 0.12:
  282. level_time -= 0.005
  283. if fall_time/1000 > fall_speed:
  284. fall_time = 0
  285. current_piece.y += 1
  286. if not(valid_space(current_piece, grid)) and current_piece.y > 0:
  287. current_piece.y -= 1
  288. change_piece = True
  289. for event in pygame.event.get():
  290. if event.type == pygame.QUIT:
  291. run = False
  292. pygame.display.quit()
  293. if event.type == pygame.KEYDOWN:
  294. if event.key == pygame.K_LEFT:
  295. current_piece.x -= 1
  296. if not(valid_space(current_piece, grid)):
  297. current_piece.x += 1
  298. if event.key == pygame.K_RIGHT:
  299. current_piece.x += 1
  300. if not(valid_space(current_piece, grid)):
  301. current_piece.x -= 1
  302. if event.key == pygame.K_DOWN:
  303. current_piece.y += 1
  304. if not(valid_space(current_piece, grid)):
  305. current_piece.y -= 1
  306. if event.key == pygame.K_UP:
  307. current_piece.rotation += 1
  308. if not(valid_space(current_piece, grid)):
  309. current_piece.rotation -= 1
  310. shape_pos = convert_shape_format(current_piece)
  311. for i in range(len(shape_pos)):
  312. x, y = shape_pos[i]
  313. if y > -1:
  314. grid[y][x] = current_piece.color
  315. if change_piece:
  316. for pos in shape_pos:
  317. p = (pos[0], pos[1])
  318. locked_positions[p] = current_piece.color
  319. current_piece = next_piece
  320. next_piece = get_shape()
  321. change_piece = False
  322. score += clear_rows(grid, locked_positions) * 10
  323. draw_window(win, grid, score, last_score)
  324. draw_next_shape(next_piece, win)
  325. pygame.display.update()
  326. if check_lost(locked_positions):
  327. draw_text_middle(win, "YOU LOST!", 80, (255,255,255))
  328. pygame.display.update()
  329. pygame.time.delay(1500)
  330. run = False
  331. update_score(score)
  332. def main_menu(win): # *
  333. run = True
  334. while run:
  335. win.fill((0,0,0))
  336. draw_text_middle(win, 'Press Any Key To Play', 60, (255,255,255))
  337. pygame.display.update()
  338. for event in pygame.event.get():
  339. if event.type == pygame.QUIT:
  340. run = False
  341. if event.type == pygame.KEYDOWN:
  342. main(win)
  343. pygame.display.quit()
  344. win = pygame.display.set_mode((S_WIDTH, S_HEIGHT))
  345. pygame.display.set_caption('Tetris')
  346. main_menu(win)