Creating a Simple Tic Tac Toe Game with Pygame Zero

Setting up the Game Window

We'll start by importing two libraries: `pgzrun` to help run the game and `random` to make unpredictable choices for the computer.


    import pgzrun
    import random
                

Next, we decide the size of our game window. The game will be 300 pixels wide and tall. Each square (or tile) of our Tic Tac Toe board is one-third of the game window's width.


    WIDTH = 300
    HEIGHT = 300
    TILE_SIZE = WIDTH // 3
                

Building the Game Logic with a Class

We'll construct a class named Game. This class is like the game's control center. When we make a new "instance" of this class, we initiate a new game.


    class Game:
        def __init__(self):
            self.board = [['' for _ in range(3)] for _ in range(3)]
            self.player = 'X'
            self.ai = 'O'
            self.current_turn = 'X'
                

Player's Turn

This section dictates how the player places an "X" on the board.


        def player_move(self, x, y):
            if self.board[y][x] == '':
                self.board[y][x] = self.player
                if not self.is_game_over():
                    self.current_turn = self.ai
                    self.ai_move()
                

AI's Turn

The computer uses this part to decide where to place an "O" on the board. It selects randomly from the available spots.


        def ai_move(self):
            available_moves = [(x, y) for y in range(3) for x in range(3) if self.board[y][x] == '']
            if available_moves:
                x, y = random.choice(available_moves)
                self.board[y][x] = self.ai
            if not self.is_game_over():
                self.current_turn = self.player
        

Checking the Game's Outcome

This section determines if someone (player or AI) has won, or if the board is filled up resulting in a tie.


        def is_game_over(self):
            for i in range(3):
                if self.board[i][0] == self.board[i][1] == self.board[i][2] != '':
                    return True
            if self.board[0][0] == self.board[1][1] == self.board[2][2] != '' or self.board[0][2] == self.board[1][1] == self.board[2][0] != '':
                return True
            if all(cell != '' for row in self.board for cell in row):
                return True
            return False
        

Starting a New Game

We create a fresh instance of our Game class, which represents a new game where nobody has made any moves yet.


    game = Game()
        

Visualizing the Game

The draw function displays the game board and the moves of both the player and the AI on the screen.


    def draw():
        screen.clear()
        for x in range(1, 3):
            screen.draw.line((TILE_SIZE * x, 0), (TILE_SIZE * x, HEIGHT), 'white')
            screen.draw.line((0, TILE_SIZE * x), (WIDTH, TILE_SIZE * x), 'white')
        
        for y in range(3):
            for x in range(3):
                if game.board[y][x] == 'X':
                    draw_x(x, y)
                elif game.board[y][x] == 'O':
                    draw_o(x, y)
        

The draw_x(x, y) Function

This function draws an "X" on the Tic Tac Toe board.

Parameters: It takes in x and y which indicate the column and row numbers of the cell where the "X" should be drawn.

Functionality: The function utilizes the screen.draw.line method twice to create two lines in the shape of an "X". These lines stretch diagonally from one corner of the cell to its opposite counterpart.


        def draw_x(x, y):
            screen.draw.line((x * TILE_SIZE, y * TILE_SIZE),
                             ((x + 1) * TILE_SIZE, (y + 1) * TILE_SIZE), 'red')
            screen.draw.line(((x + 1) * TILE_SIZE, y * TILE_SIZE),
                             (x * TILE_SIZE, (y + 1) * TILE_SIZE), 'red')
        

The draw_o(x, y) Function

This function is designated for drawing an "O" on the Tic Tac Toe board.

Parameters: Similar to draw_x, it requires x and y, which specify the column and row of the cell where the "O" should be positioned.

Functionality: The function harnesses the screen.draw.circle method to design a circle in the center of the designated cell, symbolizing the "O". The circle's radius is set to be one-third of the tile's size, ensuring it snugly fits within the cell, avoiding the edges.


        def draw_o(x, y):
            screen.draw.circle((x * TILE_SIZE + TILE_SIZE // 2, y * TILE_SIZE + TILE_SIZE // 2), 
                                TILE_SIZE // 3, 'blue')
        

Responding to Player Clicks

When the player clicks on a spot, this function determines where they clicked and registers the move for them.


    def on_mouse_down(pos):
        if game.current_turn == game.player:
            x, y = pos[0] // TILE_SIZE, pos[1] // TILE_SIZE
            game.player_move(x, y)
        

Launching the Game

To kick off our game, we'll use the pgzrun.go() function.


    pgzrun.go()
        

Copyright © KX Technology Group, LLC. All Rights Reserved.