Skip to content

Commit 7356894

Browse files
authored
Merge pull request #43 from Naumantamboli/main
Tic-Tac-Toe game with AI (using Minmax)
2 parents 687b2ef + cfa05e9 commit 7356894

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Tic-Tac-Toe Game with AI
2+
3+
This project is a Tic-Tac-Toe game implemented in Python using the Pygame library. The game presents a classic, engaging experience where players can compete against either an AI opponent or another human player. The AI leverages the Minimax algorithm, a decision-making algorithm used in game theory, to evaluate potential moves and choose the best possible action at each turn. This guarantees that the AI will always make optimal moves, creating a challenging and competitive environment for players of all skill levels.
4+
5+
### Key Features:
6+
- **Two Players**: Play against an AI or another human player.
7+
- **Minimax Algorithm**: The AI makes optimal moves based on the Minimax strategy.
8+
- **Graphical User Interface**: A simple and intuitive GUI using Pygame.
9+
- **Reset Option**: Restart the game easily at any time.
10+
11+
# Prerequisites
12+
The following libraries are required to run the script:
13+
```bash
14+
pip install pygame numpy
15+
```
16+
17+
# Installing Instructions
18+
1. **Clone the Repository**:
19+
Clone this repository to your local machine using:
20+
```bash
21+
git clone <repository-url>
22+
```
23+
24+
2. **Install Dependencies**:
25+
Navigate to the project directory and install the required packages:
26+
```bash
27+
pip install pygame numpy
28+
```
29+
30+
3. **Run the Script**:
31+
After cloning and installing dependencies, you can run the script directly:
32+
```bash
33+
python tic_tac_toe.py
34+
```
35+
36+
4. **Customize the Script**:
37+
You can modify game settings, such as board size and player options, directly in the script.
38+
39+
# Gameplay Instructions
40+
- **Player vs AI:**: Click on the grid to make your move. The AI will respond automatically.
41+
- **AI Difficulty Levels**: You can adjust the difficulty of the AI in the game settings to suit your skill level. Higher levels make the AI more challenging.
42+
- **Restart Game**: Press the R key to restart the game at any time.
43+
44+
# Usage
45+
**Player vs AI**: Click on the grid to make your move. The AI will respond automatically.
46+
47+
**Restart Game**: Press the R key to restart the game at any time.
48+
49+
# Example
50+
After starting the game, you can play by clicking on the grid cells. The AI will make its move following your turn, and the game will continue until one player wins or the game ends in a draw.
51+
![Game Screen](screenshots/screenshot1.png)
52+
![Winning State](screenshots/screenshot2.png)
53+
54+
55+
# Author
56+
**[Naumantamboli](https://github.com/Naumantamboli)**
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pygame==2.1.3
2+
numpy==1.23.5
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import pygame
2+
import sys
3+
import numpy as np
4+
5+
pygame.init()
6+
7+
WIDTH, HEIGHT = 600, 600
8+
LINE_WIDTH = 15
9+
BOARD_ROWS = 3
10+
BOARD_COLS = 3
11+
SQUARE_SIZE = WIDTH // BOARD_COLS
12+
CIRCLE_RADIUS = SQUARE_SIZE // 3
13+
CIRCLE_WIDTH = 15
14+
CROSS_WIDTH = 25
15+
SPACE = SQUARE_SIZE // 4
16+
17+
BG_COLOR = (28, 170, 156)
18+
LINE_COLOR = (23, 145, 135)
19+
CIRCLE_COLOR = (239, 231, 200)
20+
CROSS_COLOR = (66, 66, 66)
21+
TEXT_COLOR = (255, 255, 255)
22+
23+
screen = pygame.display.set_mode((WIDTH, HEIGHT))
24+
pygame.display.set_caption('Tic Tac Toe')
25+
screen.fill(BG_COLOR)
26+
27+
font = pygame.font.Font(None, 40) # Font for displaying messages
28+
board = np.zeros((BOARD_ROWS, BOARD_COLS))
29+
30+
difficulty = "medium" # AI difficulty level ("easy", "medium", "hard")
31+
32+
def draw_lines():
33+
for row in range(1, BOARD_ROWS):
34+
pygame.draw.line(screen, LINE_COLOR, (0, row * SQUARE_SIZE), (WIDTH, row * SQUARE_SIZE), LINE_WIDTH)
35+
for col in range(1, BOARD_COLS):
36+
pygame.draw.line(screen, LINE_COLOR, (col * SQUARE_SIZE, 0), (col * SQUARE_SIZE, HEIGHT), LINE_WIDTH)
37+
38+
# Draw figures (O and X)
39+
def draw_figures():
40+
for row in range(BOARD_ROWS):
41+
for col in range(BOARD_COLS):
42+
if board[row][col] == 1:
43+
pygame.draw.circle(screen, CIRCLE_COLOR,
44+
(int(col * SQUARE_SIZE + SQUARE_SIZE // 2), int(row * SQUARE_SIZE + SQUARE_SIZE // 2)),
45+
CIRCLE_RADIUS, CIRCLE_WIDTH)
46+
elif board[row][col] == 2:
47+
pygame.draw.line(screen, CROSS_COLOR,
48+
(col * SQUARE_SIZE + SPACE, row * SQUARE_SIZE + SQUARE_SIZE - SPACE),
49+
(col * SQUARE_SIZE + SQUARE_SIZE - SPACE, row * SQUARE_SIZE + SPACE), CROSS_WIDTH)
50+
pygame.draw.line(screen, CROSS_COLOR,
51+
(col * SQUARE_SIZE + SPACE, row * SQUARE_SIZE + SPACE),
52+
(col * SQUARE_SIZE + SQUARE_SIZE - SPACE, row * SQUARE_SIZE + SQUARE_SIZE - SPACE),
53+
CROSS_WIDTH)
54+
55+
def mark_square(row, col, player):
56+
board[row][col] = player
57+
58+
def available_square(row, col):
59+
return board[row][col] == 0
60+
61+
def is_board_full():
62+
return np.all(board != 0)
63+
64+
def check_win(player):
65+
for row in range(BOARD_ROWS):
66+
if np.all(board[row, :] == player):
67+
return True
68+
for col in range(BOARD_COLS):
69+
if np.all(board[:, col] == player):
70+
return True
71+
if board[0, 0] == player and board[1, 1] == player and board[2, 2] == player:
72+
return True
73+
if board[0, 2] == player and board[1, 1] == player and board[2, 0] == player:
74+
return True
75+
return False
76+
77+
def display_message(message):
78+
text = font.render(message, True, TEXT_COLOR)
79+
text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2))
80+
screen.blit(text, text_rect)
81+
pygame.display.update()
82+
pygame.time.wait(2000) # Wait for 2 seconds to display the message
83+
84+
# Minimax algorithm with difficulty levels
85+
def minimax(board, depth, is_maximizing):
86+
if check_win(2): # AI win
87+
return 1
88+
elif check_win(1): # Player win
89+
return -1
90+
elif is_board_full():
91+
return 0
92+
93+
if is_maximizing:
94+
best_score = -np.inf
95+
for row in range(BOARD_ROWS):
96+
for col in range(BOARD_COLS):
97+
if available_square(row, col):
98+
board[row][col] = 2
99+
score = minimax(board, depth + 1, False)
100+
board[row][col] = 0
101+
best_score = max(score, best_score)
102+
return best_score
103+
else:
104+
best_score = np.inf
105+
for row in range(BOARD_ROWS):
106+
for col in range(BOARD_COLS):
107+
if available_square(row, col):
108+
board[row][col] = 1
109+
score = minimax(board, depth + 1, True)
110+
board[row][col] = 0
111+
best_score = min(score, best_score)
112+
return best_score
113+
114+
# AI Move based on difficulty level
115+
def ai_move():
116+
best_score = -np.inf
117+
move = None
118+
for row in range(BOARD_ROWS):
119+
for col in range(BOARD_COLS):
120+
if available_square(row, col):
121+
board[row][col] = 2
122+
score = minimax(board, 0, False)
123+
board[row][col] = 0
124+
if score > best_score:
125+
best_score = score
126+
move = (row, col)
127+
128+
if move:
129+
mark_square(move[0], move[1], 2)
130+
131+
# Easy AI move: choose a random available square
132+
def easy_ai_move():
133+
available_moves = [(row, col) for row in range(BOARD_ROWS) for col in range(BOARD_COLS) if available_square(row, col)]
134+
if available_moves:
135+
move = available_moves[np.random.randint(len(available_moves))]
136+
mark_square(move[0], move[1], 2)
137+
138+
def restart():
139+
screen.fill(BG_COLOR)
140+
draw_lines()
141+
global board
142+
board = np.zeros((BOARD_ROWS, BOARD_COLS))
143+
144+
player = 1 # Player 1 is human
145+
game_over = False
146+
147+
draw_lines()
148+
149+
while True:
150+
for event in pygame.event.get():
151+
if event.type == pygame.QUIT:
152+
pygame.quit()
153+
sys.exit()
154+
155+
if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
156+
mouseX = event.pos[0] # X coordinate
157+
mouseY = event.pos[1] # Y coordinate
158+
159+
clicked_row = mouseY // SQUARE_SIZE
160+
clicked_col = mouseX // SQUARE_SIZE
161+
162+
if available_square(clicked_row, clicked_col):
163+
mark_square(clicked_row, clicked_col, player)
164+
if check_win(player):
165+
display_message("Player Wins!")
166+
game_over = True
167+
player = 2
168+
169+
if player == 2 and not game_over:
170+
if difficulty == "easy":
171+
easy_ai_move()
172+
else:
173+
ai_move()
174+
175+
if check_win(2):
176+
display_message("AI Wins!")
177+
game_over = True
178+
player = 1
179+
180+
if event.type == pygame.KEYDOWN:
181+
if event.key == pygame.K_r:
182+
restart()
183+
game_over = False
184+
player = 1
185+
186+
if game_over and is_board_full():
187+
display_message("It's a Draw!")
188+
game_over = True
189+
190+
draw_figures()
191+
pygame.display.update()

0 commit comments

Comments
 (0)