diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md b/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md new file mode 100644 index 0000000..2da034f --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md @@ -0,0 +1,68 @@ +# AI vs AI Tic-Tac-Toe Game 🎮 + +An interactive Tic-Tac-Toe game where two AI agents powered by different language models compete against each other built on phidata Agent Framework and Streamlit as UI. Watch as GPT-4O battles against either DeepSeek V3 or Google's Gemini 1.5 Flash in this classic game! + +## Features 🌟 + +- Player X: Powered by OpenAI's GPT-4o (o1 models as api is yet to roll out for tier) +- Player O: Choice between DeepSeek AI or Google's Gemini +- Interactive game board using Streamlit +- Real-time move visualization +- AI Judge to determine game outcomes +- Clean and intuitive user interface + +## Prerequisites 📋 + +- Python 3.8+ +- OpenAI API key +- Either DeepSeek API key or Google API key (for Player O) + +## How to Run 🚀 + +1. **Setup Environment** + ```bash + # Clone the repository + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_tic_tac_toe_agent + + # Install dependencies + pip install -r requirements.txt + ``` + +2. **Configure API Keys** + - Get OpenAI API key from [OpenAI Platform](https://platform.openai.com) + - Get Google API key from [Google AI Studio](https://aistudio.google.com) (if using Gemini) + - Get DeepSeek API key from DeepSeek platform [Deepseek platform](https://www.deepseek.com) (if using DeepSeek v3 model) + +4. **Run the Application** + ```bash + streamlit run ai_tic_tac_toe_agent.py + ``` + +5. **Using the Interface** + - Enter your API keys in the sidebar + - Click "Start Game" to begin + - Watch as the AI agents battle it out! + - Monitor the game progress and final results + +## Game Components 🎯 + +- **Game Board** + - 3x3 interactive grid + - Real-time move visualization + - Clear symbol placement (X/O) + +- **AI Players** + - Player X (GPT-4o): Strategic offensive moves + - Player O (DeepSeek/Gemini): Defensive countermoves since this agent started later + - AI Judge: Game outcome validation + +- **Game Flow** + - Alternating turns between AIs + - Move validation and error handling + - Winner determination + - Draw detection + +## Disclaimer ⚠️ + +This is a demonstration project showcasing AI capabilities in game playing. API costs will apply based on your usage of the OpenAI, DeepSeek, or Google APIs. diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/ai_tic_tac_toe_agent.py b/ai_agent_tutorials/ai_tic_tac_toe_agent/ai_tic_tac_toe_agent.py new file mode 100644 index 0000000..67d32f4 --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/ai_tic_tac_toe_agent.py @@ -0,0 +1,273 @@ +import re +import streamlit as st +from phi.agent import Agent +from phi.model.openai import OpenAIChat +from phi.model.deepseek import DeepSeekChat +from phi.model.google import Gemini + +# Streamlit App Title +st.title("🤖 Tic-Tac-Toe: AI vs AI") + +# Enhanced Welcome Message +with st.chat_message("assistant"): + st.markdown(""" + **Welcome to the Tic-Tac-Toe AI Battle!** 🎮 + This project pits two advanced AI agents against each other in a classic game of Tic-Tac-Toe. + Here's what you need to know: + """) + st.info(""" + - **Player X**: Powered by OpenAI's GPT-4. + - **Player O**: Powered by DeepSeek's AI or Google's Gemini (if DeepSeek API key is not provided). + - **How to Play**: Enter your API keys in the sidebar, click **Start Game**, and watch the AI battle it out! + - **Goal**: The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins. + - **Draw**: If the board fills up without a winner, the game ends in a draw. + """) + st.markdown("Ready to see who wins? Click the **Start Game** button below! 🚀") + +# Initialize the game board in session state +if 'board' not in st.session_state: + st.session_state.board = [[None, None, None], + [None, None, None], + [None, None, None]] + +# Function to display the board with better styling +def display_board(board): + st.markdown(""" + + """, unsafe_allow_html=True) + + st.write("Current Board:") + board_html = '
' + for row in board: + for cell in row: + cell_value = cell if cell is not None else " " + board_html += f'
{cell_value}
' + board_html += '
' + st.markdown(board_html, unsafe_allow_html=True) + +# Function to get the board state as a string +def get_board_state(board): + rows = [] + for i, row in enumerate(board): + row_str = " | ".join([f"({i},{j}) {cell or ' '}" for j, cell in enumerate(row)]) + rows.append(f"Row {i}: {row_str}") + return "\n".join(rows) + +# Function to check for a winner +def check_winner(board): + # Check rows + for row in board: + if row[0] == row[1] == row[2] and row[0] is not None: + return row[0] + # Check columns + for col in range(3): + if board[0][col] == board[1][col] == board[2][col] and board[0][col] is not None: + return board[0][col] + # Check diagonals + if board[0][0] == board[1][1] == board[2][2] and board[0][0] is not None: + return board[0][0] + if board[0][2] == board[1][1] == board[2][0] and board[0][2] is not None: + return board[0][2] + # Check for draw + if all(cell is not None for row in board for cell in row): + return "Draw" + return None + +# Sidebar for API keys +st.sidebar.header("API Keys") +openai_api_key = st.sidebar.text_input("Enter your OpenAI API Key", type="password") +deepseek_api_key = st.sidebar.text_input("Enter your DeepSeek API Key", type="password") +google_api_key = st.sidebar.text_input("Enter your Google API Key (for Gemini)", type="password") + +if openai_api_key: + st.session_state.openai_api_key = openai_api_key +if deepseek_api_key: + st.session_state.deepseek_api_key = deepseek_api_key +if google_api_key: + st.session_state.google_api_key = google_api_key + +# Initialize agents if API keys are provided +if 'openai_api_key' in st.session_state: + player_x = Agent( + name="Player X", + model=OpenAIChat(id="gpt-4o", temperature=0.1, api_key=st.session_state.openai_api_key), + instructions=[ + "You are a Tic-Tac-Toe player using the symbol 'X'.", + "Your opponent is using the symbol 'O'. Block their potential winning moves.", + "Make your move in the format 'row, col' based on the current board state.", + "Strategize to win by placing your symbol in a way that blocks your opponent from forming a straight line.", + "Do not include any explanations or extra text. Only provide the move.", + "Row and column indices start from 0.", + ], + markdown=True, + ) + + # Initialize Player O with DeepSeek or Google Gemini + if 'deepseek_api_key' in st.session_state: + player_o = Agent( + name="Player O", + model=DeepSeekChat(api_key=st.session_state.deepseek_api_key), + instructions=[ + "You are a Tic-Tac-Toe player using the symbol 'O'.", + "Your opponent is using the symbol 'X'. Block their potential winning moves.", + "Make your move in the format 'row, col' based on the current board state.", + "Strategize to win by placing your symbol in a way that blocks your opponent from forming a straight line.", + "Do not include any explanations or extra text. Only provide the move.", + "Row and column indices start from 0.", + ], + markdown=True, + ) + elif 'google_api_key' in st.session_state: + player_o = Agent( + name="Player O", + model=Gemini(id="gemini-1.5-flash", api_key=st.session_state.google_api_key), + instructions=[ + "You are a Tic-Tac-Toe player using the symbol 'O'.", + "Your opponent is using the symbol 'X'. Block their potential winning moves.", + "Make your move in the format 'row, col' based on the current board state.", + "Strategize to win by placing your symbol in a way that blocks your opponent from forming a straight line.", + "Do not include any explanations or extra text. Only provide the move.", + "Row and column indices start from 0.", + ], + markdown=True, + ) + else: + st.warning("Please provide either a DeepSeek API key or a Google API key for Player O.") + + judge = Agent( + name="Judge", + model=OpenAIChat(id="gpt-4o", temperature=0.1, api_key=st.session_state.openai_api_key), + instructions=[ + "You are the judge of a Tic-Tac-Toe game.", + "The board is presented as rows with positions separated by '|'.", + "Rows are labeled from 0 to 2, and columns from 0 to 2.", + "Example board state:", + "Row 0: (0,0) X | (0,1) | (0,2) O", + "Row 1: (1,0) O | (1,1) X | (1,2) X", + "Row 2: (2,0) X | (2,1) O | (2,2) O", + "Determine the winner based on this board state.", + "The winner is the player with three of their symbols in a straight line (row, column, or diagonal).", + "If the board is full and there is no winner, declare a draw.", + "Provide only the result (e.g., 'Player X wins', 'Player O wins', 'Draw').", + ], + markdown=True, + ) + + # Function to extract the move from the agent's response + def extract_move(response): + content = response.content.strip() + match = re.search(r'\d\s*,\s*\d', content) + if match: + move = match.group().replace(' ', '') + return move + numbers = re.findall(r'\d+', content) + if len(numbers) >= 2: + row = int(numbers[0]) + col = int(numbers[1]) + return f"{row},{col}" + return None + + # Game loop + def play_game(): + if 'current_player' not in st.session_state: + st.session_state.current_player = player_x + if 'symbol' not in st.session_state: + st.session_state.symbol = "X" + if 'move_count' not in st.session_state: + st.session_state.move_count = 0 + + max_moves = 9 + winner = None # Initialize winner variable + + while st.session_state.move_count < max_moves: + # Display the board + display_board(st.session_state.board) + + # Prepare the board state for the agent + board_state = get_board_state(st.session_state.board) + move_prompt = ( + f"Current board state:\n{board_state}\n" + f"{st.session_state.current_player.name}'s turn. Make your move in the format 'row, col'." + ) + + # Get the current player's move + with st.chat_message("assistant"): + st.write(f"**{st.session_state.current_player.name}'s turn:**") + move_response = st.session_state.current_player.run(move_prompt) + st.code(f"Agent {st.session_state.current_player.name} response:\n{move_response.content}", language="markdown") + move = extract_move(move_response) + st.write(f"**Extracted move:** {move}") + + if move is None: + st.error("Invalid move! Please use the format 'row, col'.") + continue + + try: + row, col = map(int, move.split(',')) + if st.session_state.board[row][col] is not None: + st.error("Invalid move! Cell already occupied.") + continue + st.session_state.board[row][col] = st.session_state.symbol + except (ValueError, IndexError): + st.error("Invalid move! Please use the format 'row, col'.") + continue + + # Check for a winner or draw + winner = check_winner(st.session_state.board) + if winner: + break # Exit the loop if there's a winner + + # Switch players + st.session_state.current_player = player_o if st.session_state.current_player == player_x else player_x + st.session_state.symbol = "O" if st.session_state.symbol == "X" else "X" + st.session_state.move_count += 1 + + # After the game loop, display the final board and involve the judge agent + st.write("**Final Board:**") + display_board(st.session_state.board) + + if winner: + st.success(f"**Result:** {winner}") + else: + st.success("**Result:** Draw") + + # Judge's announcement + st.write("\n**Game Over. Judge is determining the result...**") + st.write("**Final board state passed to judge:**") + st.code(get_board_state(st.session_state.board), language="markdown") + judge_prompt = ( + f"Final board state:\n{get_board_state(st.session_state.board)}\n" + f"Determine the winner and announce the result." + ) + judge_response = judge.run(judge_prompt) + st.code(f"Judge's raw response:\n{judge_response.content}", language="markdown") + announcement = judge_response.content.strip() + st.success(f"**Judge's Announcement:** {announcement}") + + # Start Game Button + if st.button("Start Game"): + st.session_state.board = [[None, None, None], + [None, None, None], + [None, None, None]] + st.session_state.current_player = player_x + st.session_state.symbol = "X" + st.session_state.move_count = 0 + play_game() +else: + st.warning("Please enter your OpenAI API key and either Deepseek/Gemini API key to start the game.") \ No newline at end of file diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/requirements.txt b/ai_agent_tutorials/ai_tic_tac_toe_agent/requirements.txt new file mode 100644 index 0000000..4129d50 --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/requirements.txt @@ -0,0 +1,4 @@ +streamlit==1.41.1 +phidata==2.7.3 +openai==1.58.1 +google-generativeai==0.8.3