DEV Community

Cover image for A Simple Python Tic-Tac-Toe Game Using Pygame
Ramakrushna Mohapatra
Ramakrushna Mohapatra

Posted on • Edited on

A Simple Python Tic-Tac-Toe Game Using Pygame

Hello Dev world! This blog is about to create a simple and cool game which we were playing from our childhood. the best game we played as a 90's kid during school time.Yes you heard it right! its TIC TAC TOE game. I am going to show you how you can build in Python. But, moving far let me give you the definition of the Tic Tac Toe Game.

Definition of Tic Tac Toe Game:

It is a traditional strategy game where two players look for different turns to complete a row, a column, or a diagonal with either three O’s or three X’s drawn in the spaces of a grid of nine squares. The squares contain different noughts and crosses. It is typically a paper-and-pencil game but now programmed like a computer game. The player whoever first completes placing three of their marks in a horizontal, vertical, or diagonal row in a square wins.

As we got to know about this, lets go to the first step of making this game:

REQUIREMENTS FOR THE GAME:

  • A good & fast processing PC with a Python environment & pygame package installed. You can choose Mac Book, Asus Zenbook, Dell Inspiron, or any Pc with a high processor.
  • Code Ide or Code Editor.(I used Pycharm editor. Its fully depends on you)
  • A notebook for writing important notation.
  • Your Focus.

HOW THE GAME WORKS:

  • Our Tic Tac Toe is programmed in other to allow two users or players to play the game in the same time.
  • It is GUI game & gives an instant alert when players wins or losses or draw the game.

STEPS REQUIRED TO MAKE THIS AWESOME GAME LIVE:

  • First of all, create a folder named any in your PC & drag it to your code editor.
  • Secondly, open your command prompt(CMD) & install the Pygame package by typing pip install pygame command.(I used windows10 OS)
  • Thirdly, make a file called TicTacToeGame.py & folders called image. It will you to store all your codes & image resource files needed for the game.
  • Set your codes which are given below to your respective files. And about the images i used in that code, depends on you. just download your convenience images for X and O and put it inside the image folder. and give the path correctly under:

**X_IMAGE =
pygame.transform.scale(pygame.image.load("**Images/x.png**"), (150,
150))

O_IMAGE =
pygame.transform.scale(pygame.image.load("**Images/o.png**"),(150,
150))**

  • Lastly just run this code and enjoy the game.

CODE

I have mentioned comments before every new code addes to this project. Hope it will help for the new dev guys who is trying to built this game.

TicTacToeGame.py

import pygame import math # Initializing Pygame pygame.init() # Screen WIDTH = 500 ROWS = 3 win = pygame.display.set_mode((WIDTH, WIDTH)) pygame.display.set_caption("TicTacToe") # Colors WHITE = (255, 255, 255) BLACK = (0, 0, 0) GRAY = (200, 200, 200) RED = (255, 0, 0) BLUE = (0, 0, 255) # Images X_IMAGE = pygame.transform.scale(pygame.image.load("Images/x.png"), (150, 150)) O_IMAGE = pygame.transform.scale(pygame.image.load("Images/o.png"), (150, 150)) # Fonts END_FONT = pygame.font.SysFont('courier', 40) def draw_grid(): gap = WIDTH // ROWS # Starting points x = 0 y = 0 for i in range(ROWS): x = i * gap pygame.draw.line(win, GRAY, (x, 0), (x, WIDTH), 3) pygame.draw.line(win, GRAY, (0, x), (WIDTH, x), 3) def initialize_grid(): dis_to_cen = WIDTH // ROWS // 2 # Initializing the array game_array = [[None, None, None], [None, None, None], [None, None, None]] for i in range(len(game_array)): for j in range(len(game_array[i])): x = dis_to_cen * (2 * j + 1) y = dis_to_cen * (2 * i + 1) # Adding centre coordinates game_array[i][j] = (x, y, "", True) return game_array def click(game_array): global x_turn, o_turn, images # Mouse position m_x, m_y = pygame.mouse.get_pos() for i in range(len(game_array)): for j in range(len(game_array[i])): x, y, char, can_play = game_array[i][j] # Distance between mouse and the centre of the square dis = math.sqrt((x - m_x) ** 2 + (y - m_y) ** 2) # If it's inside the square if dis < WIDTH // ROWS // 2 and can_play: if x_turn: # If it's X's turn images.append((x, y, X_IMAGE)) x_turn = False o_turn = True game_array[i][j] = (x, y, 'x', False) elif o_turn: # If it's O's turn images.append((x, y, O_IMAGE)) x_turn = True o_turn = False game_array[i][j] = (x, y, 'o', False) # Checking if someone has won def has_won(game_array): # Checking rows for row in range(len(game_array)): if (game_array[0][2] == game_array[1][2] == game_array[2][2]) and game_array[0][2] != "": display_message(game_array[0][2].upper() + " has won!") return True # Checking columns for col in range(len(game_array)): if (game_array[0][2] == game_array[1][2] == game_array[2][2]) and game_array[0][2] != "": display_message(game_array[0][2].upper() + " has won!") return True # Checking main diagonal if (game_array[0][0][2] == game_array[1][1][2] == game_array[2][2][2]) and game_array[0][0][2] != "": display_message(game_array[0][0][2].upper() + " has won!") return True # Checking reverse diagonal if (game_array[0][2][2] == game_array[1][1][2] == game_array[2][0][2]) and game_array[0][2][2] != "": display_message(game_array[0][2][2].upper() + " has won!") return True return False def has_drawn(game_array): for i in range(len(game_array)): for j in range(len(game_array[i])): if game_array[i][j][2] == "": return False display_message("It's a draw!") return True def display_message(content): pygame.time.delay(500) win.fill(WHITE) end_text = END_FONT.render(content, 1, BLACK) win.blit(end_text, ((WIDTH - end_text.get_width()) // 2, (WIDTH - end_text.get_height()) // 2)) pygame.display.update() pygame.time.delay(3000) def render(): win.fill(WHITE) draw_grid() # Drawing X's and O's for image in images: x, y, IMAGE = image win.blit(IMAGE, (x - IMAGE.get_width() // 2, y - IMAGE.get_height() // 2)) pygame.display.update() def main(): global x_turn, o_turn, images, draw images = [] draw = False run = True x_turn = True o_turn = False game_array = initialize_grid() while run: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if event.type == pygame.MOUSEBUTTONDOWN: click(game_array) render() if has_won(game_array) or has_drawn(game_array): run = False while True: if __name__ == '__main__': main() 
Enter fullscreen mode Exit fullscreen mode

FINAL STATEMENT:

It is simple beginner friendly Tic-Tac-Toe Game which is easy for any beginners to built & understand. You can also download this code from my github page directly. Hope this will help you to build this game and enjoy this game with you hoomies or with your friends. Let's connect and built together a great dev enovironment.

Cheers! Happy coding

Top comments (5)

Collapse
 
abdurrahmaanj profile image
Abdur-Rahmaan Janhangeer

Put python after the 3 backsticks so that your code is syntax-highlighted.

print(1) 
Enter fullscreen mode Exit fullscreen mode

Else have a look at this lib. You think it make PyGame programming easier? Thanks

Collapse
 
djungarik profile image
Timur Berezhnoy • Edited

Checking rows and columns doesn't work, so I changed some lines a little bit. It works properly now.

# Checking rows for row in range(0,3): if (game_array[row][0][2] == game_array[row][1][2] == game_array[row][2][2]) and game_array[row][0][2] != "": display_message(game_array[row][0][2].upper() + " has won!") return True # Checking columns for col in range(0, 3): if (game_array[0][col][2] == game_array[1][col][2] == game_array[2][col][2]) and game_array[0][col][2] != "": display_message(game_array[0][col][2].upper() + " has won!") return True 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ramakm profile image
Ramakrushna Mohapatra

Worked for me. may be version issue. Thanks for your comment.

Collapse
 
hairash profile image
Hairash

Hello! Thanks for code!
I have noticed one moment there:
You have constant ROWS = 3, and it's value can be changed.
And at the same time you create game array:

game_array = [[None, None, None], [None, None, None], [None, None, None]]

that means you have 3x3 field.
I think, it's better to replace this line with:

game_array = [[None] * ROWS for _ in range(ROWS)]

So it will work for every field size.

Collapse
 
ramakm profile image
Ramakrushna Mohapatra

Yeah, For generic purpose its better to use your mentioned line. Thanks.