Skip to content

An Improved user interface was build for the TIC TAC TOE using pygame #2260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Interface was build to tic-tac-toe
An Interface using pygame was build for the game and game will be in loop untill user closes it. The inteface was build in a way such that it shows different colors for different situations.
  • Loading branch information
BhanuSaketh authored Jun 30, 2024
commit 6b898b8adf4f4f18205293dda8cf84b426254dbd
260 changes: 163 additions & 97 deletions AI Game/Tic-Tac-Toe-AI/tictactoe.py
Original file line number Diff line number Diff line change
@@ -1,104 +1,170 @@
import tkinter as tk #provides a library of basic elements of GUI widgets
from tkinter import messagebox #provides a different set of dialogues that are used to display message boxes
import random

def check_winner(board, player):
# Check rows, columns, and diagonals for a win
for i in range(3):
if all(board[i][j] == player for j in range(3)) or all(board[j][i] == player for j in range(3)):
import sys
import numpy as np
import pygame

pygame.init()
WHITE = (255, 255, 255)
GRAY = (180, 180, 180)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)

WIDTH = 300
HEIGHT = 300
BOARD_ROWS = 3
BOARD_COLS = 3
SQUARE_SIZE = WIDTH // BOARD_COLS
CIRCLE_RADIUS = SQUARE_SIZE // 3
CIRCLE_WIDTH = 15
CROSS_WIDTH = 25

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("TIC TAC WITH AI")
screen.fill(BLACK)
board = np.zeros((BOARD_ROWS, BOARD_COLS))

def draw_lines(color=WHITE):
for i in range(1, BOARD_ROWS):
pygame.draw.line(screen, color, start_pos=(0, SQUARE_SIZE * i), end_pos=(WIDTH, SQUARE_SIZE * i))
pygame.draw.line(screen, color, start_pos=(SQUARE_SIZE * i, 0), end_pos=(SQUARE_SIZE * i, WIDTH))

def draw_figure(color=WHITE):
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
if board[row][col] == 1:
pygame.draw.circle(screen, color, (int(col * SQUARE_SIZE + SQUARE_SIZE // 2), int(row * SQUARE_SIZE + SQUARE_SIZE // 2)), CIRCLE_RADIUS, CIRCLE_WIDTH)
elif board[row][col] == 2:
pygame.draw.line(screen, color, (col * SQUARE_SIZE + SQUARE_SIZE // 4, row * SQUARE_SIZE + SQUARE_SIZE // 4), (col * SQUARE_SIZE + 3 * SQUARE_SIZE // 4, row * SQUARE_SIZE + 3 * SQUARE_SIZE // 4), CROSS_WIDTH)
pygame.draw.line(screen, color, (col * SQUARE_SIZE + SQUARE_SIZE // 4, row * SQUARE_SIZE + 3 * SQUARE_SIZE // 4), (col * SQUARE_SIZE + 3 * SQUARE_SIZE // 4, row * SQUARE_SIZE + SQUARE_SIZE // 4), CROSS_WIDTH)

def mark_square(row, col, player):
board[row][col] = player

def available_square(row, col):
return board[row][col] == 0

def is_board_full(check_board=board):
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
if check_board[row][col] == 0:
return False
return True

def check_win(player, check_board=board):
for col in range(BOARD_COLS):
if check_board[0][col] == player and check_board[1][col] == player and check_board[2][col] == player:
return True
if all(board[i][i] == player for i in range(3)) or all(board[i][2 - i] == player for i in range(3)):
for row in range(BOARD_ROWS):
if check_board[row][0] == player and check_board[row][1] == player and check_board[row][2] == player:
return True
if check_board[0][0] == player and check_board[1][1] == player and check_board[2][2] == player:
return True
if check_board[0][2] == player and check_board[1][1] == player and check_board[2][0] == player:
return True
return False

def is_board_full(board):
return all(all(cell != ' ' for cell in row) for row in board)

def minimax(board, depth, is_maximizing):
if check_winner(board, 'X'):
return -1
if check_winner(board, 'O'):
return 1
if is_board_full(board): #if game is full, terminate
def minimax(minimax_board, depth, is_maximizing):
if check_win(2, minimax_board):
return 1000 - depth
elif check_win(1, minimax_board):
return depth - 1000
elif is_board_full(minimax_board):
return 0

if is_maximizing: #recursive approach that fills board with Os
max_eval = float('-inf')
for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'O'
eval = minimax(board, depth + 1, False) #recursion
board[i][j] = ' '
max_eval = max(max_eval, eval)
return max_eval
else: #recursive approach that fills board with Xs
min_eval = float('inf')
for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'X'
eval = minimax(board, depth + 1, True) #recursion
board[i][j] = ' '
min_eval = min(min_eval, eval)
return min_eval

#determines the best move for the current player and returns a tuple representing the position
def best_move(board):
best_val = float('-inf')
best_move = None

for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'O'
move_val = minimax(board, 0, False)
board[i][j] = ' '
if move_val > best_val:
best_val = move_val
best_move = (i, j)

return best_move

def make_move(row, col):
if board[row][col] == ' ':
board[row][col] = 'X'
buttons[row][col].config(text='X')
if check_winner(board, 'X'):
messagebox.showinfo("Tic-Tac-Toe", "You win!")
root.quit()
elif is_board_full(board):
messagebox.showinfo("Tic-Tac-Toe", "It's a draw!")
root.quit()
else:
ai_move()
if is_maximizing:
best_score = float('-inf')
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
if minimax_board[row][col] == 0:
minimax_board[row][col] = 2
score = minimax(minimax_board, depth + 1, False)
minimax_board[row][col] = 0
best_score = max(score, best_score)
return best_score
else:
messagebox.showerror("Error", "Invalid move")

#AI's turn to play
def ai_move():
row, col = best_move(board)
board[row][col] = 'O'
buttons[row][col].config(text='O')
if check_winner(board, 'O'):
messagebox.showinfo("Tic-Tac-Toe", "AI wins!")
root.quit()
elif is_board_full(board):
messagebox.showinfo("Tic-Tac-Toe", "It's a draw!")
root.quit()

root = tk.Tk()
root.title("Tic-Tac-Toe")

board = [[' ' for _ in range(3)] for _ in range(3)]
buttons = []

for i in range(3):
row_buttons = []
for j in range(3):
button = tk.Button(root, text=' ', font=('normal', 30), width=5, height=2, command=lambda row=i, col=j: make_move(row, col))
button.grid(row=i, column=j)
row_buttons.append(button)
buttons.append(row_buttons)

root.mainloop()
best_score = float('inf')
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
if minimax_board[row][col] == 0:
minimax_board[row][col] = 1
score = minimax(minimax_board, depth + 1, True)
# print(score)
minimax_board[row][col] = 0
best_score = min(score, best_score)
return best_score

def best_move():
best_score = float('-inf')
move = (-1, -1)
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
if board[row][col] == 0:
board[row][col] = 2
score = minimax(board, 0, False)
board[row][col] = 0
if score > best_score:
best_score = score
move = (row, col)
if move != (-1, -1):
mark_square(move[0], move[1], 2)
return True
return False

def restart_game():
screen.fill(BLACK)
draw_lines()
for row in range(BOARD_ROWS):
for col in range(BOARD_COLS):
board[row][col] = 0

draw_lines()
player = 1
game_over = False

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
mouseX = event.pos[0] // SQUARE_SIZE
mouseY = event.pos[1] // SQUARE_SIZE

if available_square(mouseY, mouseX):
mark_square(mouseY, mouseX, player)
if check_win(player):
game_over = True
player = player % 2 + 1

if not game_over:
if best_move():
if check_win(2):
game_over = True
player = player % 2 + 1
if not game_over:
if is_board_full():
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
restart_game()
game_over = False
player = 1

draw_figure()
pygame.display.update()

if game_over:
if check_win(1):
draw_figure(GREEN)
draw_lines(GREEN)
elif check_win(2):
draw_figure(RED)
draw_lines(RED)
else:
draw_figure(GRAY)
draw_lines(GRAY)
pygame.display.update()
pygame.time.wait(3000)
restart_game()
game_over = False
player = 1