class MainGUI: def __init__(self): pygame.init() self.manager = GameManager() self.enemy = Ai() pygame.display.set_caption("Tic Tac Toe") self.WIDTH = 540 self.HEIGHT = 540 self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT)) self.background = pygame.Surface((self.WIDTH, self.HEIGHT)) self.background.fill(pygame.Color('#E3E3E3')) # FONTS self.playerFont = pygame.font.SysFont('arial', 70) self.resultFont = pygame.font.SysFont('arial', 60, bold=True) self.infoFont = pygame.font.SysFont('arial', 30, italic=True) # define cell dimensions self.cellWidth = self.WIDTH / 3 self.cellHeight = self.HEIGHT / 3 self.board = [] # to create the 3x3 grid for i in range(3): for j in range(3): self.board.append( Cell(self.cellWidth * i, self.cellHeight * j, self.cellWidth, self.cellHeight)) self.manager.gameState = 'progress' self.running = True def displayGrids(self): # horizontal lines for i in range(2): # pygame.draw.line(surface, color, start_pos, end_pos, width = 1) start_pos = (0, int(self.cellHeight * (i + 1))) end_pos = (self.WIDTH, int(self.cellHeight * (i + 1))) pygame.draw.line(self.background, (0, 0, 0), start_pos, end_pos, 2) # vertical lines for i in range(2): # pygame.draw.line(surface, color, start_pos, end_pos, width = 1) start_pos = (int(self.cellWidth * (i + 1)), 0) end_pos = (int(self.cellWidth * (i + 1)), self.HEIGHT) pygame.draw.line(self.background, (0, 0, 0), start_pos, end_pos, 2) for cell in self.board: player = self.playerFont.render(cell.state, True, (0, 0, 0)) x, y = self.playerFont.size(cell.state) self.screen.blit( player, (int((cell.x + cell.w / 2) - x / 2), int((cell.y + cell.h / 2) - y / 2))) def endGameMsg(self, result): # rectangle that the message will be drawn w = self.WIDTH h = 150 x = 0 y = int(self.HEIGHT / 2 - h / 2) pygame.draw.rect(self.screen, pygame.Color( '#4D4D4D'), pygame.Rect(x, y, w, h)) # result text if self.manager.result == 'tie': resultText = "It's a tie!" result = self.resultFont.render(resultText, True, (0, 0, 0)) else: resultText = f"{self.manager.result} won!" result = self.resultFont.render(resultText, True, (0, 0, 0)) x, y_txt = self.resultFont.size(resultText) self.screen.blit(result, (int(w / 2 - x / 2), int(y + 5))) # info text infoText = "Press R to restart the game!" info = self.infoFont.render(infoText, True, (0, 0, 0)) x, y_txt = self.infoFont.size(infoText) self.screen.blit(info, (int(w / 2 - x / 2), int(y + 100))) def run(self): while self.running: for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False # check mouse down if event.type == pygame.MOUSEBUTTONDOWN: if self.manager.gameState == 'progress': for cell in self.board: if self.manager.currentPlayer == 'X' and cell.checkUserCLicked(pygame.mouse.get_pos()) and cell.state == '': # cause the O player is the AI cell.changeState('X') self.manager.changeTurn() # check keys pressed if event.type == pygame.KEYDOWN: # restart the game if event.key == pygame.K_r and self.manager.gameState == 'over': self.manager.currentPlayer = 'X' for cell in self.board: cell.state = '' self.manager.gameState = 'progress' # recolorize the background self.background.fill(pygame.Color('#ffffff')) # to check if there's a win if self.manager.checkWin(self.board): self.manager.currentPlayer = '' self.manager.gameState = 'over' self.manager.result = self.manager.checkWin(self.board, True) # to check if there's a tie if self.manager.checkTie(self.board): self.manager.currentPlayer = '' self.manager.gameState = 'over' self.manager.result = 'tie' # check if it's AI turn if self.manager.currentPlayer == 'O' and self.manager.gameState == 'progress': self.enemy.play(self.board) self.manager.changeTurn() # UI self.screen.blit(self.background, (0, 0)) if self.manager.gameState == 'over': # if tie, paint te background gray if self.manager.result == 'tie': self.background.fill(pygame.Color('#9DA897')) elif self.manager.result == 'X': self.background.fill(pygame.Color('#7AFF77')) elif self.manager.result == 'O': self.background.fill(pygame.Color('#F53920')) self.displayGrids() self.endGameMsg(self.manager.result) if self.manager.gameState != 'over': self.displayGrids() pygame.display.update()