AI_Diplomacy/bot_client/WEBSOCKET_CLIENT_README.md
Tyler Marques 78d9ed6818
General house keeping, and the start of the bot_client
Signed-off-by: Tyler Marques <me@tylermarques.com>
2025-07-29 15:56:12 -07:00

7.6 KiB

WebSocket Diplomacy Client

This directory contains a WebSocket-based client for connecting to a Diplomacy server, designed as a drop-in replacement for direct Game() import usage in AI game simulations.

Files

  • websocket_diplomacy_client.py - Main WebSocket client class
  • lm_game_websocket.py - WebSocket version of lm_game.py
  • websocket_client_example.py - Simple usage examples
  • WEBSOCKET_CLIENT_README.md - This documentation

Overview

The WebSocketDiplomacyClient provides a simplified interface for interacting with a remote Diplomacy server via WebSocket connections. It wraps the existing diplomacy client functionality and provides methods similar to the local Game class.

Key Features

  • Drop-in replacement for direct Game() usage
  • Async/await support for all operations
  • Automatic reconnection and synchronization
  • Multiple game management (create, join, list)
  • Full game interaction (orders, messages, state queries)
  • Authentication handling with username/password

Quick Start

1. Start a Diplomacy Server

First, start a Diplomacy server:

# From the diplomacy directory
python -m diplomacy.server.run --port 8432

2. Basic Client Usage

import asyncio
from websocket_diplomacy_client import connect_to_diplomacy_server

async def main():
    # Connect to server
    client = await connect_to_diplomacy_server(
        hostname="localhost",
        port=8432,
        username="player1",
        password="mypassword"
    )
    
    # Create a new game
    game = await client.create_game(
        map_name="standard",
        power_name="FRANCE",
        n_controls=1  # For testing
    )
    
    # Get current state
    print(f"Current phase: {client.get_current_phase()}")
    print(f"France units: {client.get_units('FRANCE')}")
    
    # Submit orders
    await client.set_orders('FRANCE', ["A PAR H", "F BRE H", "A MAR H"])
    
    # Process game (if admin)
    await client.process_game()
    
    # Clean up
    await client.close()

asyncio.run(main())

3. Run the WebSocket Version of lm_game.py

# Make sure the server is running first
python lm_game_websocket.py --hostname localhost --port 8432 --username ai_player --create_multi_power_game

API Reference

Connection and Authentication

# Connect to server
client = await connect_to_diplomacy_server(hostname, port, username, password)

# Or manual connection
client = WebSocketDiplomacyClient(hostname, port)
await client.connect_and_authenticate(username, password)

Game Management

# Create new game
game = await client.create_game(
    map_name="standard",
    rules=["NO_PRESS", "IGNORE_ERRORS", "POWER_CHOICE"],
    power_name="FRANCE",  # None for observer
    n_controls=7,
    deadline=None,
    registration_password=None
)

# Join existing game
game = await client.join_game(
    game_id="ABC123",
    power_name="ENGLAND",  # None for observer
    registration_password=None
)

# List available games
games = await client.list_games(
    game_id_filter=None,
    map_name=None,
    status=None,
    include_protected=False
)

Game Interaction

# Submit orders
await client.set_orders(power_name, ["A PAR H", "F BRE H"])

# Clear orders
await client.clear_orders(power_name)

# Set wait flag
await client.set_wait_flag(power_name, wait=True)

# Send diplomatic message
await client.send_message(
    sender="FRANCE",
    recipient="ENGLAND",  # or "GLOBAL"
    message="Hello!"
)

# Process game (admin only)
await client.process_game()

# Vote for draw
await client.vote(power_name, "yes")

State Queries

# Get current phase and state
current_phase = client.get_current_phase()
current_short_phase = client.get_current_short_phase()
state = client.get_state()

# Get power information
power = client.get_power("FRANCE")
units = client.get_units("FRANCE")
orderable_locations = client.get_orderable_locations("FRANCE")

# Get possible orders
all_possible_orders = client.get_all_possible_orders()

# Get game history
order_history = client.order_history
result_history = client.result_history
messages = client.messages

# Check game status
is_done = client.is_game_done
all_powers = client.powers

Synchronization

# Synchronize with server state
await client.synchronize()

# Get phase history
history = await client.get_phase_history(from_phase=None, to_phase=None)

Differences from Local Game Class

Async Operations

All operations that communicate with the server are async and must be awaited:

# Local Game
game.set_orders("FRANCE", ["A PAR H"])

# WebSocket Client  
await client.set_orders("FRANCE", ["A PAR H"])

Authentication Required

You must authenticate with the server before performing any operations:

await client.connect_and_authenticate("username", "password")

Game Creation/Joining

Instead of creating a local game object, you create or join games on the server:

# Local
game = Game()

# WebSocket
game = await client.create_game(power_name="FRANCE")

Limited Admin Operations

Some operations (like process_game()) require admin privileges on the server.

Command Line Arguments for lm_game_websocket.py

python lm_game_websocket.py [options]

Options:
  --hostname HOST         Server hostname (default: localhost)
  --port PORT            Server port (default: 8432)
  --username USER        Username for authentication (default: ai_player)
  --password PASS        Password for authentication (default: password)
  --game_id ID           Join existing game instead of creating new one
  --max_year YEAR        Maximum year to simulate (default: 1901)
  --num_negotiation_rounds N  Number of negotiation rounds (default: 0)
  --models MODEL_LIST    Comma-separated list of models for powers
  --planning_phase       Enable planning phase
  --create_multi_power_game   Create game and join multiple powers (testing)

Examples

Basic Server Interaction

python websocket_client_example.py

Join Existing Game

python websocket_client_example.py GAME_ID_HERE

Run AI vs AI Game

# Start server in one terminal
python -m diplomacy.server.run --port 8432

# Run AI game in another terminal
python lm_game_websocket.py --create_multi_power_game --models "gpt-4,claude-3,gpt-3.5-turbo,gemini-pro,gpt-4,claude-3,gpt-3.5-turbo"

Error Handling

The client includes automatic reconnection and synchronization. Common error scenarios:

  • Connection failures: Automatically retried with exponential backoff
  • Authentication errors: Raised immediately, check credentials
  • Permission errors: Some operations require admin/moderator rights
  • Game state mismatches: Automatic synchronization attempts to resolve

Troubleshooting

  1. "Must connect and authenticate first" - Call connect_and_authenticate() before other operations

  2. "Invalid client game" - The game object is no longer valid, try synchronizing or rejoining

  3. Connection timeouts - Check that the server is running and accessible

  4. Permission denied - Some operations require admin rights or game ownership

  5. Game not found - Verify the game ID exists and you have access

Integration with Existing Code

To convert existing code from local Game() usage:

  1. Replace Game() imports with WebSocketDiplomacyClient
  2. Add authentication step
  3. Add await to all game operations
  4. Handle the async context properly
  5. Replace direct game creation with create_game() or join_game()

The lm_game_websocket.py file demonstrates a complete conversion of the original lm_game.py script.