fork(1) download
  1. import pygame
  2.  
  3.  
  4.  
  5. def main():
  6.  
  7. # Setup the properties of the game / screen
  8. pygame.init()
  9. SCREEN_WIDTH ,SCREEN_HEIGHT = 1280, 720
  10. FPS = 60
  11. screen = pygame.display.set_mode( (SCREEN_WIDTH, SCREEN_HEIGHT) )
  12. pygame.display.set_caption('Tic Tac Toe')
  13. clock = pygame.time.Clock()
  14. running = True
  15. clicked = False
  16. # 0 = no winner, 1 = player1 won, 2 = player2 won, 3 = tie
  17. winner = 0
  18. restart = False
  19. BG_COLOR = (0, 0, 0)
  20. b = board(SCREEN_WIDTH, SCREEN_HEIGHT)
  21.  
  22. # Counts whose turn it is
  23. # Even turn = Player1
  24. # Odd turn = Player2
  25. turn = 0
  26.  
  27. # Fill an array with 9 area objects, for each
  28. # area of the board
  29. #
  30. # area 0.0 | area 0.1 | area 0.2
  31. # _______________________________
  32. # area 1.0 | area 1.1 | area 1.2
  33. # _______________________________
  34. # area 2.0 | area 2.1 | area 2.2
  35. areas = []
  36. for i in range(3):
  37. row = []
  38. for j in range(3):
  39. row.append(area(
  40. (b.get_board_posx() + (j * ( (b.get_board_size() / 3) +
  41. (b.get_thickness() /2 ) ) ) ),
  42. (b.get_board_posy() + (i * ( (b.get_board_size() / 3) +
  43. (b.get_thickness() / 2 ) ) ) ),
  44. b.get_field_size()
  45. ))
  46.  
  47. areas.append(row)
  48.  
  49.  
  50. ###########
  51. # GAME LOOP
  52. ###########
  53. while running:
  54.  
  55. # Abort condition
  56. # If (x) is clicked, terminate program
  57. # If clicked is True, the user clicked in this
  58. # iteration of the game loop
  59. for event in pygame.event.get():
  60. if event.type == pygame.QUIT:
  61. running = False
  62. elif event.type == pygame.MOUSEBUTTONDOWN:
  63. clicked = True
  64. if (not (winner == 0)):
  65. restart = True
  66.  
  67. # If any key or mousebutton is pressed
  68. # while game is over, game restarts
  69. elif event.type == pygame.KEYDOWN:
  70. if (not winner == 0):
  71. restart = True
  72.  
  73. if event.key == pygame.K_ESCAPE:
  74. running = False
  75.  
  76.  
  77.  
  78.  
  79. # Setup screen
  80. screen.fill(BG_COLOR)
  81. b.draw_board(screen)
  82. mouse_posx, mouse_posy = pygame.mouse.get_pos()
  83.  
  84.  
  85. # Looping through every area on the board
  86. # Most of the game logic happens here
  87. for i in range(len(areas)):
  88. for j in range(len(areas[i])):
  89.  
  90. # Draw already set X tokens
  91. if (areas[i][j].get_state() == 2):
  92. draw_x_token(
  93. areas[i][j].get_posx(),
  94. areas[i][j].get_posy(),
  95. b.get_field_size(),
  96. screen,
  97. b.get_color()
  98. )
  99.  
  100. # Draw already set O tokens
  101. if (areas[i][j].get_state() == 3):
  102. draw_o_token(
  103. areas[i][j].get_posx(),
  104. areas[i][j].get_posy(),
  105. b.get_field_size(),
  106. screen,
  107. b.get_color()
  108. )
  109.  
  110.  
  111. # Checking if mouse is hovering over any
  112. # of the areas
  113. # If so, preview token that is about to be drawn
  114. if(areas[i][j].is_in(mouse_posx, mouse_posy)):
  115. # print('Mouse is in Area({}, {})'.format(i, j))
  116.  
  117.  
  118. # Handling clicks (Draw tokens)
  119. if clicked:
  120. if (not(areas[i][j].get_state() == 2) and
  121. not(areas[i][j].get_state() ==3) and winner == 0 ):
  122.  
  123. if (turn % 2 == 0):
  124. draw_x_token(
  125. areas[i][j].get_posx(),
  126. areas[i][j].get_posy(),
  127. b.get_field_size(),
  128. screen,
  129. b.get_color()
  130. )
  131.  
  132. areas[i][j].set_state(2)
  133. turn += 1
  134.  
  135. else:
  136. draw_o_token(
  137. areas[i][j].get_posx(),
  138. areas[i][j].get_posy(),
  139. b.get_field_size(),
  140. screen,
  141. b.get_color()
  142. )
  143.  
  144. areas[i][j].set_state(3)
  145. turn += 1
  146.  
  147.  
  148.  
  149. if ( (areas[i][j].get_state() == 0
  150. or areas[i][j].get_state() == 1) and winner == 0 ):
  151.  
  152. # even turn: Player1
  153. if (turn % 2 == 0):
  154. draw_x_token(
  155. areas[i][j].get_posx(),
  156. areas[i][j].get_posy(),
  157. b.get_field_size(),
  158. screen,
  159. b.get_color()
  160. )
  161.  
  162. areas[i][j].set_state(1)
  163.  
  164. else:
  165. draw_o_token(
  166. areas[i][j].get_posx(),
  167. areas[i][j].get_posy(),
  168. b.get_field_size(),
  169. screen,
  170. b.get_color()
  171. )
  172.  
  173. areas[i][j].set_state(1)
  174.  
  175.  
  176.  
  177. # If mouse is not hovering over an area
  178. # and area is not already used
  179. # Set state to inactive
  180. else:
  181. if (
  182. not(areas[i][j].get_state() == 2) and
  183. not(areas[i][j].get_state() ==3)
  184. ):
  185. areas[i][j].set_state(0)
  186.  
  187.  
  188. # Check if there is a winner
  189. # after this round
  190. win_cons = [
  191. # Horizontal
  192. [ areas[0][0], areas[0][1], areas[0][2] ],
  193. [ areas[1][0], areas[1][1], areas[1][2] ],
  194. [ areas[2][0], areas[2][1], areas[2][2] ],
  195. # Vertical
  196. [ areas[0][0], areas[1][0], areas[2][0] ],
  197. [ areas[0][1], areas[1][1], areas[2][1] ],
  198. [ areas[0][2], areas[1][2], areas[2][2] ],
  199. # Diagonal
  200. [ areas[0][2], areas[1][1], areas[2][0] ],
  201. [ areas[0][0], areas[1][1], areas[2][2] ]
  202. ]
  203. for i in range( len(win_cons) ):
  204. if (
  205. win_cons[i][0].get_state() ==
  206. win_cons[i][1].get_state() ==
  207. win_cons[i][2].get_state() ==
  208. 2
  209. ):
  210. winner = 1
  211.  
  212. if (
  213. win_cons[i][0].get_state() ==
  214. win_cons[i][1].get_state() ==
  215. win_cons[i][2].get_state() ==
  216. 3
  217. ):
  218. winner = 2
  219.  
  220. # Check for tie
  221. fields_filled = 0
  222. for i in range(len(areas)):
  223. for j in range(len(areas[i])):
  224. if (
  225. areas[i][j].get_state() == 2 or
  226. areas[i][j].get_state() == 3
  227. ):
  228. fields_filled += 1
  229.  
  230. if (fields_filled == 9 and winner == 0):
  231. winner = 3
  232.  
  233. if ( not (winner == 0) ):
  234.  
  235. if winner == 1:
  236. draw_text(screen, 'Player X has Won. Press any key to restart',
  237. b.get_board_posx(),
  238. b.get_board_posy() - b.get_board_size() * 0.08,
  239. int( round(b.get_board_size() * 0.055) ) )
  240. elif winner == 2:
  241. draw_text(screen, 'Player O has Won. Press any key to restart',
  242. b.get_board_posx(),
  243. b.get_board_posy() - b.get_board_size() * 0.08,
  244. int( round(b.get_board_size() * 0.055) ))
  245. elif winner == 3:
  246. draw_text(screen, 'You both win! Press any key to restart',
  247. b.get_board_posx(),
  248. b.get_board_posy() - b.get_board_size() * 0.08,
  249. int( round(b.get_board_size() * 0.055) ) )
  250.  
  251.  
  252.  
  253. # Reset all changing variables
  254. # and set area states to inactive
  255. if restart:
  256. restart = False
  257. winner = 0
  258. turn = 0
  259.  
  260. for i in range(len(areas)):
  261. for j in range(len(areas[i])):
  262. areas[i][j].set_state(0)
  263.  
  264.  
  265.  
  266. # Pygame stuff
  267. pygame.display.update()
  268. clock.tick(FPS)
  269. clicked = False
  270.  
  271. ##################
  272. # END OF GAME LOOP
  273. ##################
  274.  
  275. # closing the pygame application
  276. pygame.quit()
  277.  
  278.  
  279. def draw_text(screen, text, posx, posy, size):
  280. my_font = pygame.font.SysFont('Arial', size)
  281. textsurface = my_font.render(text, False, (255, 255, 255))
  282. screen.blit(textsurface, (posx, posy))
  283.  
  284. def draw_x_token(posx, posy, size, screen, color):
  285. offset = size * 0.1
  286. thickness = size * 0.1
  287.  
  288. points0 = [
  289. (posx + offset, posy + offset),
  290. (posx + offset + thickness, posy + offset),
  291. (posx + size - offset, posy + size - offset),
  292. (posx + size - (offset + thickness), posy + size - offset)]
  293.  
  294. pygame.draw.polygon(screen, color, points0, 0 )
  295.  
  296. points1 = [
  297. ( posx + size - (offset + thickness), posy + offset),
  298. ( posx + size - offset, posy + offset),
  299. ( posx + offset + thickness, posy + size - offset),
  300. ( posx + offset, posy + size - offset)]
  301.  
  302. pygame.draw.polygon(screen, color, points1, 0 )
  303.  
  304. def draw_o_token(posx, posy, size, screen, color):
  305. offset = size * 0.1
  306. thickness = size * 0.1
  307. radius = size / 2 - offset
  308.  
  309. pygame.draw.circle(
  310. screen,
  311. color,
  312. ( int( round(posx + (size / 2), 0) ),
  313. int( round(posy + (size / 2), 0) ) ),
  314. int( round(radius) ),
  315. int( round (thickness) ) )
  316.  
  317.  
  318. class board:
  319.  
  320. def __init__(self, SCREEN_WIDTH, SCREEN_HEIGHT):
  321. self.SCREEN_WIDTH = SCREEN_WIDTH
  322. self.SCREEN_HEIGHT = SCREEN_HEIGHT
  323.  
  324. self.BOARD_WIDTH = self.BOARD_HEIGHT = 550
  325. self.COLOR = (255, 255, 255)
  326. self.THICKNESS = self.BOARD_WIDTH * 0.025
  327.  
  328. # The point (posx, posy) is at the top left position
  329. # of the board
  330. # Setting up posx and posy in a way
  331. # that the board is always drawn in the centre
  332. # of the pygame application/screen
  333. self.posx = (self.SCREEN_WIDTH / 2) - (self.BOARD_WIDTH / 2)
  334. self.posy = (self.SCREEN_HEIGHT / 2) - (self.BOARD_HEIGHT / 2)
  335.  
  336. # Printing positions of the 4 board lines
  337. # for debug purposes
  338. #print( 'Left vertical line {}, {}'.format(
  339. #self.posx + (self.BOARD_WIDTH / 3) - (self.THICKNESS / 2),
  340. #self.posy
  341. #) )
  342.  
  343. #print( 'Right vertical line {}, {}'.format(
  344. #self.posx + ( ( (self.BOARD_WIDTH / 3) - (self.THICKNESS / 2) ) * 2),
  345. #self.posy
  346. #))
  347.  
  348. #print( 'Upper horizontal line {}, {}'.format(
  349. #self.posx,
  350. #self.posy + (self.BOARD_HEIGHT / 3) - (self.THICKNESS / 2)
  351. #) )
  352.  
  353. #print( 'Lower horizontal line {}, {}'.format(
  354. #self.posx,
  355. #self.posy + ( ( (self.BOARD_HEIGHT / 3) - (self.THICKNESS / 2) ) * 2)
  356. #))
  357.  
  358.  
  359. # Draws the game board in the middle of the screen
  360. def draw_board(self, screen):
  361.  
  362. # Draw left vertical line
  363. pygame.draw.rect(screen, self.COLOR, (
  364. self.posx + (self.BOARD_WIDTH / 3) - (self.THICKNESS / 2),
  365. self.posy, self.THICKNESS, self.BOARD_HEIGHT), 0)
  366.  
  367. # Draw right verical line
  368. pygame.draw.rect(screen, self.COLOR, (
  369. self.posx + ( (self.BOARD_WIDTH / 3) * 2 ),
  370. self.posy, self.THICKNESS, self.BOARD_HEIGHT), 0)
  371.  
  372. # Draw upper horizontal line
  373. pygame.draw.rect(screen, self.COLOR, (
  374. self.posx,
  375. self.posy + (self.BOARD_HEIGHT / 3) - (self.THICKNESS / 2),
  376. self.BOARD_WIDTH, self.THICKNESS), 0)
  377.  
  378. # Draw lower horizontal line
  379. pygame.draw.rect(screen, self.COLOR, (
  380. self.posx,
  381. self.posy + ( (self.BOARD_HEIGHT / 3) * 2),
  382. self.BOARD_WIDTH, self.THICKNESS), 0)
  383.  
  384. # Getters to access board vars
  385. def get_board_posx(self):
  386. return self.posx
  387. def get_board_posy(self):
  388. return self.posy
  389. def get_board_size(self):
  390. return self.BOARD_WIDTH
  391. def get_thickness(self):
  392. return self.THICKNESS
  393. def get_field_size(self):
  394. return (self.BOARD_WIDTH / 3) - (self.THICKNESS / 2)
  395. def get_color(self):
  396. return self.COLOR
  397.  
  398. # The board is divided into 9 areas:
  399. #
  400. # area 0.0 | area 0.1 | area 0.2
  401. # _______________________________
  402. # area 1.0 | area 1.1 | area 1.2
  403. # _______________________________
  404. # area 2.0 | area 2.1 | area 2.2
  405. class area:
  406. active = False
  407.  
  408.  
  409. def __init__(self, posx, posy, size):
  410. self.posx = posx
  411. self.posy = posy
  412.  
  413. # width and height of an area
  414. self.size = size
  415.  
  416. # 0 = inactive
  417. # 1 = mouse is hovering over area
  418. # 2 = area is filled with an X
  419. # 3 = area is filled with an O
  420. self.state = 0
  421.  
  422. # Debug
  423. #print(posx, posy, size)
  424.  
  425. def __repr__(self):
  426. return 'Area({}, {})'.format(self.posx, self.posy)
  427.  
  428. # Function tests if Point(x, y) lies in the Area
  429. # Typically used with mouseposition
  430. def is_in(self, x, y):
  431. if (
  432. (x >= self.posx) and # Top left limit
  433. (x <= (self.posx + self.size)) and # Top right limit
  434. (y >= self.posy) and # Bottom left limit
  435. (y <= (self.posy + self.size)) # Bottom right limit
  436. ):
  437. return True
  438.  
  439. else:
  440. return False
  441.  
  442. # only for debug
  443. def print_pos(self):
  444. print(self.posx, self.posy, self.size)
  445.  
  446.  
  447.  
  448. def get_posx(self):
  449. return self.posx
  450.  
  451. def get_posy(self):
  452. return self.posy
  453.  
  454.  
  455. def get_active(self):
  456. return self.active
  457.  
  458. def change_active(self):
  459. self.active = not self.active
  460.  
  461.  
  462. def get_state(self):
  463. return self.state
  464.  
  465. def set_state(self, state):
  466. if (state == 0 or
  467. state == 1 or
  468. state == 2 or
  469. state == 3):
  470. self.state = state
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478. main()
  479.  
Runtime error #stdin #stdout #stderr 0.04s 9380KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
Traceback (most recent call last):
  File "./prog.py", line 1, in <module>
ImportError: No module named 'pygame'