Tic-tac-toe in python

by Alex
Tic-tac-toe in python

It is very useful to write some simple programs in the programming language in order to study it. Here we present a tic-tac-toe game written in Python 3 with a graphical interface.

About the program

In this game you can compete with the computer. The first move is up to the player. But to beat the artificial intelligence in this confrontation will not be so easy. The computer does not “yawn” and if it has a chance to win, it will certainly take advantage of it.

About the program

At the bottom is a button to start a new game. If you press it, the playing field will be cleared and you can start the game again. The player puts crosses, and the computer puts zeros. As always, the winner is the one who first makes a line of his symbols: horizontally, vertically or diagonally.

Libraries and variable declarations

To display graphics we will use the standard Tkinter library, which is installed with Python. We also need the random library in order to get random numbers which will make the computer’s moves appear unexpected. This is also the standard Python library. So you don’t need to install anything additionally. We just plug it in with import. Create a root window, set its header and declare the necessary variables:

  • game_run – we will write False to this variable at the end of the game, to prohibit making moves when the winner is already determined.
  • field – this will be a two-dimensional list, which will store the buttons of the game field. A move will be to change the inscription on the button to an “X” or “O”.
  • cross_count in this variable we will keep track of the number of crosses on the field. In order to record a draw on the fifth cross, in case no one wins.
from tkinter import *
import random
root = Tk()
root.title('Criss-cross')
game_run = True
field = []
cross_count = 0

Button presses handling

The new_game function will be called when a new game button is pressed. On the field, all crosses and zeros are removed. Make the color of the buttons pale purple. Set global variables game_run and cross_count to initial values. These are the global variables that you are trying to access from the function. So you have to use the keyword global in Python before you try to change their value.

def new_game():
    for row in range(3):
        for col in range(3):
            field[row][col]['text'] = ' '
            field[row][col]['background'] = ''lavender''
    global game_run
    game_run = True
    global cross_count
    cross_count = 0

The click function will be called after you click on the field, i.e. when you try to put a cross. If the game is not over, the cross is placed. After this we increase the counter of the number of crosses placed. Then use the check_win function to check if we have won with this move. If there is no winner yet and there are more moves, then the computer_move function performs the move, and also after the move there is a check for the win.

def click(row, col):
    if game_run and field[row][col]['text'] == ':
        field[row][col]['text'] = 'X''
        global cross_count
        cross_count += 1
        check_win('X')
        if game_run and cross_count < 5:
            computer_move()
            check_win('O')

Checking for wins

The check_win function checks for wins. It goes through all possible combinations of fields that form a line and calls the check_line function with them. The variable smb is the character “X” or “O”, i.e. X’s or Z’s. If “O” is set, it checks if the computer has won. If a win is fixed, then change the background color of the buttons that make up the line to pink. And also write value False to game_run.

def check_win(smb):
    for n in range(3):
        check_line(field[n][0], field[n][1], field[n][2], smb)
        check_line(field[0][n], field[1][n], field[2][n], smb)
    check_line(field[0][0], field[1][1], field[2][2], smb)
    check_line(field[2][0], field[1][1], field[0][2], smb)

def check_line(a1,a2,a3,smb):
    if a1['text'] == smb and a2['text'] == smb and a3['text'] == smb
        a1['background'] = a2['background'] = a3['background'] = 'pink'
        global game_run
        game_run = False

Let’s check all possible variants, because theoretically we can form two lines at once with one move.

Computer Actions

The computer’s move is calculated in the function computer_move. The algorithm of his actions is as follows:

  1. To check if there is a chance of winning. If the computer has a chance to win, it should not miss it. Immediately makes the victory.
  2. Checking the possible victory of the opponent in one move. If a player puts two crosses in a row, the computer tries to destroy the player’s plans.
  3. Random move. Since there is no possibility of winning and no threat of losing, a random free field is chosen. In an infinite wile loop, random numbers are run through until they fall on an unoccupied field.
def can_win(a1,a2,a3,smb):
    res = False
    if a1['text'] == smb and a2['text'] == smb and a3['text'] == '
        a3['text'] = 'O'
        res = True
    if a1['text'] == smb and a2['text'] == ' and a3['text'] == smb
        a2['text'] = 'O'
        res = True
    if a1['text'] == ' ' and a2['text'] == smb and a3['text'] == smb
        a1['text'] = 'O'
        res = True
    return res

def computer_move():
    for n in range(3):
        if can_win(field[n][0], field[n][1], field[n][2], 'O'):
            return
        if can_win(field[0][n], field[1][n], field[2][n], 'O'):
            return
    if can_win(field[0][0], field[1][1], field[2][2], 'O'):
        return
    if can_win(field[2][0], field[1][1], field[0][2], 'O'):
        return
    for n in range(3):
        if can_win(field[n][0], field[n][1], field[n][2], 'X'):
            return
        if can_win(field[0][n], field[1][n], field[2][n], 'X'):
            return
    if can_win(field[0][0], field[1][1], field[2][2], 'X'):
        return
    if can_win(field[2][0], field[1][1], field[0][2], 'X'):
        return
    while True:
        row = random.randint(0, 2)
        col = random.randint(0, 2)
        if field[row][col]['text'] == ':
            field[row][col]['text'] = 'O'
            break

GUI

We will place all GUI elements using the grid packer. In the loop we will add game field buttons. They will be stored in a two-dimensional list. In the Python programming language you add elements to the list using the append method. Set the colorspan property of the game button to 3, so it takes the whole width of the table

for row in range(3):
    line = []
    for col in range(3):
        button = Button(root, text='', width=4, height=2, 
                        font=('Verdana', 20, 'bold'),
                        background='lavender',
                        command=lambda row=row, col=col: click(row,col))
        button.grid(row=row, column=col, sticky='nsew')
        line.append(button)
    field.append(line)
new_button = Button(root, text='new game', command=new_game)
new_button.grid(row=3, column=0, columnspan=3, sticky='nsew')
root.mainloop()

We did the grid in the same way we did the buttons in the calculator example in a separate article. Overall, this implementation of tic-tac-toe is pretty good for Python 3 programmers. You can make the task a bit more difficult by adding difficulty levels. For example, on a simple level the computer makes absolutely random moves. On a more difficult level, it does not miss an opportunity to win, but it can still miss two crosses in a row.

Related Posts

LEAVE A COMMENT