Creating a Two-Player Tic-Tac-Toe Game with Python

In this tutorial, we will look at one of the ways to make the classic two-player game Tic-Tac-Toe using Python. The Python concepts that we will use in this game are: strings, loops, conditional(If/else) statements, lists, dictionaries, and functions. We will also make use of the time module.

Step 1 – Initializing the Board

First we will import the time module. The sleep() method from the time module will be used to introduce delays where needed. Next, we will create a dictionary with numbers from 1 to 9 as keys and empty strings as values to initialize our Tic-Tac-Toe board.

import time
board = { 1 : ' ', 2 : ' ', 3: ' ',
   4 : ' ', 5 : ' ', 6 : ' ', 
   7 : ' ', 8 : ' ', 9 : ' ‘}
Step 2 – Initializing Variables

Next we will initialize the variables which we will use to keep track of the player details and game status in the program.

# Initialize variables
count = 0			# counter to track number of filled slots
winner = False		        # boolean to check if anyone won
play = True			# boolen to check if the game should continue
tie = False			# boolean to check if there is a tie
curr_player = ''		# variable to store current player identifier
player_details = []		# list to store player identifier and marker
Step 3 – Game Loop

Our next step will be to start the game loop. We will achieve that using d, which is a forever loop. Our entire game logic will exist inside this loop.

while play:
	[execute game code]

We will use several helper functions to perform repetitive actions in the program. These functions will be written outside of our game loop and invoked inside the game loop.

Step 4 – Creating a Function to Print the Tic-Tac-Toe Board 

We will create a helper function called print_board() to print the board dictionary representing the Tic-Tac-Toe board in a 3 X 3 matrix. We will use a for-in loop to iterate through the dictionary and print the board as needed. While using the print function inside the for loop, we can access the keys of our dictionary with the loop variable i and the corresponding values using these keys (syntax: board[i]). We make use of the end=“ “  parameter to print the board horizontally. To break it into a 3 X 3 matrix, we will use an if condition that checks each key in the dictionary. If the key turns out to be a multiple of 3, we use print() to force the next key to be printed in a new line.

def printBoard():
  for i in board:
   print( i, ':', board[i], ' ', end="")
   if i%3 == 0:
    print()

We will start the game by invoking the print_board() function from the game loop.

while play:
  print_board()
Step 5 – Accepting Input from our Players

We will be using identifiers ‘A‘ and ‘B‘ to identify the two players and ‘X‘ and ‘O‘ as the corresponding markers. The markers will be used to mark the slot chosen by the players on the game board. We will create another helper function called get_player_details(). This function will accept the identifier of the current player as a parameter and return a list containing the identifier and marker for the other player.  

def get_player_details(curr_player):
  if curr_player == 'A':
   return ['B','O']
  else:
   return ['A','X']

After printing the game board, we will invoke the get_player_details() function to get the details for the first player. Note that the curr_player variable is blank at this point. As a result, the function will return ‘A‘ and ‘X‘ as list values. The first player will thus be assigned the identifier ‘A‘ and the marker ‘X‘. The variable curr_player will also be initialized with the first element from the list so that the function can return the correct values when invoked again.

player_details = get_player_details(curr_player)
curr_player = player_details[0]

Next, we will prompt the first player to choose a number(slot) on the board for their marker.

print("Player {}: Enter a number between 1 and 9".format(curr_player))
input_slot = int(input())

We are using the input() function to store the input from the player in a variable called input_slot. Since input() function always returns a string, we will have to convert the user input to a number using the int() function and then store it in our input_slot variable.

Step 6 – Putting a Marker in the Desired Position

In this step, we will update the board with the user input.  

insert_input(input_slot, player_details[1])

To achieve this, we will create a helper function called insert_input(). This function takes two parameters: slot_num which is the slot chosen by the player, and the player’s marker.

This function also checks if the desired slot is available and uses a while loop to keep prompting until the user chooses an available slot. The slot_num corresponds to the keys in the dictionary representing the board. A slot is deemed available if the corresponding value in the board dictionary is empty. The value is set to the marker once an available slot is found.

 def insert_input(slot_num, marker):
     while board[slot_num] != ' ':
        print("spot taken, pick another no.")
        slot_num = int(input())
     board[slot_num] = marker
Step 7 – Win Logic

After each user input, we will check if any player won. The variable winner will be set to True or False depending on whether or not anyone wins.

winner = win_game(player_details[1], curr_player)

To achieve this, we will use a helper function called win_game(). The function accepts two parameters: the player’s marker and identifier.

We will use the function to check all possible winning combinations (vertically, horizontally and diagonally) and determine if the values (markers) are the same (either all ‘X’s or all ‘O’s). On finding a winning combination we will first print the board to show the final layout. We will then use the sleep() function from the time module to pause for a second and then print who won.

def win_game(marker, player_id):
    if board[1] == marker and board[2] == marker and board[3] == marker or \
    board[4] == marker and board[5] == marker and board[6] == marker or \
    board[7] == marker and board[8] == marker and board[9] == marker or \
    board[1] == marker and board[4] == marker and board[7] == marker or \
    board[2] == marker and board[5] == marker and board[8] == marker or \
    board[3] == marker and board[6] == marker and board[9] == marker or \
    board[1] == marker and board[5] == marker and board[9] == marker or \
    board[3] == marker and board[5] == marker and board[7] == marker:

        print_board()
        time.sleep(1)
        print("Player", player_id, "wins!")
        return True

    else:
        return False
Step 8 – Tie Logic

Next we will add the logic to handle a tie. The game is tied when there is no winner even after all the spots on the board have been filled. To determine a tie, we will have to keep track of the number of spots filled. We will use a variable called count for this and increment its value by 1 after each move. 

count += 1

We check the variables count and winner after each move. If all the slots have been filled (count = 9) and there is no winner (winner = False), we declare the game to be a tie. We then set the variable tie to True and print the board to show the final layout.

if count == 9 and not winner:
        print("It's a tie!!")
        tie = True
        print_board()
Step 9 – Play Again Logic

Once we either have a winner or a tied game, we should check if the players want to play again. The variable play will be set to True or False depending on whether or not the players choose to play again. The count and current player variables will be reset if the players choose to play again.

if winner or tie:
        play = play_again()
	if play:
            curr_player = ''
            count = 0

We will create a helper function called play_again() to capture user input and take action. When executed, this function will ask the player if they want to play again. If the players wish to play again, the board is reset and the function returns True. Otherwise, the function prints a ‘Thank You‘ message and returns False.

def play_again():
    print("Do you want to play again?")
    play_again = input()

    if play_again.upper() == 'Y':
        for z in board:
            board[z] = ' '
        return True
    else:
        print("Thanks for playing. See you next time!")
        return False
The Complete Code

Here is the complete code for the Two-Player Tic-Tac-Toe game. Do give it a try.

import time

# Initialize board
board = { 1 : ' ', 2 : ' ', 3: ' ',
         4 : ' ', 5 : ' ', 6 : ' ', 
         7 : ' ', 8 : ' ', 9 : ' '}

# Initialize variables
count = 0		# counter to track number of filled slots
winner = False		# boolean to check if anyone won
play = True		# boolen to check if the game should continue
tie = False		# boolean to check if there is a tie
curr_player = ''	# variable to store current player identifier
player_details = []	# list to store player identifier and marker

# Helper functions
def get_player_details(curr_player):
    """Function to get player identifier and marker"""
    if curr_player == 'A':
        return ['B','O']
    else:
        return ['A','X']
    

def print_board():
    """Function to print the board"""
    for i in board:
        print( i, ':', board[i], ' ', end='')
        if i%3 == 0:
            print()


def win_game(marker, player_id):
    """Function to check for winning combination"""
    if board[1] == marker and board[2] == marker and board[3] == marker or \
    board[4] == marker and board[5] == marker and board[6] == marker or \
    board[7] == marker and board[8] == marker and board[9] == marker or \
    board[1] == marker and board[4] == marker and board[7] == marker or \
    board[2] == marker and board[5] == marker and board[8] == marker or \
    board[3] == marker and board[6] == marker and board[9] == marker or \
    board[1] == marker and board[5] == marker and board[9] == marker or \
    board[3] == marker and board[5] == marker and board[7] == marker:

        print_board()
        time.sleep(1)
        print("Player", player_id, "wins!")
        return True

    else:
        return False


def insert_input(slot_num, marker):
    """Function for capturing user inputs"""
    while board[slot_num] != ' ':
        print("spot taken, pick another no.")
        slot_num = int(input())
    board[slot_num] = marker

def play_again():
    """Function to check if player wants to play again"""
    print("Do you want to play again?")
    play_again = input()

    if play_again.upper() == 'Y':
        for z in board:
            board[z] = ' '
        return True
    else:
        print("Thanks for playing. See you next time!")
        return False
    
# Main program
while play:

    print_board()

    player_details = get_player_details(curr_player)
    curr_player = player_details[0]
    print("Player {}: Enter a number between 1 and 9".format(curr_player))
    input_slot = int(input())

    #Inserting 'X' or 'O' in desired spot
    insert_input(input_slot, player_details[1])
    count += 1
    
    # Check if anybody won
    winner = win_game(player_details[1], curr_player)
    if count == 9 and not winner:
        print("It's a tie!!")
        tie = True
        print_board()

    # Check if players want to play again
    if winner or tie:
        play = play_again()
        if play:
            curr_player = ''
            count = 0

Related Posts