Day 19: A Tic Tac Toe Game In Python

Welcome to the Day Nineteen of my 21-day project series!

Today I’ll make A Tic Tac Toe Game In Python that has nothing special.

Cause it’s already very special. All of us have played it in the most boring lectures in our school and college.

I am super Excited!! Are you??

Do read the experience

Project Contents

This mini project is called Tic Tac Toe Game In Python.

If you don’t know what’s tic tac toe. Go play it…

It is a two-player game that continues until one player wins or the game ends in a tie.

It’s a text-based game. And is implemented using a Numpy array(ndarray).

It uses basic OOP concepts. And it could have been divided into three parts but right now there are just two.

Tell me what should I improve in this.

I wouldn’t get into the step-by-step explanation of the code as the article becomes super long. (And I guess boring too.)

But I would post an explanatory article for it soon.

Full Source Code

Here’s the full source code of The Tic Tac Toe Game In Python:

import os
import numpy as np

class Game:
    def __init__(self):
        """Initialize a new Tic-Tac-Toe game with an empty game board."""
        self.game_arr = np.array([
                            [" ", " ", " "],
                            [" ", " ", " "],
                            [" ", " ", " "]
                         ])
        
    def update(self, row, column, new_val):
        """
        Update the game board with the player's move at the specified position.

        Parameters:
            row (int): The row index of the move.
            column (int): The column index of the move.
            new_val (str): The value of the player's move ("X" or "O").

        Raises:
            ValueError: If the new_val is not a valid move ("X" or "O").
        """
        valid = ["X", "x", "O", "o"]
        if new_val in valid:
            self.game_arr[row][column] = new_val
            self.make_grid(self.game_arr)
        else:
            print("Invalid Value!!")

    
    def make_grid(self,arr):
        """
        Display the current Tic-Tac-Toe game board.

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.
        """
        print(f"""
{arr[0][0]} | {arr[0][1]} | {arr[0][2]}
----------
{arr[1][0]} | {arr[1][1]} | {arr[1][2]}
----------
{arr[2][0]} | {arr[2][1]} | {arr[2][2]}
""")

    def get_current_game(self):
        """
        Get the current state of the Tic-Tac-Toe game board.

        Returns:
            numpy.array: The 3x3 numpy array representing the game board.
        """
        return self.game_arr 
      
    def check_win(self, arr):
        """
        Check if there is a winning combination on the game board.

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.

        Returns:
            list or False: If there is a winning combination, returns [True, "X"/"O"].
                           Otherwise, returns False.
        """
        res_r = self.check_row(arr)
        if not res_r:
            res_c = self.check_col(arr)
            if not res_c:
                res_d = self.check_diag(arr)
                if not res_d:
                    return False
                else:
                    return [True,res_d[1]]
            else:
                return [True,res_c[1]]
        else:
            return [True,res_r[1]]

    
    def check_row(self, arr):
        """
        Check if any row on the game board has a winning combination.

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.

        Returns:
            list or False: If there is a winning row, returns [True, "X"/"O"].
                           Otherwise, returns False.
        """
        # This shouldn't be hard-coded, but
        # I am doing it to save time
        for i in arr:
            if i[0] == i[1] == i[2] != " ":
                return [True,i[0]]
        return False
        
    def check_col(self, arr):
        """
        Check if any column on the game board has a winning combination.

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.

        Returns:
            list or False: If there is a winning column, returns [True, "X"/"O"].
                           Otherwise, returns False.
        """
        # This shouldn't be hard-coded, but
        # I am doing it to save time
        for i in range(3):  # Assuming it's a 3x3 grid
            if arr[0][i] == arr[1][i] == arr[2][i] != " ":
                return [True, arr[0][i]]
        return False
    
    def check_diag(self, arr):
        """
        Check if any diagonal on the game board has a winning combination.

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.

        Returns:
            list or False: If there is a winning diagonal, returns [True, "X"/"O"].
                           Otherwise, returns False.
        """
        # This shouldn't be hard-coded, but
        # I am doing it to save time
        if arr[0][0] == arr[1][1] == arr[2][2] != " ":
            return [True,arr[0][0]]
        elif arr[0][2] == arr[1][1] == arr[2][0] != " ":
            return [True,arr[0][2]]
        else:
            return False
        
    def check_tie(self, arr) -> bool:
        """
        Check if the game has ended in a tie (draw).

        Parameters:
            arr (numpy.array): The 3x3 numpy array representing the game board.

        Returns:
            bool: True if the game is a tie, False otherwise.
        """
        if " " in arr:
            return False
        else:
            return True
        
    def game_details(self):
        print("Enter your choice according to this: ")
        print("1. Top Left")
        print("2. Top Center")
        print("3. Top Right")
        print("4. Center Left")
        print("5. Center Center")
        print("6. Center Right")
        print("7. Bottom Left")
        print("8. Bottom Center")
        print("9. Bottom Right")


        
g = Game()
win = False
map_dict = {
            1:[0,0], 2:[0,1], 3:[0,2],
            4:[1,0], 5:[1,1], 6:[1,2],
            7:[2,0], 8:[2,1], 9:[2,2],
        }
players = {"O":"Player1", "X":"Player2"}
choices = []

while not win:
    g.game_details()
    g.make_grid(g.get_current_game())
    # getting input from player 1
    player1 = int(input("Player 1 Enter the Choice(1-9): "))
    # Checking if it's already taken
    while player1 in choices:
        print("Make another choice! It's already Taken!")
        player1 = int(input("Player 2 Enter the Choice(1-9): "))
    # updating according to the player1's choice
    g.update(map_dict[player1][0], map_dict[player1][1], "O")
    # Checking for tie
    if g.check_tie(g.get_current_game()):
        os.system('cls' if os.name == 'nt' else 'clear')
        g.make_grid(g.get_current_game())
        print("It's a tie!")
        break
    # checking if player 1 won
    check = g.check_win(g.get_current_game())
    try:
        if check[0]==True:
            os.system('cls' if os.name == 'nt' else 'clear')
            g.make_grid(g.get_current_game())
            print(f"{players[check[1]]} wins")
            win=True
            break
    except Exception:
        pass

    g.make_grid(g.get_current_game())
    choices.append(player1)
    # getting input from player 2
    player2 = int(input("Player 2 Enter the Choice(1-9): "))
    # Checking if it's already taken
    while player2 in choices:
        print("Make another choice! It's already Taken!")
        player2 = int(input("Player 2 Enter the Choice(1-9): "))
    # updating according to the player2's choice
    g.update(map_dict[player2][0], map_dict[player2][1], "X")
    # Checking for tie
    if g.check_tie(g.get_current_game()):
        os.system('cls' if os.name == 'nt' else 'clear')
        g.make_grid(g.get_current_game())
        print("It's a tie!")
        break
    # checking if player 2 won
    check2 = g.check_win(g.get_current_game())
    try:
        if check2[0]==True:
            os.system('cls' if os.name == 'nt' else 'clear')
            g.make_grid(g.get_current_game())
            print(f"{players[check2[1]]} wins")
            win=True
            break
    except Exception:
        pass
    g.make_grid(g.get_current_game())
    choices.append(player2)

The Tic Tac Toe Game In Python is well documented and well written it would be easy to understand. Here are the links to topics within the mini-project.

You can check them if you have any doubts or confusion:

Possible Improvements (That I’ll add after 21 days)

  1. Code Modularizing
  2. Improved AI Opponent
  3. GUI Interface
  4. Multiple Game Modes
  5. Undo/Redo Moves
  6. Game Replay

And a lot more…

Experience of the day

In case you don’t know this project is a part of the brand new series that I have started. #21days21projects in python. To read more about it you can check out this page.

And for those who already know here’s my experience of the day.

Another great day!

You won’t believe that despite being a programmer for so long I have never ever made this basic project before.

Like seriously, I always avoided it. Cause I thought I would somehow fail to do this.

But I faced it too. Was a very nice experience. I first time took pen and paper to first draw up the logic because I was so scared.

And I learned that it is a good practice and I should do it for all my projects or problems. It’s much faster and clearer with it.

Do let me know whether you liked this Tic Tac Toe Game In Python. Also, let me know if there are any suggestions.

And most importantly how was your DAY 19?

Insightful?

Well, I hope it was fun. And remember it’s perfectly awesome if you missed out. Continue to work from tomorrow.

And today just write one line of code as simple as making a variable or printing something.

Your suggestions are welcomed!

Happy coding…

And wait, if you have some ideas for the upcoming projects do let me know that too. Even when the series ends do let me know what you like…

Leave a Reply

This Post Has 2 Comments

  1. hello!,I really like your writing so much! share we communicate more about your post on AOL? I require a specialist in this area to resolve my problem. Maybe that’s you! Looking ahead to see you.