Skip to content
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

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
39 changes: 39 additions & 0 deletions AI Game/Tic-Tac-Toe-AI/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# TIC TAC WITH AI

## Overview

TIC TAC WITH AI is a Python-based Tic Tac Toe game using the Pygame library. This project includes a basic implementation of the game with an AI opponent.The AI uses the minimax algorithm to make optimal moves, providing a challenging opponent for players.

## Features

- Single-player mode against an AI
- Minimax algorithm for AI decision-making
- Interactive graphical user interface using Pygame
- Restart functionality to play multiple games in one session
- Visual indicators for game outcome: win, lose, or draw



### Game Controls

- **Mouse Click:** Place your mark (X) on the board.
- **R Key:** Restart the game.

### Game Rules

- The game is played on a 3x3 grid.
- You are X, and the AI is O.
- Players take turns placing their marks in empty squares.
- The first player to get three of their marks in a row (horizontally, vertically, or diagonally) wins.
- If all nine squares are filled and neither player has three in a row, the game ends in a draw.

### Sample Interface

![image](https://github.com/BhanuSaketh/Python/assets/118091571/41a2823f-b901-485d-b53e-6ddd774dfd96)


## How It Works

- The game board is represented by a 3x3 numpy array.
- The game loop listens for user input and updates the game state accordingly.
- The AI uses the minimax algorithm to evaluate possible moves and choose the best one.
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