How to build a Tic Tac Toe Game in Python

In this tutorial, you will learn how to build the classic Tic Tac Toe game using Python and Visual Studio Code.

Project goalGet started with Python by creating a player vs computer Tic Tac Toe game
What you’ll learnFunctions, input() and randrange() functions, while and for loops, if-statement
Tools you’ll needPython 3, Visual Studio Code and Python extension for Visual Studio Code
Time needed to complete60 minutes

Prerequisite

To complete the exercise, you will need to install:

  • Python 3
  • Visual Studio Code or other code editor

If you need help with installing these tools, follow the instructions in the Microsoft Learn Module Set up your Python beginner development environment with Visual Studio Code.

Instructions

Open Visual Studio Code and create a new file named tic-tac-toe.py.

Creating the board

You are going to create the board of the game. Firstly, define the main() function, which will contain all the game’s code.

1
2
3
def main():
    pass
main()

Inside the main() function, create a two-dimensional list that represents the board of the game.

1
2
3
4
5
board = [
    [" ", " ", " "],
    [" ", " ", " "],
    [" ", " ", " "]
]

Then create the function print_board() that takes as argument the board of the game and prints it. The rows and the columns of the board are numbered from 1 to 3. We will use the print_board() function to print the board in every round.

1
2
3
4
5
6
7
def print_board(board):
    print("\n    1   2   3 \n")
    print("1   " + board[0][0] + " | " + board[0][1] + " | " + board[0][2])
    print("   ---+---+---")
    print("2   " + board[1][0] + " | " + board[1][1] + " | " + board[1][2])
    print("   ---+---+---")
    print("3   " + board[2][0] + " | " + board[2][1] + " | " + board[2][2] + "\n")

Creating the players

The game has 2 players:

  • the player who uses the “X” symbol and
  • the random player (computer) who uses the “O” symbol.

Create a variable named turn to store the number of the current player. Player “X” plays first.

1
2
3
4
# Create 2 players
players = ["X", "O"]
# Player X plays first
turn = 0

The game ends when the board is full. Therefore, use a while loop with a condition not is_board_full(board) to simulate the game.

1
2
while not is_board_full(board):
    pass

where the is_board_full() function takes as argument the board of the game and checks if the board has empty squares. If the board contains empty squares, the function returns False.

1
2
3
4
5
def is_board_full(board):
    for item in board:
        if " " in item:
            return False
    return True
With the while loop you can repeat a set of instructions as long as a condition is true. You can also use the else statement to run code when the condition becomes false.

Use the else keyword to print the board of the game and the message “It’s a tie!” at the end of the game.

1
2
3
4
5
while not is_board_full(board):
    pass
else:
    print_board(board)
    print("It's a tie!")

In the next sections, you will learn how to check if a player won and end the game (the while loop) using the break statement.

Inside the while loop, the flow of the game will look like this:

  • Use the print_board() function to print the board of the game.
  • Simulate a player’s move and update the board.
    • If the value of the turn variable is 0, the classic player plays.
    • If the value of the turn variable is 1, computer plays.
  • Check if a player won and end the game.
  • Select the next player.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
while not is_board_full(board):
    print_board(board)
    if turn == 0:
        # User plays
        pass
    else:
        # Computer plays
        pass
        
    # Check if the player won
       
    # Select the next player
    turn = 1 - turn
else:
    print_board(board)
    print("It's a tie!")

Creating the classic player

Define the function play() with the board as argument. This function takes as input from the player the row and the column number and check if their move is valid.

  • If the row and column numbers are not in the range of 1 to 3, print an appropriate message and then use the input() function to get new input from the player.
  • If the row and column numbers are valid but the square of the board is not empty, print an appropriate message and repeat the above process.
  • Lastly, if the player chooses a valid square, return the row and column numbers.
To receive information from the user through the keyboard, you can use the input() function. The input() function has an optional parameter, known as prompt, which is a string that will be printed before the input.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def play(board):
    while True:
        row = input("Enter row number: ")
        while not row.isdigit() or int(row) < 1 or int(row) > 3:
            row = input("Enter row number between 1-3: ")
        row = int(row)
        col = input("Enter column number: ")
        while not col.isdigit() or int(col) < 1 or int(col) > 3:
            col = input("Enter column number between 1-3: ")
        col = int(col)
        if board[row-1][col-1] != " ":
            print("Pick an empty box!")
        else:
            return (row-1, col-1)

In the main() function, call the play() function to get the row and column numbers and then update the board of the game.

1
2
row, col = play(board)
board[row][col] = players[turn]

Creating the random player (computer)

Define the function play_random() with the board as argument. This function finds all the possible moves (the squares of the board that are empty) and stores the row and the column numbers of the valid squares in the list possible_moves. Then it randomly selects one of the valid squares and returns the row and column numbers of the selected square.

Use the command:

1
random.randrange(len(possible_moves))

to generate a random number in the range of 0 (included) to len(possible_moves) (not included), where len(possible_moves) is the length of the list possible_moves.

Then use this number to select the corresponding list item:

1
possible_moves[random.randrange(len(possible_moves))]

and return it.

1
2
3
4
5
6
7
8
def play_random(board):
    possible_moves = []
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == " ":
                possible_moves.append((row, col))
    
    return possible_moves[random.randrange(len(possible_moves))]

In short, the randrange() function returns a randomly selected number from a specified range. We can use two parameters to specify the lower and higher limit. For example, randrange(1, 10) will return a number between 1 (included) and 10 (not included) and randrange(10) will return a number between 0 (included) and 10 (not included).

In order to use the randrange() function you should add the following lines of code at the beginning of your program:

1
2
3
import random
from datetime import datetime
random.seed(datetime.now())

In the main() function, call the play_random() function to get the random row and column numbers and then update the board of the game.

1
2
row, col = play_random(board)
board[row][col] = players[turn]

Finding the winner

The last step of the game is to find the player that won. A player wins, if they succeed in placing three of their marks in a diagonal, horizontal, or vertical row.

Firstly, define the function check_winner(), which takes as argument the board of the game and uses the functions check_row(), check_column(), check_diagonals() to determine if a player won.

1
2
3
4
5
6
7
8
9
def check_winner(board):
    for i in range(3):
        if check_row(board, i):
            return True
        if check_column(board, i):
            return True
    if check_diagonals(board):
        return True
    return False

The check_row() function takes as arguments the board of the game and the number of the board’s row and returns True if a player has placed three of their marks in the selected row.

1
2
def check_row(board, row):
    return (board[row][0] == board[row][1] and board[row][1] == board[row][2] and board[row][0] != " ")

The check_column() function takes as arguments the board of the game and the number of the board’s column and returns True if a player has placed three of their marks in the selected column.

1
2
def check_column(board, col):
    return (board[0][col] == board[1][col] and board[1][col] == board[2][col] and board[0][col] != " ")

Lastly, the check_diagonals() function takes as argument the board of the game and returns True if a player has placed three of their marks in a diagonal.

1
2
3
def check_diagonals(board):
    return (board[0][0] == board[1][1] and board[1][1] == board[2][2] and board[0][0] != " ") or\
            (board[2][0] == board[1][1] and board[1][1] == board[0][2] and board[2][0] != " ")

In the main() function, inside the while loop, use the check_winner() function to check if a player wins. If a player wins, print the board of the game and an appropriate message and then use the break statement to end the game.

1
2
3
4
if check_winner(board):
    print_board(board)
    print("You won!" if turn == 0 else "Computer won!")
    break

Congratulations! You’ve made it! You have developed a Tic Tac Toe game in Python.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import random
from datetime import datetime
def print_board(board):
    print("\n    1   2   3 \n")
    print("1   " + board[0][0] + " | " + board[0][1] + " | " + board[0][2])
    print("   ---+---+---")
    print("2   " + board[1][0] + " | " + board[1][1] + " | " + board[1][2])
    print("   ---+---+---")
    print("3   " + board[2][0] + " | " + board[2][1] + " | " + board[2][2] + "\n")
def check_row(board, row):
    return (board[row][0] == board[row][1] and board[row][1] == board[row][2] and board[row][0] != " ")
def check_column(board, col):
    return (board[0][col] == board[1][col] and board[1][col] == board[2][col] and board[0][col] != " ")
def check_diagonals(board):
    return (board[0][0] == board[1][1] and board[1][1] == board[2][2] and board[0][0] != " ") or\
            (board[2][0] == board[1][1] and board[1][1] == board[0][2] and board[2][0] != " ")
def check_winner(board):
    for i in range(3):
        if check_row(board, i):
            return True
        if check_column(board, i):
            return True
    if check_diagonals(board):
        return True
    return False
def is_board_full(board):
    for item in board:
        if " " in item:
            return False
    return True
def play(board):
    while True:
        row = input("Enter row number: ")
        while not row.isdigit() or int(row) < 1 or int(row) > 3:
            row = input("Enter row number between 1-3: ")
        row = int(row)
        col = input("Enter column number: ")
        while not col.isdigit() or int(col) < 1 or int(col) > 3:
            col = input("Enter column number between 1-3: ")
        col = int(col)
        if board[row-1][col-1] != " ":
            print("Pick an empty box!")
        else:
            return (row-1, col-1)
def play_random(board):
    possible_moves = []
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == " ":
                possible_moves.append((row, col))
    
    return possible_moves[random.randrange(len(possible_moves))]
def main():
    random.seed(datetime.now())
    print("\n== Tic Tac Toe ==")
    # Create an empty board
    board = [ 
        [" ", " ", " "],
        [" ", " ", " "],
        [" ", " ", " "]
    ]
    # Create 2 players
    players = ["X", "O"]
    # Player X plays first
    turn = 0
    while not is_board_full(board):
        print_board(board)
        if turn == 0:
            # User input
            print("You play!")
            row, col = play(board)
            board[row][col] = players[turn]
            
        else:
            # Compuuter plays
            print("Computer plays!")
            row, col = play_random(board)
            board[row][col] = players[turn]
        # Check if the player won
        if check_winner(board):
            print_board(board)
            print("You won!" if turn == 0 else "Computer won!")
            break
        
        # Select the next player
        turn = 1 - turn
    
    else:
        print_board(board)
        print("It's a tie!")
main()

You May Also Like