Tic-tac-toe is a classic game that has entertained people for generations. While it may seem simple on the surface, it can be a challenging and fun game to play with others.
In this article, we will walk you through the process of setting up a tic-tac-toe game board with Tkinter and setting up tic-tac-toe game logic in Python.
Setting Up Tic-Tac-Toe Game Board with Tkinter
Tkinter is a Python library used to create graphical user interfaces. It provides a wide variety of tools to create windows, buttons, text fields, and other graphical elements.
The first step towards setting up a tic-tac-toe game board is creating the game board with Tkinter. We begin by importing the tkinter library in Python:
import tkinter as tk
Next, we create a window to hold the game board with the following code:
window = tk.Tk()
window.title("Tic Tac Toe")
The above code creates a window and sets its title to “Tic Tac Toe”. We can customize the window’s dimensions using the geometry()
method.
window.geometry("300x300")
This code sets the window’s width and height to 300 pixels. We can now create a 3×3 playing grid by using a combination of Frame
and Label
objects.
board = tk.Frame(window)
board.grid()
for i in range(3):
for j in range(3):
cell = tk.Label(board, width=10, height=5, relief='sunken')
cell.grid(row=i, column=j)
The Frame
object creates a group of widgets, which can make it easier to manage and manipulate the game board. The nested for
loop creates 9 Label
objects, representing the 9 cells of the game board.
The width
and height
parameters give the cells their dimensions. The relief
parameter sets the border style for each cell.
Placing the game board on the screen
We have created a game board, but it is not yet visible on the screen. We need to call the mainloop()
method to activate the window, which we can do by adding this code at the end of our program:
window.mainloop()
This code runs the Tkinter event loop, which enables us to interact with the game board.
Once we run the program, the game board should appear on the screen.
Setting Up Tic-Tac-Toe Game Logic in Python
The next step is to set up the game logic in Python. To do this, we need to define classes for players and their moves, create a class to represent game logic, set up the abstract game board, and figure out the winning combinations.
Defining classes for players and their moves
We can create a class for each player, which will store their name and the cells they have marked on the game board.
class Player:
def __init__(self, name, symbol):
self.name = name
self.symbol = symbol
self.moves = []
def mark_cell(self, cell):
self.moves.append(cell)
The Player
class has an __init__
method that creates the player’s name, symbol, and an empty moves
list to store the cells they have marked.
The mark_cell
method adds a cell to the player’s moves list when they mark it.
Creating a class to represent game logic
We can create a Game
class to handle the game’s logic. This class will initialize the game board, keep track of player turns, and check for winning combinations.
class Game:
def __init__(self, player1, player2):
self.board = [['' for i in range(3)] for j in range(3)]
self.player1 = player1
self.player2 = player2
self.current_player = player1
def mark_cell(self, row, col):
if self.board[row][col] == '':
self.board[row][col] = self.current_player.symbol
self.current_player.mark_cell((row, col))
self.switch_player()
def switch_player(self):
if self.current_player == self.player1:
self.current_player = self.player2
else:
self.current_player = self.player1
def get_winner(self):
for i in range(3):
if self.board[i][0] == self.board[i][1] == self.board[i][2] != '':
return self.current_player
elif self.board[0][i] == self.board[1][i] == self.board[2][i] != '':
return self.current_player
if self.board[0][0] == self.board[1][1] == self.board[2][2] != '':
return self.current_player
elif self.board[0][2] == self.board[1][1] == self.board[2][0] != '':
return self.current_player
elif all(self.board[i][j] != '' for i in range(3) for j in range(3)):
return 'Draw'
else:
return None
The Game
class initializes the game board as a 3×3 matrix of empty cells and sets the first player to be player1
. The mark_cell
method checks if the selected cell is empty, marks the cell with the current player’s symbol, and updates their moves list.
It then switches the current player to the other player. The get_winner
method checks each row, column, and diagonal to see if there are three matching symbols in a row.
If this condition is met, it returns the current player. If all cells on the board have been marked but there is no winner, it returns “Draw”.
If there is no winner yet, it returns None
.
Setting up the abstract game board
Now that we have set up the game logic, we need to track the moves of each player on the abstract game board. We can do this by creating a 3×3 matrix of tuples representing each cell on the game board.
board = [[(i, j) for j in range(3)] for i in range(3)]
We can use this matrix to map each cell to its corresponding button on the game board.
board_buttons = [[None for j in range(3)] for i in range(3)]
for i in range(3):
for j in range(3):
button = tk.Button(board, text='', font='Arial 30', width=4, height=2,
command=lambda row=i, col=j: self.mark_cell(row, col))
button.grid(row=i, column=j)
board_buttons[i][j] = button
This code creates a Button
object for each cell and maps it to the corresponding cell in the board_buttons
matrix.
The command
parameter specifies what function to call when the button is clicked, which in this case is the mark_cell
method of the Game
class.
Figuring out the winning combinations
The final step is to figure out the winning combinations. We can use the get_winner
method of the Game
class to check if there is a winner after each move.
winner = game.get_winner()
if winner is not None:
if winner == 'Draw':
message = 'It is a draw!'
else:
message = winner.name + ' has won!'
tk.messagebox.showinfo('Game Over', message)
This code checks if there is a winner. If there is a winner, it displays a message box with the winner’s name or “Draw”.
Conclusion
In this article, we have walked you through the process of setting up a tic-tac-toe game board with Tkinter and setting up tic-tac-toe game logic in Python. By following these steps, you can create your own tic-tac-toe game that can be played on your computer.
We hope this article has been informative and that you will enjoy creating and playing your own tic-tac-toe game. In the last section, we covered the initial steps of setting up a tic-tac-toe game board with Tkinter and defining game logic in Python.
In this section, we will be exploring further enhancements to the codebase by defining the TicTacToeBoard class along with added functionality. We will also discuss how to handle player interaction, process player moves, determine the winner, and add logic to handle tie games.
Defining the TicTacToeBoard class
The TicTacToeBoard class is responsible for displaying the game board to the user and updating it with the current state of the game. We will start by defining this class, which will hold an instance of the game board state, an instance of the Game class discussed earlier, and the various visual elements of the game board that will be displayed to the user.
class TicTacToeBoard(Frame):
def __init__(self, master=None):
super().__init__(master)
self.game_state = [[None for _ in range(3)] for _ in range(3)]
self.game = Game()
self.current_player = 1
self.init_ui()
The __init__
method initializes the state of the game with a 3×3 matrix that holds None values, an instance of the Game class, and the current player, which is set to player 1. We call the init_ui
method to display the game board on the screen.
Adding functionality to the TicTacToeBoard class
Now that we’ve defined the TicTacToeBoard class, we’re ready to add functionality to it. This includes handling player interaction, processing player moves, determining the winner of the game, and adding logic to handle tie games.
Creating a method to process player moves
To process player moves, we need to create a method that is triggered when a player clicks a square on the game board. When the player clicks a square, we need to update the state of the game board with the player’s mark and switch turns to the next player.
def process_move(self, row, col):
if self.game_state[row][col]:
return
self.game_state[row][col] = self.current_player
self.game.mark_board(row, col, self.current_player)
self.current_player = 1 if self.current_player == 2 else 2
The code above checks if a square is already marked by a player before marking it with the current player’s mark. It then calls the mark_board
method of the Game
class to update the state of the game and switch turns to the next player.
Determining the winner of the game
To determine the winner of the game, we need to add a method that checks the state of the game board after each move and returns the winner. If there is no winner, it returns None.
def check_winner(self):
winner = self.game.check_winner()
if winner:
tk.messagebox.showinfo('Game Over', f'{winner.name} Wins!!')
return winner.symbol
return None
This code delegates the task of checking the winner to the check_winner
method of the Game
class. If there is a winner, it displays a message box with the winner’s name and returns their symbol.
Otherwise, it returns None.
Adding logic to handle tie games
Finally, we need to add logic to handle tie games. In the case where all squares are marked and no winner is found, the game should display a message box with information that the game is a tie.
def check_tie(self):
if all(all(x for x in row) for row in self.game_state):
tk.messagebox.showinfo('Game Over', 'Tie Game')
return True
return False
This code checks if all squares are marked and no winner is found. If so, it displays a message box with the information that the game is tied.
Putting it all together
Here’s how the updated TicTacToeBoard class looks when all the added functionality is put together:
class TicTacToeBoard(Frame):
def __init__(self, master=None):
super().__init__(master)
self.game_state = [[None for _ in range(3)] for _ in range(3)]
self.game = Game()
self.current_player = 1
self.init_ui()
def init_ui(self):
for i in range(3):
for j in range(3):
btn = Button(self, height=3, width=6)
btn['command'] = lambda row=i, col=j: self.process_move(row, col)
btn.grid(row=i, column=j)
self.game.add_player_mark(i, j, btn)
def process_move(self, row, col):
if self.game_state[row][col]:
return
self.game_state[row][col] = self.current_player
self.game.mark_board(row, col, self.current_player)
self.current_player = 1 if self.current_player == 2 else 2
self.check_winner()
self.check_tie()
def check_winner(self):
winner = self.game.check_winner()
if winner:
tk.messagebox.showinfo('Game Over', f'{winner.name} Wins!!')
return winner.symbol
return None
def check_tie(self):
if all(all(x for x in row) for row in self.game_state):
tk.messagebox.showinfo('Game Over', 'Tie Game')
return True
return False
The init_ui
method is responsible for creating and organizing the button elements in a 3×3 format. We assign a callback function to each button command that calls the process_move
method to mark the selected cell with the current player’s marker.
The check_winner
and check_tie
methods handle the logic for determining a winner or a tie in the game.
Conclusion
In this section, we have added more functionality to the TicTacToeBoard class, including processing player moves, handling the logic for determining a winner or a tie in the game, and extended the game functionality. Together, these functionalities make for a polished and enjoyable Tic Tac Toe game that you can play on your computer.
We hope this article has been insightful and that you will have fun building your own version of this classic game. In the last section, we discussed how to enhance the TicTacToeBoard class to handle player interaction and determine the winner of the game.
In this section, we will explore how to create the game interface with Tkinter, add buttons to the game interface, link the game board to the game interface, and run the Tic-Tac-Toe game.
Creating the game interface with Tkinter
We start by creating a window to hold the game interface with the following code:
class GameInterface(Frame):
def __init__(self):
super().__init__()
self.master.title('Tic Tac Toe')
self.master.resizable(width=True, height=True)
self.pack(fill=BOTH, expand=True)
self.board = TicTacToeBoard(self)
self.board.pack(fill=BOTH, expand=True)
This code creates a window and sets its title to “Tic Tac Toe”. We use the pack()
method to place the TicTacToeBoard object, which is responsible for displaying the game board, within the window.
Adding buttons to the game interface
Next, we add buttons to the game interface to allow the user to reset the game board and exit the game. We can do this by defining two new methods in the GameInterface
class that create and position the buttons.
class GameInterface(Frame):
def __init__(self):
# ... self.add_buttons()
def add_buttons(self):
reset_button = Button(self, text='Reset', command=self.reset_board)
reset_button.pack(side=LEFT, padx=5, pady=5)
exit_button = Button(self, text='Exit', command=self.quit)
exit_button.pack(side=RIGHT, padx=5, pady=5)
def reset_board(self):
self.board.reset()
The add_buttons()
method creates a “Reset” button and an “Exit” button and packs them into the window using the pack()
method.
The reset_board()
method is bound to the “Reset”