Game of Tic-Tac-Toe with Python

coconutShark
Analytics Vidhya
Published in
8 min readMar 28, 2021

Tic-Tac-Toe! A familiar game to all of us and a very simple one to play. But how difficult is it to create a Tic-Tac-Toe in Python? Well! its pretty simple. A game of Tic-Tac-Toe can be created using basic python programming language. Here, in this article I will walkthrough steps to create your own Tic-Tac-Toe game in python.

Source Code: https://github.com/pujesh/TicTacToe

To start with, let me present you with my file structure.

Fig: Folder Structure

Here, we have the main project as TicTacToe and under the src directory, I have created 4 modules. Our program starts off with the main.py which lets a player choose between X and O and displays the initial board. It then calls the user_interact() function from the interact.py module. The interact module is used to interact with the players and gets the position in the board for every move. This is where most of the work happens. The module prints out every time the user provides an input with the updated board and checks whether the provided position is available or not by the check_position() function in check.py module. The board is updated by calling the update_board() and displays the updated board by invoking the display_board() function from the board.py module. The program starts checking for possible win after the 4th entry by the user, by calling the check_result() function from the check module. If the check_result function finds a winner, it announces a winner and displays the board by crossing all the three positions. The cross marks on the board are executed through the cross_board() function from the board module.

That was just an overview on how the overall program functions. Lets, get into more details about each module, starting with main.py.

Fig: main.py

main.py:

The main module is a starting point of our program and we start with welcoming the players and letting Player 1 choose either X or O. Once, the user provides with the option, it displays the initial board and calls the user_interact() function.

Fig: main.py output

The figure above is the output obtain from the main.py module. The highlighted part in the figure shows the step where the program asks for the user’s input. Once the user provides ‘X’ then the program displays the Tic-Tac-Toe board. We can see that there are two boards that is being displayed. This is because, the board on the left displays the available position for the user to pick and the board on the right displays once the user enters a position in the board. Now let us see what the user_interact() function does after it is being invoked by the main module.

interact.py

The interact.py contains only one function (user_interact()) and I will be describing it in two parts.
The first part:

Fig: interact.py (a)

The first part contains only the import and the initialization statements. Here, we initialize a position board (pos_board) where the players can view the available positions in the board and game board (game_board) where all the fields are initially blank. Then, each player is assigned with a symbol ‘X’ or ‘O’ depending on the choice made by the Player 1. We have also assigned False to game which will denote that the program needs to loop until the game is over. The variable turn denotes the number of turn/times the loop has executed.
The second part:

Fig: interact.py (b)

Now, the main logic starts from the second part of this module. We know there are only two players and the game finishes in 9 moves, thus, we will run a loop until it loops 9 times or when the game finds a winner. Every time, it asks players to pick a position that are available in the position board. A player can pick a position by choosing a number from 1 to 9 and a number that is available in the position board. If the number is out of range or is an alphabet or if the player chooses a number not listed in the position board, we ask the player to re-enter the number. This is done by the check_position() function. For example:

Fig: Player 1 chose position 6

Here, we can see that Player 1 chooses position 6 which is under the range and available in the position board. Thus the program takes the input and prints out the updated board. It removes the position from the position board (board on the left) and inserts a ‘X’ mark on the game board (board on the right).

Fig: Player 2 chose wrong position

Now, when Player 2 tries to choose position 6 which was chosen by Player 1, the program informs the user that the position is already filled. On the second try, the Player 2 tries to pick number 10 which is not present in the position table and similarly when Player 2 tries to pick an alphabet, the game repeatedly asks for a valid position and does not move forward until it gets one.
After every input, the program updates the position/game board with the ‘X’ or ‘O’ mark and displays output with the updated boards.
Since, we know the game can only find a winner on or after the 4th turn, this is when we start checking for a winner after the variable ‘turn’ is greater or equal to 4. We do this by calling the check_result() function. The function returns a True value and a game board with the row/column/diagonal crossed out when a winning criteria is met. When the game has a winner, it displays the board and ends the loop by updating the variable ‘game’ with True. If the winning criteria is not met, the game continues until it ends in a draw.
This is the overall flow of the interact module. It enters a loop until the game finds a winner or ends in a draw.

Fig: End of the game with a winner

In the above figure, we can see that the Player 1 has won the game and the position 3, 6 and 9 are crossed out. In the case of draw, we can see an output in the following way:

Fig: End of the game with a draw

check.py

Fig: check.py

So, here we have the check.py module, which is mostly used to check the available positions and the result. We can see the check_position() function being called everytime the player enters a position. This makes sure that the position provided by the player is valid and available. The function returns True if the position is available else the function returns False.

The other function defined in the module is the check_result() function. This function is used to check if the game is won or drawn after the player choses a position. Since, the game can be own only after the 4th run, we also have added the function to check after the turn is greater than 4. You can see this in the interact.py module above (Fig: interact.py (b), line 35 & 36).
We have defined a tuple named moves which consists all the possible combination of the position in the board to win a game. Then we run a loop and check if any position in the board with the mentioned moves has the same symbol (‘X’ or ‘O’). If we find any position in any of the moves with all of the same symbol, we declare a winner of the game else the game continues until all the positions are filled and the game ends in a draw.

board.py

The last module we have to create is the board.py module. This module deals with the display, update and crossing out the position on the board.

Fig: board.py (a)

Here, we have two functions — display_board() and update_board(). The function display_board() as the name suggest displays the board. The function takes in two parameters — pos_board (the position board — to display the available positions in the board) and game_board (the game board — where the X and O are displayed). Every time the board is displayed, two boards are being displayed as we have seen above. One shows the available position on the board (position board) where as the other one (game board) shows the position that the players have already filled. The parameter pos_board, game_board we obtain are always updated after every turn. These boards are updated from the update_board() function.
The update_board() function takes four parameters — pos_board, game_board, n (the position to update) and mark (the mark ‘X’ or ‘O’ to be filled in the n-th position. Once the function is called, it starts to loop inside the position board and remove the position number once the n-th position value matches the position number in the position board. Here, since we have implemented the position board and game board differently, the game board is updated with the mark by one single line of code (Fig: board.py (a), line 21).
NOTE: We can see it is easier to implement the way we have defined game_board. We could do this for the pos_board as well and remove the extra line of codes.

Fig: board.py (b)
Fig: board.py (b)

The other part of the board.py module consists of the cross_board function. Once we confirm that the game is over and won by one of the player (when we get True value from the check_result() function in check.py module), we call this function to cross out the position that has won the game. We use ‘-’, ‘|’, ‘/’ and ‘\’ symbols to cross out the position based on the moves.

Fig: Position 1, 2 and 3 are crossed out with ‘-’ as to mark the game was won.
Fig: Another example of game being won when position 1, 5 and 9 being filled with ‘O’ mark but is crossed out by ‘\’ mark.

So, this sums up on the python programming to create a Tic-Tac-Toe. There are different approaches that can be used to achieve the goal. I would like you to try out your approach and let me know if I could do anything better optimized way. It is all about optimizing our code and redundancy. Hope you liked my post about the Tic-Tac-Toe game using python.

Dhanyabaad!! 🙏🏼

--

--