AI_Diplomacy/bot_client/websocket_client_example.py
Tyler Marques aa0e5852e5
WIP: Starting work on running games via websocket
First crack, mostly Claude, on running each agent as an individual
connection to the server via WebSocket.
2025-07-29 15:57:42 -07:00

201 lines
6.6 KiB
Python

"""
Simple example demonstrating how to use the WebSocketDiplomacyClient.
This script shows basic operations like connecting, creating/joining games,
and interacting with a Diplomacy server via WebSocket.
"""
import asyncio
from loguru import logger
from websocket_diplomacy_client import connect_to_diplomacy_server
async def basic_client_example():
"""
Basic example showing how to connect and interact with a Diplomacy server.
"""
try:
# Connect to the server
logger.info("Connecting to Diplomacy server...")
client = await connect_to_diplomacy_server(
hostname="localhost",
port=8432,
username="test_player",
password="test_password",
)
logger.info("Connected successfully!")
# List available games
logger.info("Listing available games...")
games = await client.list_games()
logger.info(f"Found {len(games)} games:")
for game in games:
logger.info(
f" Game {game.get('game_id', 'unknown')}: {game.get('status', 'unknown')} "
f"({game.get('n_players', 0)}/{game.get('n_controls', 0)} players)"
)
# Get available maps
logger.info("Getting available maps...")
maps = await client.get_available_maps()
logger.info(f"Available maps: {list(maps.keys())}")
# Create a new game
logger.info("Creating a new game...")
game = await client.create_game(
map_name="standard",
rules=["NO_PRESS", "IGNORE_ERRORS", "POWER_CHOICE"],
power_name="FRANCE", # Control France
n_controls=1, # Only need 1 player to start (for testing)
deadline=None, # No time pressure
)
logger.info(f"Created game {client.game_id} as {client.power_name}")
# Get current game state
logger.info("Getting current game state...")
state = client.get_state()
logger.info(f"Current phase: {client.get_current_phase()}")
logger.info(f"France has {len(client.get_units('FRANCE'))} units")
# Get possible orders
logger.info("Getting possible orders for France...")
possible_orders = client.get_all_possible_orders()
france_orders = possible_orders.get("FRANCE", [])
logger.info(f"France can make {len(france_orders)} possible orders")
if france_orders:
logger.info(f"First few orders: {france_orders[:5]}")
# Submit some orders (example: hold all units)
logger.info("Submitting hold orders for all French units...")
units = client.get_units("FRANCE")
hold_orders = []
for unit in units:
# Format: "A PAR H" means Army in Paris holds
hold_orders.append(f"{unit} H")
if hold_orders:
await client.set_orders("FRANCE", hold_orders)
logger.info(f"Submitted orders: {hold_orders}")
# Try to process the game (might fail if we don't have admin rights)
logger.info("Attempting to process the game...")
try:
await client.process_game()
logger.info("Game processed successfully")
# Synchronize to get updated state
await client.synchronize()
logger.info(
f"After processing - Current phase: {client.get_current_phase()}"
)
except Exception as e:
logger.warning(f"Could not process game (normal if not admin): {e}")
# Leave the game
logger.info("Leaving the game...")
await client.game.leave()
logger.info("Left the game successfully")
except Exception as e:
logger.error(f"Error in example: {e}", exc_info=True)
finally:
# Clean up
if "client" in locals():
await client.close()
logger.info("Example completed")
async def join_existing_game_example(game_id: str):
"""
Example showing how to join an existing game.
Args:
game_id: ID of the game to join
"""
try:
logger.info(f"Joining existing game {game_id}...")
client = await connect_to_diplomacy_server(
hostname="localhost",
port=8432,
username="test_player_2",
password="test_password",
)
# Join as an observer first
game = await client.join_game(game_id=game_id, power_name=None)
logger.info(f"Joined game {game_id} as observer")
# Get game state
state = client.get_state()
logger.info(f"Game phase: {client.get_current_phase()}")
logger.info(f"Game status: {game.status}")
# List powers and their status
for power_name, power in client.powers.items():
logger.info(
f"{power_name}: {len(power.centers)} centers, "
f"{len(power.units)} units, eliminated: {power.is_eliminated()}"
)
except Exception as e:
logger.error(f"Error joining game: {e}", exc_info=True)
finally:
if "client" in locals():
await client.close()
async def message_sending_example():
"""
Example showing how to send diplomatic messages.
"""
try:
client = await connect_to_diplomacy_server()
# Create a game with PRESS allowed
game = await client.create_game(
rules=[
"IGNORE_ERRORS",
"POWER_CHOICE",
], # Remove NO_PRESS to allow messages
power_name="FRANCE",
n_controls=1,
)
# Send a public message
await client.send_message(
sender="FRANCE",
recipient="GLOBAL",
message="Greetings from France! Let's have a fair game.",
)
logger.info("Sent public message")
# Send a private message (would need another power to be present)
try:
await client.send_message(
sender="FRANCE",
recipient="ENGLAND",
message="Hello England, shall we discuss an alliance?",
)
logger.info("Sent private message to England")
except Exception as e:
logger.info(f"Could not send private message: {e}")
except Exception as e:
logger.error(f"Error in messaging example: {e}", exc_info=True)
finally:
if "client" in locals():
await client.close()
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
# Join existing game if game ID provided as argument
game_id = sys.argv[1]
asyncio.run(join_existing_game_example(game_id))
else:
# Run basic example
asyncio.run(basic_client_example())