Skip to content

Commit

Permalink
Merge pull request #77 from Madhuvod/ai-chess
Browse files Browse the repository at this point in the history
Added new demo - AI Agents playing Chess
  • Loading branch information
Shubhamsaboo authored Jan 14, 2025
2 parents 273c4a5 + a6c13cc commit 2a3f173
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 0 deletions.
31 changes: 31 additions & 0 deletions ai_agent_tutorials/ai_chess_game/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# AI Chess Game - Autogen

This is a simple Chess game that uses an AI agents - Player black and player white to play the game. There's also a board proxy agent to execute the tools and manage the game. It is important to use a board proxy as a non-LLM "guard rail" to ensure the game is played correctly and to prevent agents from making illegal moves.

Two agents (agent_white and agent_black) are initialized using the OpenAI API key. These agents are configured to play chess as white and black, respectively.
A board_proxy agent is created to manage the board state and validate moves.
Functions (make_move and available_moves) are registered with the agents to allow them to interact with the board.


### How to get Started?

1. Clone the GitHub repository

```bash
git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git
cd ai_agent_tutorials/ai_chess_game
```
2. Install the required dependencies:

```bash
pip install -r requirements.txt
```
3. Get your OpenAI API Key

- Sign up for an [OpenAI account](https://platform.openai.com/) (or the LLM provider of your choice) and obtain your API key.

4. Run the Streamlit App
```bash
streamlit run ai_chess_agents.py
```

249 changes: 249 additions & 0 deletions ai_agent_tutorials/ai_chess_game/ai_chess_agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import chess
import chess.svg
import streamlit as st
from autogen import ConversableAgent, register_function

if "openai_api_key" not in st.session_state:
st.session_state.openai_api_key = None
if "board" not in st.session_state:
st.session_state.board = chess.Board()
if "made_move" not in st.session_state:
st.session_state.made_move = False
if "board_svg" not in st.session_state:
st.session_state.board_svg = None
if "move_history" not in st.session_state:
st.session_state.move_history = []
if "max_turns" not in st.session_state:
st.session_state.max_turns = 5

st.sidebar.title("Chess Agent Configuration")
openai_api_key = st.sidebar.text_input("Enter your OpenAI API key:", type="password")
if openai_api_key:
st.session_state.openai_api_key = openai_api_key
st.sidebar.success("API key saved!")

st.sidebar.info("""
For a complete chess game with potential checkmate, it would take max_turns > 200 approximately.
However, this will consume significant API credits and a lot of time.
For demo purposes, using 5-10 turns is recommended.
""")

max_turns_input = st.sidebar.number_input(
"Enter the number of turns (max_turns):",
min_value=1,
max_value=1000,
value=st.session_state.max_turns,
step=1
)

if max_turns_input:
st.session_state.max_turns = max_turns_input
st.sidebar.success(f"Max turns of total chess moves set to {st.session_state.max_turns}!")

st.title("Chess with AutoGen Agents")

def available_moves() -> str:
available_moves = [str(move) for move in st.session_state.board.legal_moves]
return "Available moves are: " + ",".join(available_moves)

def execute_move(move: str) -> str:
try:
chess_move = chess.Move.from_uci(move)
if chess_move not in st.session_state.board.legal_moves:
return f"Invalid move: {move}. Please call available_moves() to see valid moves."

# Update board state
st.session_state.board.push(chess_move)
st.session_state.made_move = True

# Generate and store board visualization
board_svg = chess.svg.board(st.session_state.board,
arrows=[(chess_move.from_square, chess_move.to_square)],
fill={chess_move.from_square: "gray"},
size=400)
st.session_state.board_svg = board_svg
st.session_state.move_history.append(board_svg)

# Get piece information
moved_piece = st.session_state.board.piece_at(chess_move.to_square)
piece_unicode = moved_piece.unicode_symbol()
piece_type_name = chess.piece_name(moved_piece.piece_type)
piece_name = piece_type_name.capitalize() if piece_unicode.isupper() else piece_type_name

# Generate move description
from_square = chess.SQUARE_NAMES[chess_move.from_square]
to_square = chess.SQUARE_NAMES[chess_move.to_square]
move_desc = f"Moved {piece_name} ({piece_unicode}) from {from_square} to {to_square}."
if st.session_state.board.is_checkmate():
winner = 'White' if st.session_state.board.turn == chess.BLACK else 'Black'
move_desc += f"\nCheckmate! {winner} wins!"
elif st.session_state.board.is_stalemate():
move_desc += "\nGame ended in stalemate!"
elif st.session_state.board.is_insufficient_material():
move_desc += "\nGame ended - insufficient material to checkmate!"
elif st.session_state.board.is_check():
move_desc += "\nCheck!"

return move_desc
except ValueError:
return f"Invalid move format: {move}. Please use UCI format (e.g., 'e2e4')."

def check_made_move(msg):
if st.session_state.made_move:
st.session_state.made_move = False
return True
else:
return False

if st.session_state.openai_api_key:
try:
agent_white_config_list = [
{
"model": "gpt-4o-mini",
"api_key": st.session_state.openai_api_key,
},
]

agent_black_config_list = [
{
"model": "gpt-4o-mini",
"api_key": st.session_state.openai_api_key,
},
]

agent_white = ConversableAgent(
name="Agent_White",
system_message="You are a professional chess player and you play as white. "
"First call available_moves() first, to get list of legal available moves. "
"Then call execute_move(move) to make a move.",
llm_config={"config_list": agent_white_config_list, "cache_seed": None},
)

agent_black = ConversableAgent(
name="Agent_Black",
system_message="You are a professional chess player and you play as black. "
"First call available_moves() first, to get list of legal available moves. "
"Then call execute_move(move) to make a move.",
llm_config={"config_list": agent_black_config_list, "cache_seed": None},
)

game_master = ConversableAgent(
name="Game_Master",
llm_config=False,
is_termination_msg=check_made_move,
default_auto_reply="Please make a move.",
human_input_mode="NEVER",
)

register_function(
execute_move,
caller=agent_white,
executor=game_master,
name="execute_move",
description="Call this tool to make a move.",
)

register_function(
available_moves,
caller=agent_white,
executor=game_master,
name="available_moves",
description="Get legal moves.",
)

register_function(
execute_move,
caller=agent_black,
executor=game_master,
name="execute_move",
description="Call this tool to make a move.",
)

register_function(
available_moves,
caller=agent_black,
executor=game_master,
name="available_moves",
description="Get legal moves.",
)

agent_white.register_nested_chats(
trigger=agent_black,
chat_queue=[
{
"sender": game_master,
"recipient": agent_white,
"summary_method": "last_msg",
}
],
)

agent_black.register_nested_chats(
trigger=agent_white,
chat_queue=[
{
"sender": game_master,
"recipient": agent_black,
"summary_method": "last_msg",
}
],
)

st.info("""
This chess game is played between two AG2 AI agents:
- **Agent White**: A GPT-4o-mini powered chess player controlling white pieces
- **Agent Black**: A GPT-4o-mini powered chess player controlling black pieces
The game is managed by a **Game Master** that:
- Validates all moves
- Updates the chess board
- Manages turn-taking between players
- Provides legal move information
""")

initial_board_svg = chess.svg.board(st.session_state.board, size=300)
st.subheader("Initial Board")
st.image(initial_board_svg)

if st.button("Start Game"):
st.session_state.board.reset()
st.session_state.made_move = False
st.session_state.move_history = []
st.session_state.board_svg = chess.svg.board(st.session_state.board, size=300)
st.info("The AI agents will now play against each other. Each agent will analyze the board, "
"request legal moves from the Game Master (proxy agent), and make strategic decisions.")
st.success("You can view the interaction between the agents in the terminal output, after the turns between agents end, you get view all the chess board moves displayed below!")
st.write("Game started! White's turn.")

chat_result = agent_black.initiate_chat(
recipient=agent_white,
message="Let's play chess! You go first, its your move.",
max_turns=st.session_state.max_turns,
summary_method="reflection_with_llm"
)
st.markdown(chat_result.summary)

# Display the move history (boards for each move)
st.subheader("Move History")
for i, move_svg in enumerate(st.session_state.move_history):
# Determine which agent made the move
if i % 2 == 0:
move_by = "Agent White" # Even-indexed moves are by White
else:
move_by = "Agent Black" # Odd-indexed moves are by Black

st.write(f"Move {i + 1} by {move_by}")
st.image(move_svg)

if st.button("Reset Game"):
st.session_state.board.reset()
st.session_state.made_move = False
st.session_state.move_history = []
st.session_state.board_svg = None
st.write("Game reset! Click 'Start Game' to begin a new game.")

except Exception as e:
st.error(f"An error occurred: {e}. Please check your API key and try again.")

else:
st.warning("Please enter your OpenAI API key in the sidebar to start the game.")
5 changes: 5 additions & 0 deletions ai_agent_tutorials/ai_chess_game/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
streamlit
chess==1.11.1
autogen==0.6.1
cairosvg
pillow

0 comments on commit 2a3f173

Please sign in to comment.