tictactoe.py
import pygame
from pygame.locals import *
pygame.init()
pygame.font.init()
window_size = (450, 500)
screen = pygame.display.set_mode(window_size)
pygame.display.set_caption("Tic Tac Toe")
class TicTacToe():
def __init__(self, table_size):
self.table_size = table_size
self.cell_size = table_size // 3
self.table_space = 20
self.player = "X"
self.winner = None
self.taking_move = True
self.running = True
self.table = []
for col in range(3):
self.table.append([])
for row in range(3):
self.table[col].append("-")
self.background_color = (255, 174, 66)
self.table_color = (50, 50, 50)
self.line_color = (190, 0, 10)
self.instructions_color = (17, 53, 165)
self.game_over_bg_color = (47, 98, 162)
self.game_over_color = (255, 179, 1)
self.font = pygame.font.SysFont("Courier New", 35)
self.FPS = pygame.time.Clock()
# draws table representation
def _draw_table(self):
tb_space_point = (self.table_space, self.table_size - self.table_space)
cell_space_point = (self.cell_size, self.cell_size * 2)
r1 = pygame.draw.line(screen, self.table_color, [tb_space_point[0], cell_space_point[0]], [tb_space_point[1], cell_space_point[0]], 8)
c1 = pygame.draw.line(screen, self.table_color, [cell_space_point[0], tb_space_point[0]], [cell_space_point[0], tb_space_point[1]], 8)
r2 = pygame.draw.line(screen, self.table_color, [tb_space_point[0], cell_space_point[1]], [tb_space_point[1], cell_space_point[1]], 8)
c2 = pygame.draw.line(screen, self.table_color, [cell_space_point[1], tb_space_point[0]], [cell_space_point[1], tb_space_point[1]], 8)
def _change_player(self):
self.player = "O" if self.player == "X" else "X"
# processing clicks to move
def _move(self, pos):
try:
x, y = pos[0] // self.cell_size, pos[1] // self.cell_size
if self.table[x][y] == "-":
self.table[x][y] = self.player
self._draw_char(x,y,self.player)
self._game_check()
self._change_player()
except:
print("Click inside the table only")
# draws character of the recent player to the selected table cell
def _draw_char(self, x, y, player):
if self.player == "O":
img = pygame.image.load("images/Tc-O.png")
elif self.player == "X":
img = pygame.image.load("images/Tc-X.png")
img = pygame.transform.scale(img, (self.cell_size, self.cell_size))
screen.blit(img, (x * self.cell_size, y * self.cell_size, self.cell_size, self.cell_size))
# instructions and game-state messages
def _message(self):
if self.winner is not None:
screen.fill(self.game_over_bg_color, (130, 445, 193, 35))
msg = self.font.render(f'{self.winner} WINS!!', True, self.game_over_color)
screen.blit(msg,(144,445))
elif not self.taking_move:
screen.fill(self.game_over_bg_color, (130, 445, 193, 35))
instructions = self.font.render('DRAW!!', True, self.game_over_color)
screen.blit(instructions,(165,445))
else:
screen.fill(self.background_color, (135, 445, 188, 35))
instructions = self.font.render(f'{self.player} to move', True, self.instructions_color)
screen.blit(instructions,(135,445))
def _game_check(self):
# vertical check
for x_index, col in enumerate(self.table):
win = True
pattern_list = []
for y_index, content in enumerate(col):
if content != self.player:
win = False
break
else:
pattern_list.append((x_index, y_index))
if win == True:
self._pattern_strike(pattern_list[0],pattern_list[-1],"ver")
self.winner = self.player
self.taking_move = False
break
# horizontal check
for row in range(len(self.table)):
win = True
pattern_list = []
for col in range(len(self.table)):
if self.table[col][row] != self.player:
win = False
break
else:
pattern_list.append((col, row))
if win == True:
self._pattern_strike(pattern_list[0],pattern_list[-1],"hor")
self.winner = self.player
self.taking_move = False
break
# left diagonal check
for index, row in enumerate(self.table):
win = True
if row[index] != self.player:
win = False
break
if win == True:
self._pattern_strike((0,0),(2,2),"left-diag")
self.winner = self.player
self.taking_move = False
# right diagonal check
for index, row in enumerate(self.table[::-1]):
win = True
if row[index] != self.player:
win = False
break
if win == True:
self._pattern_strike((2,0),(0,2),"right-diag")
self.winner = self.player
self.taking_move = False
# blank table cells check
blank_cells = 0
for row in self.table:
for cell in row:
if cell == "-":
blank_cells += 1
if blank_cells == 0:
self.taking_move = False
# strikes a line to winning patterns if already has
def _pattern_strike(self, start_point, end_point, line_type):
# gets the middle value of the cell
mid_val = self.cell_size // 2
# for the vertical winning pattern
if line_type == "ver":
start_x, start_y = start_point[0] * self.cell_size + mid_val, self.table_space
end_x, end_y = end_point[0] * self.cell_size + mid_val, self.table_size - self.table_space
# for the horizontal winning pattern
elif line_type == "hor":
start_x, start_y = self.table_space, start_point[-1] * self.cell_size + mid_val
end_x, end_y = self.table_size - self.table_space, end_point[-1] * self.cell_size + mid_val
# for the diagonal winning pattern from top-left to bottom right
elif line_type == "left-diag":
start_x, start_y = self.table_space, self.table_space
end_x, end_y = self.table_size - self.table_space, self.table_size - self.table_space
# for the diagonal winning pattern from top-right to bottom-left
elif line_type == "right-diag":
start_x, start_y = self.table_size - self.table_space, self.table_space
end_x, end_y = self.table_space, self.table_size - self.table_space
# draws the line strike
line_strike = pygame.draw.line(screen, self.line_color, [start_x, start_y], [end_x, end_y], 8)
def main(self):
screen.fill(self.background_color)
self._draw_table()
while self.running:
self._message()
for self.event in pygame.event.get():
if self.event.type == pygame.QUIT:
self.running = False
if self.event.type == pygame.MOUSEBUTTONDOWN:
if self.taking_move:
self._move(self.event.pos)
pygame.display.flip()
self.FPS.tick(60)
if __name__ == "__main__":
g = TicTacToe(window_size[0])
g.main()