Tic-Tac-Toe Python Code

Python

import pygame
import sys
import random
import math
from enum import Enum

# Initialize pygame
pygame.init()
pygame.font.init()

# Screen dimensions
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Modern Tic-Tac-Toe")

# Colors
BACKGROUND = (18, 18, 24)
GRID_COLOR = (40, 44, 60)
GRID_HIGHLIGHT = (70, 80, 120)
PLAYER_X_COLOR = (86, 156, 214)  # Blue
PLAYER_O_COLOR = (220, 120, 100)  # Coral
TEXT_COLOR = (220, 220, 220)
BUTTON_COLOR = (60, 64, 90)
BUTTON_HOVER = (80, 90, 140)
BUTTON_TEXT = (220, 220, 220)
PANEL_COLOR = (30, 34, 48, 200)

# Game settings
BOARD_SIZES = [3, 4, 5]  # Supported board sizes
DEFAULT_BOARD_SIZE = 3
CELL_SIZE = 100
BOARD_PADDING = 50
ANIMATION_SPEED = 0.15

# Fonts
TITLE_FONT = pygame.font.SysFont("Arial", 48, bold=True)
SCORE_FONT = pygame.font.SysFont("Arial", 28)
BUTTON_FONT = pygame.font.SysFont("Arial", 24)
INFO_FONT = pygame.font.SysFont("Arial", 20)
SMALL_FONT = pygame.font.SysFont("Arial", 18)

class PlayerType(Enum):
    HUMAN = 1
    COMPUTER = 2

class Difficulty(Enum):
    EASY = 1
    MEDIUM = 2
    HARD = 3

class Player:
    def __init__(self, symbol, player_type=PlayerType.HUMAN, difficulty=Difficulty.EASY):
        self.symbol = symbol
        self.player_type = player_type
        self.difficulty = difficulty
        self.score = 0
        self.color = PLAYER_X_COLOR if symbol == 'X' else PLAYER_O_COLOR
        
    def __str__(self):
        return f"Player {self.symbol}"
    
    def is_computer(self):
        return self.player_type == PlayerType.COMPUTER

class Board:
    def __init__(self, size=3):
        self.size = size
        self.cells = [['' for _ in range(size)] for _ in range(size)]
        self.animations = []  # Store animation data: (row, col, symbol, progress)
        self.winning_line = None
        
    def reset(self):
        self.cells = [['' for _ in range(self.size)] for _ in range(self.size)]
        self.animations = []
        self.winning_line = None
        
    def is_valid_move(self, row, col):
        return 0 <= row < self.size and 0 <= col < self.size and self.cells[row][col] == ''
    
    def make_move(self, row, col, symbol, animate=True):
        if self.is_valid_move(row, col):
            self.cells[row][col] = symbol
            if animate:
                self.animations.append((row, col, symbol, 0))
            return True
        return False
    
    def is_full(self):
        for row in self.cells:
            for cell in row:
                if cell == '':
                    return False
        return True
    
    def check_win(self, symbol):
        # Check rows
        for row in range(self.size):
            if all(self.cells[row][col] == symbol for col in range(self.size)):
                self.winning_line = ("row", row)
                return True
        
        # Check columns
        for col in range(self.size):
            if all(self.cells[row][col] == symbol for row in range(self.size)):
                self.winning_line = ("col", col)
                return True
        
        # Check diagonals
        if all(self.cells[i][i] == symbol for i in range(self.size)):
            self.winning_line = ("diag", 0)
            return True
        if all(self.cells[i][self.size-1-i] == symbol for i in range(self.size)):
            self.winning_line = ("diag", 1)
            return True
        
        return False
    
    def get_available_moves(self):
        moves = []
        for row in range(self.size):
            for col in range(self.size):
                if self.cells[row][col] == '':
                    moves.append((row, col))
        return moves

class Button:
    def __init__(self, x, y, width, height, text, action=None, font=BUTTON_FONT):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.action = action
        self.hovered = False
        self.font = font
        
    def draw(self, surface):
        color = BUTTON_HOVER if self.hovered else BUTTON_COLOR
        pygame.draw.rect(surface, color, self.rect, border_radius=8)
        pygame.draw.rect(surface, GRID_HIGHLIGHT, self.rect, 2, border_radius=8)
        
        text_surf = self.font.render(self.text, True, BUTTON_TEXT)
        text_rect = text_surf.get_rect(center=self.rect.center)
        surface.blit(text_surf, text_rect)
        
    def check_hover(self, pos):
        self.hovered = self.rect.collidepoint(pos)
        
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if self.hovered and self.action:
                return self.action()
        return None

class InputBox:
    def __init__(self, x, y, width, height, text='', font=BUTTON_FONT):
        self.rect = pygame.Rect(x, y, width, height)
        self.color = BUTTON_COLOR
        self.text = text
        self.font = font
        self.active = False
        self.max_length = 2  # For board size input
        
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            # If the user clicked on the input_box rect
            if self.rect.collidepoint(event.pos):
                # Toggle the active variable
                self.active = True
            else:
                self.active = False
            # Change the current color of the input box
            self.color = BUTTON_HOVER if self.active else BUTTON_COLOR
        if event.type == pygame.KEYDOWN:
            if self.active:
                if event.key == pygame.K_RETURN:
                    return self.text
                elif event.key == pygame.K_BACKSPACE:
                    self.text = self.text[:-1]
                elif event.key == pygame.K_ESCAPE:
                    self.active = False
                    self.color = BUTTON_COLOR
                else:
                    # Only allow numbers
                    if event.unicode.isdigit() and len(self.text) < self.max_length:
                        self.text += event.unicode
        return None
        
    def draw(self, surface):
        # Draw the input box
        pygame.draw.rect(surface, self.color, self.rect, border_radius=5)
        pygame.draw.rect(surface, GRID_HIGHLIGHT, self.rect, 2, border_radius=5)
        
        # Render the text
        text_surface = self.font.render(self.text, True, BUTTON_TEXT)
        # Position text in the center
        text_rect = text_surface.get_rect(center=self.rect.center)
        surface.blit(text_surface, text_rect)

class Game:
    def __init__(self):
        self.board = Board(DEFAULT_BOARD_SIZE)
        self.players = []
        self.current_player_index = 0
        self.game_mode = None  # 'pvp', 'pvc'
        self.game_over = False
        self.winner = None
        self.computer_thinking = False
        self.buttons = []
        self.input_box = None
        self.custom_size = DEFAULT_BOARD_SIZE
        self.setup_main_menu()
        self.current_screen = "main_menu"  # Track current screen
        
    def setup_main_menu(self):
        self.current_screen = "main_menu"
        self.buttons = [
            Button(WIDTH//2 - 100, HEIGHT//2 - 50, 200, 50, "Player vs Player", lambda: self.setup_board_size_menu('pvp')),
            Button(WIDTH//2 - 100, HEIGHT//2 + 20, 200, 50, "Player vs Computer", lambda: self.setup_board_size_menu('pvc')),
            Button(WIDTH//2 - 100, HEIGHT//2 + 90, 200, 50, "Quit", lambda: pygame.event.post(pygame.event.Event(pygame.QUIT)))
        ]
        
    def setup_board_size_menu(self, mode):
        self.current_screen = "board_size"
        self.game_mode = mode
        self.buttons = []
        
        # Title
        title = "Select Board Size"
        
        # Standard size buttons
        for i, size in enumerate(BOARD_SIZES):
            self.buttons.append(
                Button(WIDTH//2 - 100, HEIGHT//3 + i * 60, 200, 50, 
                      f"{size}x{size}", 
                      lambda s=size: self.start_game(s))
            )
        
        # Custom size button
        self.buttons.append(
            Button(WIDTH//2 - 100, HEIGHT//3 + len(BOARD_SIZES) * 60, 200, 50, 
                   "Custom Size", 
                   self.show_custom_size_input)
        )
        
        # Back button
        self.buttons.append(
            Button(WIDTH//2 - 100, HEIGHT - 80, 200, 50, 
                   "Back", 
                   self.setup_main_menu)
        )
    
    def show_custom_size_input(self):
        self.current_screen = "custom_size"
        self.buttons = []
        
        # Custom size input
        self.input_box = InputBox(WIDTH//2 - 50, HEIGHT//2 - 25, 100, 50, str(self.custom_size))
        
        # Confirm button
        self.buttons.append(
            Button(WIDTH//2 - 100, HEIGHT//2 + 40, 200, 50, 
                   "Confirm", 
                   self.confirm_custom_size)
        )
        
        # Back button
        self.buttons.append(
            Button(WIDTH//2 - 100, HEIGHT - 80, 200, 50, 
                   "Back", 
                   lambda: self.setup_board_size_menu(self.game_mode))
        )
    
    def confirm_custom_size(self):
        if self.input_box.text.isdigit():
            size = int(self.input_box.text)
            if 3 <= size <= 8:
                self.start_game(size)
            else:
                # Show error message?
                pass
        return True
    
    def start_game(self, board_size):
        # Validate board size
        if board_size < 3:
            board_size = 3
        elif board_size > 8:  # Set a reasonable limit
            board_size = 8
            
        self.current_screen = "game"
        self.board = Board(board_size)
        self.game_over = False
        self.winner = None
        self.current_player_index = 0
        self.input_box = None
        
        # Create players
        if self.game_mode == 'pvp':
            self.players = [
                Player('X'),
                Player('O')
            ]
        else:  # pvc
            self.players = [
                Player('X'),
                Player('O', PlayerType.COMPUTER, Difficulty.MEDIUM)
            ]
        
        # Create in-game buttons
        self.buttons = [
            Button(WIDTH - 150, HEIGHT - 60, 130, 40, "Main Menu", self.return_to_menu),
            Button(WIDTH - 150, HEIGHT - 120, 130, 40, "Restart", self.restart_game)
        ]
    
    def return_to_menu(self):
        self.game_mode = None
        self.setup_main_menu()
        return True
        
    def restart_game(self):
        self.board.reset()
        self.game_over = False
        self.winner = None
        self.current_player_index = 0
        return True
        
    def get_current_player(self):
        return self.players[self.current_player_index]
    
    def next_player(self):
        self.current_player_index = (self.current_player_index + 1) % len(self.players)
    
    def handle_click(self, pos):
        if self.game_over or self.get_current_player().is_computer():
            return
            
        # Calculate board position
        board_x = (WIDTH - (self.board.size * CELL_SIZE)) // 2
        board_y = (HEIGHT - (self.board.size * CELL_SIZE)) // 2
        
        # Check if click is on board
        if (board_x <= pos[0] <= board_x + self.board.size * CELL_SIZE and
            board_y <= pos[1] <= board_y + self.board.size * CELL_SIZE):
            
            # Calculate grid position
            col = (pos[0] - board_x) // CELL_SIZE
            row = (pos[1] - board_y) // CELL_SIZE
            
            # Make move
            if self.board.make_move(row, col, self.get_current_player().symbol):
                # Check win/draw
                if self.board.check_win(self.get_current_player().symbol):
                    self.game_over = True
                    self.winner = self.get_current_player()
                    self.winner.score += 1
                elif self.board.is_full():
                    self.game_over = True
                else:
                    self.next_player()
                    
                    # If next player is computer, set thinking flag
                    if self.get_current_player().is_computer():
                        self.computer_thinking = True
    
    def computer_move(self):
        if not self.computer_thinking or self.game_over:
            return
            
        # Artificial delay to simulate thinking
        pygame.time.delay(500)
        
        player = self.get_current_player()
        moves = self.board.get_available_moves()
        
        if not moves:
            return
            
        # Easy: random move
        if player.difficulty == Difficulty.EASY:
            row, col = random.choice(moves)
        
        # Medium: try to win or block
        elif player.difficulty == Difficulty.MEDIUM:
            # Try to win
            win_found = False
            for move in moves:
                row, col = move
                self.board.cells[row][col] = player.symbol
                if self.board.check_win(player.symbol):
                    win_found = True
                    self.board.cells[row][col] = ''
                    break
                self.board.cells[row][col] = ''
            
            if not win_found:
                # Block opponent
                opponent_symbol = 'O' if player.symbol == 'X' else 'X'
                block_found = False
                for move in moves:
                    row, col = move
                    self.board.cells[row][col] = opponent_symbol
                    if self.board.check_win(opponent_symbol):
                        block_found = True
                        self.board.cells[row][col] = ''
                        break
                    self.board.cells[row][col] = ''
                
                if not block_found:
                    # Random move
                    row, col = random.choice(moves)
        
        # Hard: minimax for 3x3
        elif player.difficulty == Difficulty.HARD and self.board.size == 3:
            row, col = self.minimax_move(player.symbol)
        else:
            row, col = random.choice(moves)
        
        # Make the move
        self.board.make_move(row, col, player.symbol)
        
        # Check win/draw
        if self.board.check_win(player.symbol):
            self.game_over = True
            self.winner = player
            self.winner.score += 1
        elif self.board.is_full():
            self.game_over = True
        else:
            self.next_player()
        
        self.computer_thinking = False
    
    def minimax_move(self, symbol):
        best_score = -float('inf')
        best_move = None
        
        for row, col in self.board.get_available_moves():
            self.board.cells[row][col] = symbol
            score = self.minimax(self.board, False, symbol)
            self.board.cells[row][col] = ''
            
            if score > best_score:
                best_score = score
                best_move = (row, col)
        
        return best_move
    
    def minimax(self, board, is_maximizing, symbol):
        opponent = 'O' if symbol == 'X' else 'X'
        
        if board.check_win(symbol):
            return 1
        elif board.check_win(opponent):
            return -1
        elif board.is_full():
            return 0
        
        if is_maximizing:
            best_score = -float('inf')
            for row, col in board.get_available_moves():
                board.cells[row][col] = symbol
                score = self.minimax(board, False, symbol)
                board.cells[row][col] = ''
                best_score = max(score, best_score)
            return best_score
        else:
            best_score = float('inf')
            for row, col in board.get_available_moves():
                board.cells[row][col] = opponent
                score = self.minimax(board, True, symbol)
                board.cells[row][col] = ''
                best_score = min(score, best_score)
            return best_score
    
    def update(self):
        # Update animations
        for i, (row, col, symbol, progress) in enumerate(self.board.animations):
            progress = min(1.0, progress + ANIMATION_SPEED)
            self.board.animations[i] = (row, col, symbol, progress)
        
        # Computer move
        if self.computer_thinking:
            self.computer_move()
    
    def draw(self, surface):
        # Draw background
        surface.fill(BACKGROUND)
        
        if self.current_screen == "main_menu":
            self.draw_main_menu(surface)
        elif self.current_screen == "board_size":
            self.draw_board_size_menu(surface)
        elif self.current_screen == "custom_size":
            self.draw_custom_size_menu(surface)
        elif self.current_screen == "game":
            self.draw_game(surface)
    
    def draw_main_menu(self, surface):
        # Draw title
        title = TITLE_FONT.render("TIC-TAC-TOE", True, TEXT_COLOR)
        surface.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
        
        # Draw subtitle
        subtitle = SCORE_FONT.render("Modern Edition", True, PLAYER_X_COLOR)
        surface.blit(subtitle, (WIDTH//2 - subtitle.get_width()//2, HEIGHT//4 + 60))
        
        # Draw buttons
        for button in self.buttons:
            button.draw(surface)
        
        # Draw instructions
        instructions = [
            "• Player vs Player: Two players on one device",
            "• Player vs Computer: Challenge AI at three difficulty levels",
            "• Use mouse or keyboard to play"
        ]
        
        for i, text in enumerate(instructions):
            text_surf = INFO_FONT.render(text, True, (180, 180, 200))
            surface.blit(text_surf, (WIDTH//2 - text_surf.get_width()//2, HEIGHT - 150 + i * 30))
    
    def draw_board_size_menu(self, surface):
        # Draw title
        title = TITLE_FONT.render("SELECT BOARD SIZE", True, TEXT_COLOR)
        surface.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//6))
        
        # Draw buttons
        for button in self.buttons:
            button.draw(surface)
    
    def draw_custom_size_menu(self, surface):
        # Draw title
        title = TITLE_FONT.render("CUSTOM BOARD SIZE", True, TEXT_COLOR)
        surface.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
        
        # Draw input label
        label = SCORE_FONT.render("Enter board size (3-8):", True, TEXT_COLOR)
        surface.blit(label, (WIDTH//2 - label.get_width()//2, HEIGHT//2 - 80))
        
        # Draw input box
        if self.input_box:
            self.input_box.draw(surface)
        
        # Draw buttons
        for button in self.buttons:
            button.draw(surface)
    
    def draw_game(self, surface):
        # Draw scores
        score_x = SCORE_FONT.render(f"Player X: {self.players[0].score}", True, PLAYER_X_COLOR)
        score_o = SCORE_FONT.render(f"Player O: {self.players[1].score}", True, PLAYER_O_COLOR)
        surface.blit(score_x, (20, 20))
        surface.blit(score_o, (WIDTH - score_o.get_width() - 20, 20))
        
        # Draw current player
        player = self.get_current_player()
        status_text = f"{player.symbol}'s Turn"
        if player.is_computer() and self.computer_thinking:
            status_text = "Computer thinking..."
        status = SCORE_FONT.render(status_text, True, player.color)
        surface.blit(status, (WIDTH//2 - status.get_width()//2, 20))
        
        # Draw board size info
        size_info = SMALL_FONT.render(f"Board Size: {self.board.size}x{self.board.size}", True, TEXT_COLOR)
        surface.blit(size_info, (WIDTH//2 - size_info.get_width()//2, 60))
        
        # Draw board
        board_x = (WIDTH - (self.board.size * CELL_SIZE)) // 2
        board_y = (HEIGHT - (self.board.size * CELL_SIZE)) // 2
        
        # Draw grid
        for i in range(self.board.size + 1):
            # Horizontal lines
            pygame.draw.line(surface, GRID_COLOR, 
                            (board_x, board_y + i * CELL_SIZE),
                            (board_x + self.board.size * CELL_SIZE, board_y + i * CELL_SIZE), 4)
            # Vertical lines
            pygame.draw.line(surface, GRID_COLOR, 
                            (board_x + i * CELL_SIZE, board_y),
                            (board_x + i * CELL_SIZE, board_y + self.board.size * CELL_SIZE), 4)
        
        # Draw symbols with animations
        for row in range(self.board.size):
            for col in range(self.board.size):
                cell_x = board_x + col * CELL_SIZE + CELL_SIZE // 2
                cell_y = board_y + row * CELL_SIZE + CELL_SIZE // 2
                
                # Draw hover effect for empty cells
                mouse_pos = pygame.mouse.get_pos()
                cell_rect = pygame.Rect(board_x + col * CELL_SIZE, 
                                       board_y + row * CELL_SIZE, 
                                       CELL_SIZE, CELL_SIZE)
                
                if (not self.game_over and not self.computer_thinking and
                    not player.is_computer() and cell_rect.collidepoint(mouse_pos) and
                    self.board.cells[row][col] == ''):
                    pygame.draw.rect(surface, GRID_HIGHLIGHT, cell_rect, border_radius=5)
                
                # Draw symbols
                symbol = self.board.cells[row][col]
                if symbol:
                    # Check if this cell has an animation
                    anim_progress = 1.0
                    for anim_row, anim_col, anim_symbol, progress in self.board.animations:
                        if anim_row == row and anim_col == col:
                            anim_progress = progress
                            break
                    
                    color = PLAYER_X_COLOR if symbol == 'X' else PLAYER_O_COLOR
                    if anim_progress < 1.0:
                        # For animation, we'll create a temporary surface with alpha
                        temp_surface = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA)
                        alpha = int(255 * anim_progress)
                        anim_color = (*color, alpha)
                        
                        if symbol == 'X':
                            # Draw animated X
                            size = int(CELL_SIZE * 0.3 * anim_progress)
                            pygame.draw.line(temp_surface, anim_color, 
                                            (CELL_SIZE//2 - size, CELL_SIZE//2 - size),
                                            (CELL_SIZE//2 + size, CELL_SIZE//2 + size), 8)
                            pygame.draw.line(temp_surface, anim_color, 
                                            (CELL_SIZE//2 - size, CELL_SIZE//2 + size),
                                            (CELL_SIZE//2 + size, CELL_SIZE//2 - size), 8)
                        else:  # 'O'
                            # Draw animated O
                            radius = int(CELL_SIZE * 0.3 * anim_progress)
                            pygame.draw.circle(temp_surface, anim_color, 
                                              (CELL_SIZE//2, CELL_SIZE//2), radius, 8)
                        
                        surface.blit(temp_surface, (board_x + col * CELL_SIZE, board_y + row * CELL_SIZE))
                    else:
                        # Draw static symbol
                        if symbol == 'X':
                            size = int(CELL_SIZE * 0.3)
                            pygame.draw.line(surface, color, 
                                            (cell_x - size, cell_y - size),
                                            (cell_x + size, cell_y + size), 8)
                            pygame.draw.line(surface, color, 
                                            (cell_x - size, cell_y + size),
                                            (cell_x + size, cell_y - size), 8)
                        else:  # 'O'
                            radius = int(CELL_SIZE * 0.3)
                            pygame.draw.circle(surface, color, (cell_x, cell_y), radius, 8)
        
        # Draw winning line - ONLY if there's a winner
        if self.board.winning_line and self.winner:
            line_type, index = self.board.winning_line
            color = self.winner.color
            
            if line_type == "row":
                y = board_y + index * CELL_SIZE + CELL_SIZE // 2
                pygame.draw.line(surface, color, 
                                (board_x, y),
                                (board_x + self.board.size * CELL_SIZE, y), 8)
            elif line_type == "col":
                x = board_x + index * CELL_SIZE + CELL_SIZE // 2
                pygame.draw.line(surface, color, 
                                (x, board_y),
                                (x, board_y + self.board.size * CELL_SIZE), 8)
            elif line_type == "diag":
                if index == 0:
                    pygame.draw.line(surface, color, 
                                    (board_x, board_y),
                                    (board_x + self.board.size * CELL_SIZE, 
                                     board_y + self.board.size * CELL_SIZE), 8)
                else:
                    pygame.draw.line(surface, color, 
                                    (board_x + self.board.size * CELL_SIZE, board_y),
                                    (board_x, board_y + self.board.size * CELL_SIZE), 8)
        
        # Draw game over message
        if self.game_over:
            # Semi-transparent overlay
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 180))
            surface.blit(overlay, (0, 0))
            
            if self.winner:
                message = f"{self.winner.symbol} Wins!"
                color = self.winner.color
            else:
                message = "It's a Draw!"
                color = TEXT_COLOR
            
            text = TITLE_FONT.render(message, True, color)
            surface.blit(text, (WIDTH//2 - text.get_width()//2, HEIGHT//3))
            
            restart = BUTTON_FONT.render("Press any key to continue", True, TEXT_COLOR)
            surface.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT//2))
        
        # Draw buttons
        for button in self.buttons:
            button.draw(surface)
            
        # Draw controls info
        controls = INFO_FONT.render("Controls: Mouse click | Arrow keys + Enter | Number keys 1-9", True, (180, 180, 200))
        surface.blit(controls, (WIDTH//2 - controls.get_width()//2, HEIGHT - 30))

def main():
    clock = pygame.time.Clock()
    game = Game()
    
    # Create a surface for the game
    game_surface = pygame.Surface((WIDTH, HEIGHT))
    
    # Main game loop
    running = True
    while running:
        mouse_pos = pygame.mouse.get_pos()
        
        # Handle events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            
            # Handle keyboard events
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    if game.current_screen == "game":
                        game.return_to_menu()
                    else:
                        running = False
                
                # Handle number keys for quick selection
                elif game.current_screen == "game" and not game.game_over and not game.get_current_player().is_computer():
                    max_cell = game.board.size * game.board.size
                    if pygame.K_1 <= event.key <= pygame.K_9 and max_cell <= 9:
                        num = event.key - pygame.K_0
                        if 1 <= num <= max_cell:
                            row = (num - 1) // game.board.size
                            col = (num - 1) % game.board.size
                            game.handle_click((
                                (WIDTH - game.board.size * CELL_SIZE) // 2 + col * CELL_SIZE + 1,
                                (HEIGHT - game.board.size * CELL_SIZE) // 2 + row * CELL_SIZE + 1
                            ))
                
                # Handle custom input
                if game.current_screen == "custom_size" and game.input_box:
                    result = game.input_box.handle_event(event)
                    if result:
                        try:
                            size = int(result)
                            if 3 <= size <= 8:
                                game.start_game(size)
                        except ValueError:
                            pass
            
            # Handle mouse events
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # Handle board clicks
                if game.current_screen == "game" and not game.input_box:
                    game.handle_click(event.pos)
                
                # Check buttons
                for button in game.buttons:
                    button.handle_event(event)
                
                # Handle custom input box
                if game.current_screen == "custom_size" and game.input_box:
                    game.input_box.handle_event(event)
        
        # Update button hover states
        for button in game.buttons:
            button.check_hover(mouse_pos)
        
        # Update game state
        game.update()
        
        # Draw everything
        game.draw(game_surface)
        
        # Draw game surface to screen
        screen.blit(game_surface, (0, 0))
        pygame.display.flip()
        
        # Cap the frame rate
        clock.tick(60)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()
            
Responsive Design
Copy to Clipboard
Syntax Highlighted
Scrollable Code