Tic Tac Toe in Python with Artificial Intelligence - It's Unbeatable

tic tac toe game in python using artificial intelligence. The logic of this game is built using the minimax algorithm.

Introduction

Tic Tac Toe is a paper and pencil game that can be part of every person's childhood memories. This game is also known as noughts and crosses. Whatever it's called, there is no doubt one of the most memorable parts of our school day.

Only two players can play this game on a three-by-three grid. Player - X and Player - O. If a player has to win this game, he has to give his mark along with three positions.

These are the position combinations to win the Tic Tac Toe game.
Winning Combinations of Tic Tac Toe Game

We used to play this game with pen and paper. As everything is going digital; So now everyone prefers to play most of the games on mobile or computer. Here we will create such a computer game.

In this tutorial, we will create a Tic Tac Toe Game in Python. The graphics of this game is managed using the PyGame library. Now we will play this game against a computer and the computer will play this game using Artificial Intelligence. One of the interesting things about this game is that the computer will be unbeatable. That means you cannot win this game against the computer.

☛Visit AlsoSentiment Analysis of Amazon Reviews using Python - NLP

Project Details

There are two ways to make the game unbeatable; using the Minimax algorithm, or Alpha-beta pruning. I used the first one.

Whenever the player makes a decision, the computer takes the most optimal action using the minimax algorithm. There are only two possibilities at the end of the game. Either the computer wins or the game is tied.

This project contains two python files, runner.py, and tictactoe.py. runner.py contains the code for managing the graphics of the game. tictactoe.py contains all the necessary functions and logic that make the optimal move for every state.

Requirement

Before you start writing your code just take a break here. Install the PyGame library if you didn't already.

👉Install PyGame: pip install pygame

tictactoe.py

Importing the libraries

Let's start writing your code by importing these modules.


import math
from random import choice
from math import inf as infinity

X = "X"
O = "O"
EMPTY = None
pl = X
first = True

The Initial state function

The initial_state function returns an empty  three-by-three grid on which the program will keep the input.


def initial_state():
"""
Returns starting state of the board.
"""
return [[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY]]

The player function

The player function takes the game state and returns the player who's the next to take the next turn. In this case, player - X or player - O. Generally X gets the first move and then the turn rotates for each move until the terminal state comes.


def player(board):
"""
Returns player who has the next turn on the board.
"""
global pl
global first
NoOfX = 0
NoOfO = 0

if first is True:
first = False
return pl
else:
for i in range(0, len(board)):
for j in range(0, len(board[0])):
if board[i][j] == X:
NoOfX += 1
elif board[i][j] == O:
NoOfO += 1

if NoOfX > NoOfO:
pl = O
else:
pl = X

return pl

The action function

The action function takes the board as an input and returns a set of all possible actions available on the board. The possible actions are represented as a tuple (i, j) where 'i' represents the row number(1, 2, or, 3) and 'j' represents the column number(1, 2, or 3).

Possible actions or places are any empty cells on the given board.


def actions(board):
"""
Returns set of all possible actions (i, j) available on the board.
"""
places = []
if not terminal(board):
for x, row in enumerate(board):
for y, cell in enumerate(row):
if cell == None:
places.append([x, y])
return places

The result function

The result function takes the board and action as input and returns the board that results from making a move on the board without modifying the original board.


def result(board, action):
"""
Returns the board that results from making move (i, j) on the board.
"""
b = board
x, y = action[0], action[1]
b[x][y] = player(board)
return b

The winner function

The winner function takes the board as an input and returns the winner of the game, if there is any, otherwise, returns None. 

There are nine positions horizontally, vertically, and diagonally. The player has to place his/her sign row-wise in one of the three places to win this game.


def winner(board):
"""
Returns the winner of the game, if there is one.
"""
WinState = [
[board[0][0], board[0][1], board[0][2]],
[board[1][0], board[1][1], board[1][2]],
[board[2][0], board[2][1], board[2][2]],
[board[0][0], board[1][0], board[2][0]],
[board[0][1], board[1][1], board[2][1]],
[board[0][2], board[1][2], board[2][2]],
[board[0][0], board[1][1], board[2][2]],
[board[2][0], board[1][1], board[0][2]],
]
if [X, X, X] in WinState:
return X
elif [O, O, O] in WinState:
return O
else:
return None

The terminal function

The terminal function takes the board as input and checks the current state of the board. If the current state is the terminal state then it returns True, otherwise, it returns False.


def terminal(board):
"""
Returns True if the game is over, False otherwise.
"""
if (winner(board) is not None) or (not any(EMPTY in sublist for
sublist in board) and winner(board) is None):
return True
else:
return False

The utility function

The utility function returns 1 if the X has won the game, and -1 if O has won, otherwise returns 0(for the tie), if and only if the current board state is the terminal state.


def utility(board):
"""
Returns 1 if X has won the game, -1 if O has won, and 0 otherwise.
"""
if terminal(board):
if winner(board) == X:
score = 1
elif winner(board) == O:
score = -1
else:
score = 0

return score

The minimax function

The minimax function is the most complex part of this code. It returns the most optimal move for the computer. I've divided the whole logic of this algorithm into two functions, "AI_Turn" and "minimax" functions.

This is showing how the minimax algorithm works in the game Tic Tac Toe in Python
Working Principle of Minimax Algorithm in Tic Tac Toe Game


# AI Turn Function
def AI_Turn(board, length, pl):
if pl == X:
best = [-1, -1, -infinity]
elif pl == O:
best = [-1, -1, +infinity]

if length == 0 or terminal(board):
score = utility(board)
return [-1, -1, score]

for cell in actions(board):
x, y = cell[0], cell[1]
board[x][y] = pl
score = AI_Turn(board, length - 1, player(board))
board[x][y] = EMPTY
score[0], score[1] = x, y

if pl == X:
if score[2] > best[2]:
best = score # Max value
else:
if score[2] < best[2]:
best = score # Min value

return best


def minimax(board):
"""
Returns the optimal action for the current player on the board.
"""
length = len(actions(board))
if length == 0 or terminal(board):
return None

if length == 9:
x = choice([0, 1, 2])
y = choice([0, 1, 2])
else:
move = AI_Turn(board, length, pl)
x, y = move[0], move[1]

return [x, y]

runner.py

Look at the yellow line. It's a font file and must be present in the main directory. You can download it through the download button below.


import pygame
import sys
import time

import tictactoe as ttt

pygame.init()
size = width, height = 600, 400

# Colors
black = (0, 0, 0)
white = (255, 255, 255)

screen = pygame.display.set_mode(size)

mediumFont = pygame.font.Font("OpenSans-Regular.ttf", 28)
largeFont = pygame.font.Font("OpenSans-Regular.ttf", 40)
moveFont = pygame.font.Font("OpenSans-Regular.ttf", 60)

user = None
board = ttt.initial_state()
ai_turn = False

while True:

for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()

screen.fill(black)

# Let the user choose a player.
if user is None:

# Draw title
title = largeFont.render("Tic-Tac-Toe", True, white)
titleRect = title.get_rect()
titleRect.center = ((width / 2), 50)
screen.blit(title, titleRect)

# Draw buttons
playXButton = pygame.Rect((width / 8), (height / 2), width / 4, 50)
playX = mediumFont.render("Play as X", True, black)
playXRect = playX.get_rect()
playXRect.center = playXButton.center
pygame.draw.rect(screen, white, playXButton)
screen.blit(playX, playXRect)

playOButton = pygame.Rect(5 * (width / 8), (height / 2), width / 4, 50)
playO = mediumFont.render("Play as O", True, black)
playORect = playO.get_rect()
playORect.center = playOButton.center
pygame.draw.rect(screen, white, playOButton)
screen.blit(playO, playORect)

# Check if button is clicked
click, _, _ = pygame.mouse.get_pressed()

if click == 1:
mouse = pygame.mouse.get_pos()
if playXButton.collidepoint(mouse):
time.sleep(0.2)
user = ttt.X

elif playOButton.collidepoint(mouse):
time.sleep(0.2)
user = ttt.O

else:

# Draw game board
tile_size = 80
tile_origin = (width / 2 - (1.5 * tile_size),
height / 2 - (1.5 * tile_size))
tiles = []
for i in range(3):
row = []
for j in range(3):
rect = pygame.Rect(
tile_origin[0] + j * tile_size,
tile_origin[1] + i * tile_size,
tile_size, tile_size
)
pygame.draw.rect(screen, white, rect, 3)

if board[i][j] != ttt.EMPTY:
move = moveFont.render(board[i][j], True, white)
moveRect = move.get_rect()
moveRect.center = rect.center
screen.blit(move, moveRect)
row.append(rect)
tiles.append(row)

game_over = ttt.terminal(board) # At first Result should be False
player = ttt.player(board) # At first it should be the X


# Show title
if game_over:
winner = ttt.winner(board)
if winner is None:
title = f"Game Over: Tie."
else:
title = f"Game Over: {winner} wins."
elif user == player:
title = f"Your turn {user}"
else:
title = f"Computer thinking..."
title = largeFont.render(title, True, white)
titleRect = title.get_rect()
titleRect.center = ((width / 2), 30)
screen.blit(title, titleRect)

# Check for AI move
if user != player and not game_over:
if ai_turn:
time.sleep(0.5)
move = ttt.minimax(board)
board = ttt.result(board, move)
ai_turn = False
else:
ai_turn = True


# Check for a user move
click, _, _ = pygame.mouse.get_pressed()
if click == 1 and user == player and not game_over:
mouse = pygame.mouse.get_pos()
for i in range(3):
for j in range(3):
if (board[i][j] == ttt.EMPTY and tiles[i][j].collidepoint(mouse)):
board = ttt.result(board, [i, j]) # (i, j)->[i, j]


if game_over:
againButton = pygame.Rect(width / 3, height - 65, width / 3, 50)
again = mediumFont.render("Play Again", True, black)
againRect = again.get_rect()
againRect.center = againButton.center
pygame.draw.rect(screen, white, againButton)
screen.blit(again, againRect)
click, _, _ = pygame.mouse.get_pressed()
if click == 1:
mouse = pygame.mouse.get_pos()
if againButton.collidepoint(mouse):
time.sleep(0.2)
user = None
board = ttt.initial_state()
ai_turn = False

pygame.display.flip()

Download the Source Code

You can download the zip file of this project from my GitHub page through the download button.

github page of tic tac toe game project with artificial intelligence
Image - GitHub Page of Tic Tac Toe Project
 

Important Note

This project is a solution to project0 CS50's Artificial Intelligence. I have developed the program in the tictactoe.py file on my own. It was a task that was given at lecture0, Search problem. This course is totally free and everyone can take this course from there.

☛Visit AlsoSix Degrees of Kevin Bacon in Python: Artificial Intelligence Project

Summary

Indeed, the popularity of Tic Tac Toe is not the same as before. But since we are talking about Artificial Intelligence here, this simple game is also a great lesson to develop using Artificial Intelligence.

In this tutorial, we developed the Tic Tac Toe Game in Python using Artificial Intelligence. The logic of this game is built using the Minimax algorithm and it makes the computer unbeatable.

The graphics in this game is handled by the PyGame library. Play this game and try to win against the computer. Let me know in the comments section, then what happens.

Thanks for reading!💙

PySeek

Subhankar Rakshit

Meet Subhankar Rakshit, a Computer Science postgraduate (M.Sc.) and the creator of PySeek. Subhankar is a programmer, specializes in Python language. With a several years of experience under his belt, he has developed a deep understanding of software development. He enjoys writing blogs on various topics related to Computer Science, Python Programming, and Software Development.

Post a Comment (0)
Previous Post Next Post