From 649422a691492d128f6a872fa38d693e52e094c8 Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:50:30 +0530 Subject: [PATCH 1/7] Create tic_tac_toc.py --- Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py diff --git a/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py b/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py new file mode 100644 index 0000000..28aa3a2 --- /dev/null +++ b/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py @@ -0,0 +1,168 @@ +import pygame +import sys +import numpy as np + +pygame.init() + +WIDTH, HEIGHT = 600, 600 +LINE_WIDTH = 15 +BOARD_ROWS = 3 +BOARD_COLS = 3 +SQUARE_SIZE = WIDTH // BOARD_COLS +CIRCLE_RADIUS = SQUARE_SIZE // 3 +CIRCLE_WIDTH = 15 +CROSS_WIDTH = 25 +SPACE = SQUARE_SIZE // 4 + +BG_COLOR = (28, 170, 156) +LINE_COLOR = (23, 145, 135) +CIRCLE_COLOR = (239, 231, 200) +CROSS_COLOR = (66, 66, 66) + +screen = pygame.display.set_mode((WIDTH, HEIGHT)) +pygame.display.set_caption('Tic Tac Toe') +screen.fill(BG_COLOR) + +board = np.zeros((BOARD_ROWS, BOARD_COLS)) + +def draw_lines(): + for row in range(1, BOARD_ROWS): + pygame.draw.line(screen, LINE_COLOR, (0, row * SQUARE_SIZE), (WIDTH, row * SQUARE_SIZE), LINE_WIDTH) + for col in range(1, BOARD_COLS): + pygame.draw.line(screen, LINE_COLOR, (col * SQUARE_SIZE, 0), (col * SQUARE_SIZE, HEIGHT), LINE_WIDTH) + +# Draw figures (O and X) +def draw_figures(): + for row in range(BOARD_ROWS): + for col in range(BOARD_COLS): + if board[row][col] == 1: + pygame.draw.circle(screen, CIRCLE_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, CROSS_COLOR, + (col * SQUARE_SIZE + SPACE, row * SQUARE_SIZE + SQUARE_SIZE - SPACE), + (col * SQUARE_SIZE + SQUARE_SIZE - SPACE, row * SQUARE_SIZE + SPACE), CROSS_WIDTH) + pygame.draw.line(screen, CROSS_COLOR, + (col * SQUARE_SIZE + SPACE, row * SQUARE_SIZE + SPACE), + (col * SQUARE_SIZE + SQUARE_SIZE - SPACE, row * SQUARE_SIZE + SQUARE_SIZE - SPACE), + 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(): + return np.all(board != 0) + +def check_win(player): + + for row in range(BOARD_ROWS): + if np.all(board[row, :] == player): + return True + for col in range(BOARD_COLS): + if np.all(board[:, col] == player): + return True + if board[0, 0] == player and board[1, 1] == player and board[2, 2] == player: + return True + if board[0, 2] == player and board[1, 1] == player and board[2, 0] == player: + return True + return False + + +# Minimax algorithm +def minimax(board, depth, is_maximizing): + if check_win(2): # AI win + return 1 + elif check_win(1): # Player win + return -1 + elif is_board_full(): + return 0 + + if is_maximizing: + best_score = -np.inf + for row in range(BOARD_ROWS): + for col in range(BOARD_COLS): + if available_square(row, col): + board[row][col] = 2 + score = minimax(board, depth + 1, False) + board[row][col] = 0 + best_score = max(score, best_score) + return best_score + else: + best_score = np.inf + for row in range(BOARD_ROWS): + for col in range(BOARD_COLS): + if available_square(row, col): + board[row][col] = 1 + score = minimax(board, depth + 1, True) + board[row][col] = 0 + best_score = min(score, best_score) + return best_score + + +# AI Move +def ai_move(): + best_score = -np.inf + move = None + for row in range(BOARD_ROWS): + for col in range(BOARD_COLS): + if available_square(row, col): + 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: + mark_square(move[0], move[1], 2) + +def restart(): + screen.fill(BG_COLOR) + draw_lines() + global board + board = np.zeros((BOARD_ROWS, BOARD_COLS)) + + +player = 1 # Player 1 is human +game_over = False + +draw_lines() + +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] # X coordinate + mouseY = event.pos[1] # Y coordinate + + clicked_row = mouseY // SQUARE_SIZE + clicked_col = mouseX // SQUARE_SIZE + + if available_square(clicked_row, clicked_col): + mark_square(clicked_row, clicked_col, player) + if check_win(player): + game_over = True + player = 2 + + if player == 2 and not game_over: + ai_move() + if check_win(2): + game_over = True + player = 1 + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_r: + restart() + game_over = False + player = 1 + + draw_figures() + pygame.display.update() From 94ef256b40aa7e79a0c4869853049a58bd3005f5 Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:05:49 +0530 Subject: [PATCH 2/7] Create README.md --- Tic-Tac-Toc using AI (min-max)/README.md | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Tic-Tac-Toc using AI (min-max)/README.md diff --git a/Tic-Tac-Toc using AI (min-max)/README.md b/Tic-Tac-Toc using AI (min-max)/README.md new file mode 100644 index 0000000..959774b --- /dev/null +++ b/Tic-Tac-Toc using AI (min-max)/README.md @@ -0,0 +1,48 @@ +# Tic-Tac-Toe Game with AI + +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. + +### Key Features: +- **Two Players**: Play against an AI or another human player. +- **Minimax Algorithm**: The AI makes optimal moves based on the Minimax strategy. +- **Graphical User Interface**: A simple and intuitive GUI using Pygame. +- **Reset Option**: Restart the game easily at any time. + +# Prerequisites +The following libraries are required to run the script: +```bash +pip install pygame numpy +``` + +# Installing Instructions +1. **Clone the Repository**: + Clone this repository to your local machine using: + ```bash + git clone + ``` + +2. **Install Dependencies**: + Navigate to the project directory and install the required packages: + ```bash + pip install pygame numpy + ``` + +3. **Run the Script**: + After cloning and installing dependencies, you can run the script directly: + ```bash + python tic_tac_toe.py + ``` + +4. **Customize the Script**: + You can modify game settings, such as board size and player options, directly in the script. + +# Usage +**Player vs AI**: Click on the grid to make your move. The AI will respond automatically. + +**Restart Game**: Press the R key to restart the game at any time. + +# Example +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. + +# Author +**[Naumantamboli](https://github.com/Naumantamboli)** From 36689b719c67a5d34b9c8ce07d1dad7ae8e1f460 Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:07:22 +0530 Subject: [PATCH 3/7] Create requirements.txt --- Tic-Tac-Toc using AI (min-max)/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Tic-Tac-Toc using AI (min-max)/requirements.txt diff --git a/Tic-Tac-Toc using AI (min-max)/requirements.txt b/Tic-Tac-Toc using AI (min-max)/requirements.txt new file mode 100644 index 0000000..4091431 --- /dev/null +++ b/Tic-Tac-Toc using AI (min-max)/requirements.txt @@ -0,0 +1,2 @@ +pygame +numpy From 13a28d21ef20f84475564b6d03092ace04d1cac4 Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:30:20 +0530 Subject: [PATCH 4/7] Update requirements.txt --- Tic-Tac-Toc using AI (min-max)/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tic-Tac-Toc using AI (min-max)/requirements.txt b/Tic-Tac-Toc using AI (min-max)/requirements.txt index 4091431..8a894f6 100644 --- a/Tic-Tac-Toc using AI (min-max)/requirements.txt +++ b/Tic-Tac-Toc using AI (min-max)/requirements.txt @@ -1,2 +1,2 @@ -pygame -numpy +pygame==2.1.3 +numpy==1.23.5 From f739cfd38f21610c1e84c92cdb589035e889c8a5 Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:34:55 +0530 Subject: [PATCH 5/7] Update tic_tac_toc.py --- Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py b/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py index 28aa3a2..f6057e1 100644 --- a/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py +++ b/Tic-Tac-Toc using AI (min-max)/tic_tac_toc.py @@ -18,13 +18,17 @@ LINE_COLOR = (23, 145, 135) CIRCLE_COLOR = (239, 231, 200) CROSS_COLOR = (66, 66, 66) +TEXT_COLOR = (255, 255, 255) screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('Tic Tac Toe') screen.fill(BG_COLOR) +font = pygame.font.Font(None, 40) # Font for displaying messages board = np.zeros((BOARD_ROWS, BOARD_COLS)) +difficulty = "medium" # AI difficulty level ("easy", "medium", "hard") + def draw_lines(): for row in range(1, BOARD_ROWS): pygame.draw.line(screen, LINE_COLOR, (0, row * SQUARE_SIZE), (WIDTH, row * SQUARE_SIZE), LINE_WIDTH) @@ -48,11 +52,9 @@ def draw_figures(): (col * SQUARE_SIZE + SQUARE_SIZE - SPACE, row * SQUARE_SIZE + SQUARE_SIZE - SPACE), CROSS_WIDTH) - def mark_square(row, col, player): board[row][col] = player - def available_square(row, col): return board[row][col] == 0 @@ -60,7 +62,6 @@ def is_board_full(): return np.all(board != 0) def check_win(player): - for row in range(BOARD_ROWS): if np.all(board[row, :] == player): return True @@ -73,8 +74,14 @@ def check_win(player): return True return False +def display_message(message): + text = font.render(message, True, TEXT_COLOR) + text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2)) + screen.blit(text, text_rect) + pygame.display.update() + pygame.time.wait(2000) # Wait for 2 seconds to display the message -# Minimax algorithm +# Minimax algorithm with difficulty levels def minimax(board, depth, is_maximizing): if check_win(2): # AI win return 1 @@ -104,8 +111,7 @@ def minimax(board, depth, is_maximizing): best_score = min(score, best_score) return best_score - -# AI Move +# AI Move based on difficulty level def ai_move(): best_score = -np.inf move = None @@ -118,16 +124,23 @@ def ai_move(): if score > best_score: best_score = score move = (row, col) + if move: mark_square(move[0], move[1], 2) +# Easy AI move: choose a random available square +def easy_ai_move(): + available_moves = [(row, col) for row in range(BOARD_ROWS) for col in range(BOARD_COLS) if available_square(row, col)] + if available_moves: + move = available_moves[np.random.randint(len(available_moves))] + mark_square(move[0], move[1], 2) + def restart(): screen.fill(BG_COLOR) draw_lines() global board board = np.zeros((BOARD_ROWS, BOARD_COLS)) - player = 1 # Player 1 is human game_over = False @@ -149,12 +162,18 @@ def restart(): if available_square(clicked_row, clicked_col): mark_square(clicked_row, clicked_col, player) if check_win(player): + display_message("Player Wins!") game_over = True player = 2 if player == 2 and not game_over: - ai_move() + if difficulty == "easy": + easy_ai_move() + else: + ai_move() + if check_win(2): + display_message("AI Wins!") game_over = True player = 1 @@ -164,5 +183,9 @@ def restart(): game_over = False player = 1 + if game_over and is_board_full(): + display_message("It's a Draw!") + game_over = True + draw_figures() pygame.display.update() From 113ee106ecb11f5f71f36a2b93cdebe29c3b8e4c Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:37:08 +0530 Subject: [PATCH 6/7] Update tic_tac_toc.py From cfa05e9c48f58820e99385e95387905aacfc79cb Mon Sep 17 00:00:00 2001 From: Nauman Tamboli <141002585+Naumantamboli@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:42:27 +0530 Subject: [PATCH 7/7] Update README.md --- Tic-Tac-Toc using AI (min-max)/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Tic-Tac-Toc using AI (min-max)/README.md b/Tic-Tac-Toc using AI (min-max)/README.md index 959774b..06d3e22 100644 --- a/Tic-Tac-Toc using AI (min-max)/README.md +++ b/Tic-Tac-Toc using AI (min-max)/README.md @@ -36,6 +36,11 @@ pip install pygame numpy 4. **Customize the Script**: You can modify game settings, such as board size and player options, directly in the script. +# Gameplay Instructions +- **Player vs AI:**: Click on the grid to make your move. The AI will respond automatically. +- **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. +- **Restart Game**: Press the R key to restart the game at any time. + # Usage **Player vs AI**: Click on the grid to make your move. The AI will respond automatically. @@ -43,6 +48,9 @@ pip install pygame numpy # Example 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. +![Game Screen](screenshots/screenshot1.png) +![Winning State](screenshots/screenshot2.png) + # Author **[Naumantamboli](https://github.com/Naumantamboli)**