### Power Management and State Queries - Python Source: https://context7.com/context7/diplomacy_readthedocs_io_en_stable/llms.txt Provides examples of accessing and modifying power properties (name, abbreviation, centers, units, orders) and querying game state (status, current phase, game done/active). It also covers network-specific power properties and how to get unit lists and orderable locations. Includes functions for clearing power data and setting power controllers in network games. ```python from diplomacy import Game game = Game() france = game.get_power('FRANCE') # Power properties print(f"Power name: {france.name}") # 'FRANCE' print(f"Abbreviation: {france.abbrev}") # 'F' print(f"Supply centers: {france.centers}") # ['PAR', 'MAR', 'BRE'] print(f"Home centers: {france.homes}") # ['PAR', 'MAR', 'BRE'] print(f"Units: {france.units}") # ['A PAR', 'A MAR', 'F BRE'] print(f"Orders: {france.orders}") # {} # Power status print(f"Is eliminated: {france.is_eliminated()}") # False print(f"Is dummy: {france.is_dummy()}") # True (not controlled) print(f"Civil disorder: {france.civil_disorder}") # False # Network game power properties if game.is_player_game(): print(f"Controller: {france.get_controller()}") print(f"Is controlled: {france.is_controlled()}") print(f"Vote: {france.vote}") # 'yes', 'no', 'neutral' # Game state queries print(f"Game status: {game.status}") print(f"Current phase: {game.phase}") print(f"Is game done: {game.is_game_done}") print(f"Is game active: {game.is_game_active}") # Get units for all powers or specific power all_units = game.get_units() print(f"All units: {all_units}") france_units = game.get_units('FRANCE') print(f"France units: {france_units}") # Get orderable locations orderable = game.get_orderable_locations('FRANCE') print(f"France orderable: {orderable}") # Clear power data game.clear_orders('FRANCE') game.clear_units('FRANCE') game.clear_centers('FRANCE') # Set power controller (network games) game.set_controlled('FRANCE', 'username123') ``` -------------------------------- ### Send GET Request Helper Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/integration/webdiplomacy_net/api This is a placeholder for a helper method designed to send GET requests to a specified URL. The implementation details are not provided in this snippet, but it's intended to be part of a class that handles network communications. ```python # ---- Helper methods ---- @gen.coroutine def _send_get_request(self, url): ``` -------------------------------- ### Send GET Request to API (Python) Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/integration/webdiplomacy_net/api This Python function sends an authenticated GET request to a specified API endpoint. It utilizes the Tornado `HTTPRequest` and `http_client.fetch` for asynchronous fetching. Dependencies include the Tornado library and an API key. It returns the HTTP response object. ```python @gen.coroutine def _send_get_request(self, url): """ Helper method to send a get request to the API endpoint """ http_request = HTTPRequest(url=url, method='GET', headers={'Authorization': 'Bearer %s' % self.api_key}, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, user_agent=API_USER_AGENT) http_response = yield self.http_client.fetch(http_request, raise_error=False) return http_response ``` -------------------------------- ### Initialize Game Flow and Phase in Python Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/map This Python code sets up the default game flow, including the sequence of phases and their abbreviations. It also validates the initial game phase provided, ensuring it has the correct format and extracting the starting year. ```python # Ensure a default game-year FLOW self.flow = ['SPRING:MOVEMENT,RETREATS', 'FALL:MOVEMENT,RETREATS', 'WINTER:ADJUSTMENTS'] self.flow_sign = 1 self.seq = ['NEWYEAR', 'SPRING MOVEMENT', 'SPRING RETREATS', 'FALL MOVEMENT', 'FALL RETREATS', 'WINTER ADJUSTMENTS'] self.phase_abbrev = {'M': 'MOVEMENT', 'R': 'RETREATS', 'A': 'ADJUSTMENTS'} # Validating initial game phase self.phase = self.phase or 'SPRING 1901 MOVEMENT' phase = self.phase.split() if len(phase) != 3: self.error += [err.MAP_BAD_PHASE % self.phase] else: self.first_year = int(phase[1]) ``` -------------------------------- ### Get Current Game Phase Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Returns the current phase of the game. The phase is represented as a string, for example, 'S1901M', 'FORMING', or 'COMPLETED'. ```python def get_current_phase(self): """ Returns the current phase (format 'S1901M' or 'FORMING' or 'COMPLETED') """ return self._phase_abbr() ``` -------------------------------- ### Initialize and Configure Diplomacy Game Engine Source: https://context7.com/context7/diplomacy_readthedocs_io_en_stable/llms.txt Demonstrates how to create and configure a Diplomacy game engine instance. Allows setting a specific map and game rules. Retrieves current game phase, status, and details about powers and their units. ```python from diplomacy import Game # Create a standard game starting in Spring 1901 game = Game() # Create game with specific map and rules game = Game( map_name='standard', rules=['NO_PRESS', 'POWER_CHOICE'] ) # Get current game phase current_phase = game.get_current_phase() # Returns 'S1901M' print(f"Current phase: {current_phase}") print(f"Game status: {game.status}") # 'forming', 'active', 'paused', 'completed', 'canceled' # Access powers in the game powers = game.powers # Dict: {'FRANCE': Power, 'ENGLAND': Power, ...} france = game.get_power('FRANCE') print(f"France centers: {france.centers}") # ['PAR', 'MAR', 'BRE'] print(f"France units: {france.units}") # ['A PAR', 'A MAR', 'F BRE'] ``` -------------------------------- ### Get Specific Phase from History Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Retrieves a single game phase's data from history based on its name. This is a convenience method that calls `get_phase_history` with the same start and end phase. ```python def get_phase_from_history(self, short_phase_name, game_role=None): """ Return a game phase data corresponding to given phase from phase history. """ return self.get_phase_history(short_phase_name, short_phase_name, game_role)[0] ``` -------------------------------- ### Create, Join, and List Diplomacy Network Games (Python) Source: https://context7.com/context7/diplomacy_readthedocs_io_en_stable/llms.txt Demonstrates how to connect to a Diplomacy server, create new games with specific configurations, list available games, and join existing games as a player or observer. Requires 'tornado' and 'diplomacy.client' libraries. ```python from diplomacy.client.connection import connect from tornado import gen from tornado.ioloop import IOLoop @gen.coroutine def game_operations(): connection = yield connect('localhost', 8888) channel = yield connection.authenticate('player1', 'password') # Create a new game as France game = yield channel.create_game( game_id='game123', n_controls=7, # Number of powers required to start deadline=300, # Seconds per phase (0 = no deadline) registration_password='secret', power_name='FRANCE', map_name='standard' ) print(f"Created game: {game.game_id}") print(f"Controlling power: {game.role}") # List available games games = yield channel.list_games( status='forming', map_name='standard', include_protected=True ) for game_info in games: print(f"Game {game_info.game_id}: {game_info.n_controls} players") # Join existing game as England game2 = yield channel.join_game( game_id='game456', power_name='ENGLAND', registration_password='secret' ) print(f"Joined game as: {game2.role}") # Join as observer (can see orders but not messages) observer_game = yield channel.join_game(game_id='game789') print(f"Observing game: {observer_game.game_id}") IOLoop.current().run_sync(game_operations) ``` -------------------------------- ### Get Phase History from Timestamp Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Returns a list of game phase data starting from the earliest phase whose state timestamp is greater than or equal to the given timestamp. If no such phase is found, an empty list is returned. ```python def phase_history_from_timestamp(self, timestamp): """ Return list of game phase data from game history for which state timestamp >= given timestamp. """ earliest_phase = '' for state in self.state_history.reversed_values(): if state['timestamp'] < timestamp: break earliest_phase = state['name'] return self.get_phase_history(from_phase=earliest_phase) if earliest_phase else [] ``` -------------------------------- ### Initialize Game State at the Beginning of a Phase Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Sets up the initial game state for a new phase. This includes resetting notes, setting victory conditions, creating placeholder power objects for any missing powers, initializing all existing powers, and rebuilding necessary game caches. This method is crucial for starting new turns or phases correctly. ```python def _begin(self): """ Called to begin the game and move to the start phase :return: Nothing """ self._move_to_start_phase() self.note = '' self.win = self.victory[0] # Create dummy power objects for non-loaded powers. for power_name in self.map.powers: if power_name not in self.powers: self.powers[power_name] = Power(self, power_name, role=self.role) # Initialize all powers - Starter having type won't be initialized. for starter in self.powers.values(): starter.initialize(self) # Build caches self.build_caches() ``` -------------------------------- ### Get Possible Convoy Destinations - Python Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Returns a list of potential destinations a unit can reach via convoy from a given starting location. It handles two cases: when the unit is being convoyed and when it is acting as a convoyer. It also supports excluding specific convoying locations. ```python def _get_convoy_destinations(self, unit, start, unit_is_convoyer=False, exclude_convoy_locs=None): """ Returns a list of possible convoy destinations for a unit :param unit: The unit BEING convoyed (e.g. 'A' or 'F') :param start: The start location of the unit (e.g. 'LON') :param unit_is_convoyer: Boolean flag. If true, list all the dests that an unit being convoyed by unit could reach :param exclude_convoy_locs: Optional. A list of convoying location that needs to be excluded from all paths. :return: A list of convoying destinations (e.g. ['PAR', 'MAR']) that can be reached from start """ if unit == 'A' and unit_is_convoyer: return [] if unit == 'F' and not unit_is_convoyer: return [] # Building cache self._build_list_possible_convoys() # If we are moving via convoy, we just read the destinations from the table if not unit_is_convoyer: if not exclude_convoy_locs: return list(self.convoy_paths_dest.get(start, {}).keys()) # We need to loop to make sure there is a path without the excluded convoyer dests = [] for dest, paths in self.convoy_paths_dest.get(start, {}).items(): for path in paths: if not [1 for excluded_loc in exclude_convoy_locs if excluded_loc in path]: dests += [dest] break return dests # If we are convoying, we need to loop through the possible convoy paths valid_dests = set([]) for _, fleets, dests in self.convoy_paths_possible: if start in fleets and (exclude_convoy_locs is None or not [1 for excluded_loc in exclude_convoy_locs if excluded_loc in fleets]): valid_dests |= dests return list(valid_dests) ``` -------------------------------- ### Channel Class Initialization Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/client/channel Initializes a Channel object, establishing an authenticated connection over a socket. Key properties include the connection object, an authentication token, and a dictionary to manage game instances associated with the channel. ```python class Channel: """ Channel - Represents an authenticated connection over a physical socket """ # pylint: disable=too-few-public-methods __slots__ = ['connection', 'token', 'game_id_to_instances', '__weakref__'] def __init__(self, connection, token): """ Initialize a channel. Properties: - **connection**: :class:`.Connection` object from which this channel originated. - **token**: Channel token, used to identify channel on server. - **game_id_to_instances**: Dictionary mapping a game ID to :class:`.NetworkGame` objects loaded for this game. Each :class:`.NetworkGame` has a specific role, which is either an observer role, an omniscient role, or a power (player) role. Network games for a specific game ID are managed within a :class:`.GameInstancesSet`, which makes sure that there will be at most 1 :class:`.NetworkGame` instance per possible role. :param connection: a Connection object. :param token: Channel token. :type connection: diplomacy.client.connection.Connection :type token: str """ self.connection = connection self.token = token self.game_id_to_instances = {} # {game id => GameInstances} ``` -------------------------------- ### Creating and Running Local Games Source: https://context7.com/context7/diplomacy_readthedocs_io_en_stable/llms.txt Initialize a game engine instance to play Diplomacy locally without network connections. You can create a standard game or a game with specific map and rules. Access game properties like phase, status, powers, centers, and units. ```APIDOC ## Creating and Running Local Games ### Description Initialize a game engine instance to play Diplomacy locally without network connections. ### Method ```python from diplomacy import Game # Create a standard game starting in Spring 1901 game = Game() # Create game with specific map and rules game = Game( map_name='standard', rules=['NO_PRESS', 'POWER_CHOICE'] ) ``` ### Accessing Game State ### Description Get current game phase, status, powers, and details about specific powers. ### Method ```python # Get current game phase current_phase = game.get_current_phase() # Returns 'S1901M' print(f"Current phase: {current_phase}") print(f"Game status: {game.status}") # 'forming', 'active', 'paused', 'completed', 'canceled' # Access powers in the game powers = game.powers # Dict: {'FRANCE': Power, 'ENGLAND': Power, ...} france = game.get_power('FRANCE') print(f"France centers: {france.centers}") # ['PAR', 'MAR', 'BRE'] print(f"France units: {france.units}") # ['A PAR', 'A MAR', 'F BRE'] ``` ``` -------------------------------- ### Move Game to the Map's Starting Phase Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Resets the game to the initial phase defined by the map configuration. This method is typically called at the beginning of a game or after certain reset operations. It ensures that game variables like `self.phase` and `self.phase_type` are set to their starting values. ```python def _move_to_start_phase(self): """ Moves to the map's start phase :return: Nothing, but sets the self.phase and self.phase_type settings """ # Retrieve the beginning phase and phase type from the map ``` -------------------------------- ### Initialize Connection Object (Python) Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/client/connection Initializes a Connection object to manage websocket communication. It sets up hostname, port, SSL preference, and internal state variables for managing connection status, requests, and responses. This constructor should not be called directly; use the `connect` function instead. ```python class Connection: """ Connection class. The connection class should not be initiated directly, but through the connect method .. code-block:: python >>> from diplomacy.client.connection import connect >>> connection = await connect(hostname, port) Properties: - **hostname**: :class:`str` hostname to connect (e.g. 'localhost') - **port**: :class:`int` port to connect (e.g. 8888) - **use_ssl**: :class:`bool` telling if connection should be securized (True) or not (False). - **url**: (property) :class:`str` websocket url to connect (generated with hostname and port) - **connection**: :class:`tornado.websocket.WebSocketClientConnection` a tornado websocket connection object - **connection_count**: :class:`int` number of successful connections from this Connection object. Used to check if message callbacks is already launched (if count > 0). - **is_connecting**: :class:`tornado.locks.Event` a tornado Event used to keep connection status. No request can be sent while is_connecting. If connected, Synchronize requests can be sent immediately even if is_reconnecting. Other requests must wait full reconnection. - **is_reconnecting**: :class:`tornado.locks.Event` a tornado Event used to keep re-connection status. Non-synchronize request cannot be sent while is_reconnecting. If reconnected, all requests can be sent. - **channels**: a :class:`weakref.WeakValueDictionary` mapping channel token to :class:`.Channel` object. - **requests_to_send**: a :class:`Dict` mapping a request ID to the context of a request **not sent**. If we are disconnected when trying to send a request, then request context is added to this dictionary to be send later once reconnected. - **requests_waiting_responses**: a :class:`Dict` mapping a request ID to the context of a request **sent**. Contains requests that are waiting for a server response. - **unknown_tokens**: :class:`set` a set of unknown tokens. We can safely ignore them, as the server has been notified. """ __slots__ = ['hostname', 'port', 'use_ssl', 'connection', 'is_connecting', 'is_reconnecting', 'connection_count', 'channels', 'requests_to_send', 'requests_waiting_responses', 'unknown_tokens'] def __init__(self, hostname, port, use_ssl=False): """ Constructor The connection class should not be initiated directly, but through the connect method .. code-block:: python >>> from diplomacy.client.connection import connect >>> connection = await connect(hostname, port) :param hostname: hostname to connect (e.g. 'localhost') :param port: port to connect (e.g. 8888) :param use_ssl: telling if connection should be securized (True) or not (False). :type hostname: str :type port: int :type use_ssl: bool """ self.hostname = hostname self.port = port self.use_ssl = bool(use_ssl) self.connection = None self.connection_count = 0 self.is_connecting = Event() self.is_reconnecting = Event() self.channels = weakref.WeakValueDictionary() # {token => Channel} self.requests_to_send = {} # type: Dict[str, RequestFutureContext] self.requests_waiting_responses = {} # type: Dict[str, RequestFutureContext] self.unknown_tokens = set() ``` -------------------------------- ### Renderer Class Constructor (Python) Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/renderer Initializes the Renderer object, taking a game instance and an optional SVG path. It loads the map SVG, defaulting to a file in the 'maps/svg' directory if no path is provided. It also loads game metadata. ```python class Renderer: """ Renderer object responsible for rendering a game state to svg """ def __init__(self, game, svg_path=None): """ Constructor :param game: The instantiated game object to render :param svg_path: Optional. Can be set to the full path of a custom SVG to use for rendering the map. :type game: diplomacy.Game :type svg_path: str, optional """ self.game = game self.metadata = {} self.xml_map = None # If no SVG path provided, we default to the one in the maps folder if not svg_path: for file_name in [self.game.map.name + '.svg', self.game.map.root_map + '.svg']: svg_path = os.path.join(settings.PACKAGE_DIR, 'maps', 'svg', file_name) if os.path.exists(svg_path): break # Loading XML if os.path.exists(svg_path): self.xml_map = minidom.parse(svg_path).toxml() ``` -------------------------------- ### Get Available Maps Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/communication/requests Fetches a list of all maps available on the game server. ```APIDOC ## GET /api/maps ### Description This endpoint retrieves a list of all available maps that can be used to start a new game. The response includes details about each map, such as the names of the powers available for play. ### Method GET ### Endpoint /api/maps ### Parameters This endpoint does not require any parameters. ### Request Body This endpoint does not accept a request body. ### Response #### Success Response (200) - **DataMaps** - A dictionary where keys are map names and values are dictionaries containing map information, including a list of power names for each map. #### Response Example ```json { "map_name_1": { "powers": ["Power1", "Power2", "Power3"] }, "map_name_2": { "powers": ["PowerA", "PowerB"] } } ``` ``` -------------------------------- ### Game Class Initialization - Python Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game The `__init__` method for the `Game` class initializes various game attributes, sets default values, and processes keyword arguments. It handles game-specific settings, rule management, and initial validation. ```python class Game(object): model = { strings.CONTROLLED_POWERS: parsing.OptionalValueType(parsing.SequenceType(str)), strings.DAIDE_PORT: parsing.OptionalValueType(int), strings.DEADLINE: parsing.DefaultValueType(int, 300), strings.ERROR: parsing.DefaultValueType(parsing.SequenceType(parsing.StringableType(err.Error)), []), strings.GAME_ID: parsing.OptionalValueType(str), strings.MAP_NAME: parsing.DefaultValueType(str, 'standard'), strings.MESSAGE_HISTORY: parsing.DefaultValueType(parsing.DictType(str, MESSAGES_TYPE), {}), strings.MESSAGES: parsing.DefaultValueType(MESSAGES_TYPE, []), strings.META_RULES: parsing.DefaultValueType(parsing.SequenceType(str), []), strings.N_CONTROLS: parsing.OptionalValueType(int), strings.NO_RULES: parsing.DefaultValueType(parsing.SequenceType(str, set), []), strings.NOTE: parsing.DefaultValueType(str, ''), strings.OBSERVER_LEVEL: parsing.OptionalValueType( parsing.EnumerationType((strings.MASTER_TYPE, strings.OMNISCIENT_TYPE, strings.OBSERVER_TYPE))), strings.ORDER_HISTORY: parsing.DefaultValueType( parsing.DictType(str, parsing.DictType(str, parsing.SequenceType(str))), {}), strings.OUTCOME: parsing.DefaultValueType(parsing.SequenceType(str), []), strings.PHASE: parsing.DefaultValueType(str, ''), strings.PHASE_ABBR: parsing.DefaultValueType(str, ''), strings.POWERS: parsing.DefaultValueType(parsing.DictType(str, parsing.JsonableClassType(Power)), {}), strings.REGISTRATION_PASSWORD: parsing.OptionalValueType(str), strings.RESULT_HISTORY: parsing.DefaultValueType(parsing.DictType(str, parsing.DictType( str, parsing.SequenceType(parsing.StringableType(common.StringableCode)))), {}), strings.ROLE: parsing.DefaultValueType(str, strings.SERVER_TYPE), strings.RULES: parsing.DefaultValueType(parsing.SequenceType(str, sequence_builder=list), ()), strings.STATE_HISTORY: parsing.DefaultValueType(parsing.DictType(str, dict), {}), strings.STATUS: parsing.DefaultValueType(parsing.EnumerationType(strings.ALL_GAME_STATUSES), strings.FORMING), strings.TIMESTAMP_CREATED: parsing.OptionalValueType(int), strings.VICTORY: parsing.DefaultValueType(parsing.SequenceType(int), []), strings.WIN: parsing.DefaultValueType(int, 0), strings.ZOBRIST_HASH: parsing.DefaultValueType(int, 0), } def __init__(self, game_id=None, **kwargs): """ Constructor """ self.victory = None self.no_rules = set() self.meta_rules = [] self.phase, self.note = '', '' self.map = None # type: Map self.powers = {} self.outcome, self.error, self.popped = [], [], [] self.orders, self.ordered_units = {}, {} self.phase_type = None self.win = None self.combat, self.command, self.result = {}, {}, {} self.supports, self.dislodged, self.lost = {}, {}, {} self.convoy_paths, self.convoy_paths_possible, self.convoy_paths_dest = {}, None, None self.zobrist_hash = 0 self.renderer = None self.game_id = None # type: str self.map_name = None # type: str self.messages = None # type: SortedDict self.role = None # type: str self.rules = [] self.state_history, self.order_history, self.result_history, self.message_history = {}, {}, {}, {} self.status = None # type: str self.timestamp_created = None # type: int self.n_controls = None self.deadline = 0 self.registration_password = None self.observer_level = None self.controlled_powers = None self.daide_port = None self.fixed_state = None # Caches self._unit_owner_cache = None # {(unit, coast_required): owner} # Remove rules from kwargs (if present), as we want to add them manually using self.add_rule(). rules = kwargs.pop(strings.RULES, None) # Update rules with game ID. kwargs[strings.GAME_ID] = game_id # Initialize game with kwargs. super(Game, self).__init__(**kwargs) # Check settings. if self.registration_password is not None and self.registration_password == '': raise exceptions.DiplomacyException('Registration password must be None or non-empty string.') if self.n_controls is not None and self.n_controls < 0: raise exceptions.NaturalIntegerException('n_controls must be a natural integer.') if self.deadline < 0: raise exceptions.NaturalIntegerException('Deadline must be a natural integer.') # Check rules. if rules is None: rules = list(DEFAULT_GAME_RULES) # Set game rules. ``` -------------------------------- ### GET /api/game/phase_data Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Retrieves the current game phase data, including orders, messages, and game state. ```APIDOC ## GET /api/game/phase_data ### Description Return a GamePhaseData object representing the current game state, including orders, messages, and game state. ### Method GET ### Endpoint /api/game/phase_data ### Parameters None ### Request Example None ### Response #### Success Response (200) - **name** (string) - The short name of the current phase. - **state** (object) - The current state of the game. - **orders** (object) - A dictionary mapping power names to their orders for the current phase, or null if orders are not set. - **messages** (array) - A list of messages for the current phase. - **results** (object) - An empty object, as results are not yet processed for the current phase. #### Response Example ```json { "name": "SUMMER 1901", "state": { "timestamp": 1678886400000, "zobrist_hash": "some_hash_value", "note": "", "name": "S1901", "units": { "ENGLAND": ["London", "Liverpool", "York"], "FRANCE": ["Paris", "Brest", "Marseilles"] }, "retreats": { "ENGLAND": [], "FRANCE": [] }, "centers": { "ENGLAND": ["London"], "FRANCE": ["Paris"] }, "homes": { "ENGLAND": ["London"], "FRANCE": ["Paris"] }, "influence": { "ENGLAND": ["London", "Liverpool", "York"], "FRANCE": ["Paris", "Brest", "Marseilles"] }, "civil_disorder": { "ENGLAND": [], "FRANCE": [] }, "builds": { "ENGLAND": 0, "FRANCE": 0 } }, "orders": { "ENGLAND": ["A L L", "A B S", "A Y S"], "FRANCE": null }, "messages": [], "results": {} } ``` ``` -------------------------------- ### API Class Documentation Source: https://diplomacy.readthedocs.io/en/stable/api/diplomacy.integration.webdiplomacy_net Documentation for the API class used to interact with webdiplomacy.net. ```APIDOC ## Class API ### Description API to interact with webdiplomacy.net. ### Parameters * **api_key** (str) - The API key for authentication. * **connect_timeout** (int, optional) - Timeout for establishing a connection. Defaults to 30. * **request_timeout** (int, optional) - Timeout for requests. Defaults to 60. ### Methods #### `list_games_with_players_in_cd()` ##### Description Lists games on the standard map where a player is in civil disorder (CD) and bots need to submit orders. ##### Returns - List of `GameIdCountryId` tuples [(game_id, country_id), (game_id, country_id)] #### `list_games_with_missing_orders()` ##### Description Lists games on the standard map where the user has not submitted orders yet. ##### Returns - List of `GameIdCountryId` tuples [(game_id, country_id), (game_id, country_id)] #### `get_game_and_power(game_id, country_id, max_phases=None)` ##### Description Returns the game and the power the user is playing. ##### Parameters * **game_id** (int) - The ID of the game object. * **country_id** (int) - The ID of the country for which to get the game state. * **max_phases** (int | None, optional) - If set, improves speed by generating the game using only the last 'x' phases. ##### Returns - A tuple consisting of: 1. The diplomacy.Game object from the game state or None if an error occurred. 2. The power name (e.g. 'FRANCE') referred to by country_id. #### `set_orders(game, power_name, orders, wait=None)` ##### Description Submits orders back to the server. ##### Parameters * **game** (diplomacy.Game) - A `diplomacy.engine.game.Game` object representing the current state of the game. * **power_name** (str) - The name of the power submitting the orders (e.g. 'FRANCE'). * **orders** (List[str]) - A list of strings representing the orders (e.g. ['A PAR H', 'F BRE - MAO']). * **wait** (bool | None, optional) - If True, sets ready=False; if False, sets ready=True. ##### Returns - True for success, False for failure. ``` -------------------------------- ### GET /api/game/state Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Retrieves the internal saved state of the game, including units, centers, homes, influence, and build information. ```APIDOC ## GET /api/game/state ### Description Gets the internal saved state of the game. This state is intended to represent the current game view, including powers' states, orders results for the previous phase, and other relevant information. For a complete state of all data in the game object, consider using `Game.to_dict()`. ### Method GET ### Endpoint /api/game/state ### Parameters #### Query Parameters - **make_copy** (boolean) - Optional. If `true`, a deep copy of the game state is returned; otherwise, attributes are returned directly. Defaults to `false`. ### Request Example ``` GET /api/game/state?make_copy=true ``` ### Response #### Success Response (200) - **timestamp** (integer) - The timestamp of the game state. - **zobrist_hash** (string) - The Zobrist hash of the current game state. - **note** (string) - Any notes associated with the current game state. - **name** (string) - The abbreviated name of the current phase (e.g., "S1901" for Summer 1901). - **units** (object) - A dictionary where keys are power names and values are lists of unit locations (including retreats indicated by '*'). - **retreats** (object) - A dictionary where keys are power names and values are lists of units in retreat. - **centers** (object) - A dictionary where keys are power names and values are lists of supply centers controlled by that power. - **homes** (object) - A dictionary where keys are power names and values are lists of home supply centers for that power. - **influence** (object) - A dictionary where keys are power names and values are lists of locations influenced by that power's units. - **civil_disorder** (object) - A dictionary where keys are power names and values are lists of locations with civil disorder. - **builds** (object) - A dictionary where keys are power names and values are the number of builds available for that power. #### Response Example ```json { "timestamp": 1678886400000, "zobrist_hash": "some_hash_value", "note": "", "name": "S1901", "units": { "ENGLAND": ["London", "Liverpool", "York"], "FRANCE": ["Paris", "Brest", "Marseilles"] }, "retreats": { "ENGLAND": [], "FRANCE": [] }, "centers": { "ENGLAND": ["London"], "FRANCE": ["Paris"] }, "homes": { "ENGLAND": ["London"], "FRANCE": ["Paris"] }, "influence": { "ENGLAND": ["London", "Liverpool", "York"], "FRANCE": ["Paris", "Brest", "Marseilles"] }, "civil_disorder": { "ENGLAND": [], "FRANCE": [] }, "builds": { "ENGLAND": 0, "FRANCE": 0 } } ``` ``` -------------------------------- ### Submit Orders and Manage Game State (Python) Source: https://context7.com/context7/diplomacy_readthedocs_io_en_stable/llms.txt Shows how to submit orders for a specific power, set wait flags, clear orders, and vote for draws within a Diplomacy network game. Also includes retrieving phase history. Requires 'tornado' and 'diplomacy.client' libraries. ```python from diplomacy.client.connection import connect from tornado import gen from tornado.ioloop import IOLoop @gen.coroutine def submit_network_orders(): connection = yield connect('localhost', 8888) channel = yield connection.authenticate('player1', 'password') game = yield channel.join_game('game123', power_name='FRANCE') # Submit orders for your power yield game.set_orders(orders=['A PAR - PIC', 'A MAR - BUR', 'F BRE - MAO']) # Set wait flag (game won't process until all powers clear wait) yield game.wait() # Or clear wait flag to indicate ready yield game.no_wait() # For game masters: set orders for any power yield game.set_orders( power_name='ENGLAND', orders=['F LON - NTH', 'A LVP - YOR'], wait=False ) # Clear orders yield game.clear_orders() # Vote for draw yield game.vote(vote='yes') # 'yes', 'no', or 'neutral' # Get order history phase_data = yield game.get_phase_history(from_phase='S1901M', to_phase='F1901M') for phase in phase_data: print(f"Phase {phase.name}") print(f"Orders: {phase.orders}") print(f"Results: {phase.results}") IOLoop.current().run_sync(submit_network_orders) ``` -------------------------------- ### Get Orders API Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Retrieves orders for a specific power or all powers in the game. It can filter orders based on the current phase. ```APIDOC ## GET /game/orders ### Description Retrieves orders for a specific power or all powers in the game. It can filter orders based on the current phase. ### Method GET ### Endpoint /game/orders ### Parameters #### Query Parameters - **power_name** (string) - Optional - The name of the power (e.g. 'FRANCE') or None for all powers ### Request Example GET /game/orders?power_name=FRANCE ### Response #### Success Response (200) - **orders** (list or dict) - A list of orders if a power name is provided, or a dictionary of powers with their orders if None is provided. - Example for single power: `["A PAR H", "A MAR - BUR"]` - Example for all powers: `{"FRANCE": ["A PAR H", "A MAR - BUR", ...], ...}` #### Response Example { "orders": [ "A PAR H", "A MAR - BUR" ] } ``` -------------------------------- ### Get Playable Powers Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/communication/requests Retrieves the set of powers that are currently playable (uncontrolled and not eliminated) for a specific game. ```APIDOC ## GET /api/games/{game_id}/playable_powers ### Description This endpoint fetches the list of powers that are currently available to be joined or controlled within a specific game. These powers are defined as dummy (uncontrolled) and have not yet been eliminated from the game. ### Method GET ### Endpoint /api/games/{game_id}/playable_powers ### Parameters #### Path Parameters - **game_id** (str) - Required - The ID of the game for which to retrieve playable powers. ### Request Body This endpoint does not accept a request body. ### Response #### Success Response (200) - **DataPowerNames** - A set containing the names of all powers that are currently playable in the specified game. #### Response Example ```json ["PowerA", "PowerB", "PowerC"] ``` ``` -------------------------------- ### API Module Imports for webdiplomacy.net Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/integration/webdiplomacy_net/api This snippet lists the essential imports for the API class, including logging, OS operations, socket error handling, URL encoding, and Tornado's asynchronous HTTP client. It also imports utilities for game state conversion and order representation from within the Diplomacy project. ```python # ============================================================================== # Copyright (C) 2019 - Philip Paquette # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Affero General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more # details. # # You should have received a copy of the GNU Affero General Public License along # with this program. If not, see . # ============================================================================== """ Contains an API class to send requests to webdiplomacy.net """ import logging import os from socket import herror, gaierror, timeout from urllib.parse import urlencode from tornado import gen from tornado.httpclient import HTTPRequest from tornado.simple_httpclient import HTTPTimeoutError, HTTPStreamClosedError import ujson as json from diplomacy.integration.base_api import BaseAPI from diplomacy.integration.webdiplomacy_net.game import state_dict_to_game_and_power from diplomacy.integration.webdiplomacy_net.orders import Order from diplomacy.integration.webdiplomacy_net.utils import CACHE, GameIdCountryId ``` -------------------------------- ### Get Map Power Names Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game Retrieves a sequence of all power names present on the game map. This is a basic utility method for accessing game configuration. ```python def get_map_power_names(self): """ Return sequence of map power names. """ return self.powers.keys() ``` -------------------------------- ### Initialize Game State and Rules Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/engine/game This Python code initializes the game state by processing rules, setting game parameters like deadlines and solitaire mode, and generating unique identifiers for the game. It also handles the association of powers with the game instance and performs initial state validation. ```python for rule in rules: self.add_rule(rule) # Check settings about rule NO_DEADLINE. if 'NO_DEADLINE' in self.rules: self.deadline = 0 # Check settings about rule SOLITAIRE. if 'SOLITAIRE' in self.rules: self.n_controls = 0 elif self.n_controls == 0: # If number of allowed players is 0, the game can only be solitaire. self.add_rule('SOLITAIRE') # Check timestamp_created. if self.timestamp_created is None: self.timestamp_created = common.timestamp_microseconds() # Check game ID. if self.game_id is None: self.game_id = base64.b64encode(os.urandom(12), b'-_').decode('utf-8') # Validating status self._validate_status(reinit_powers=(self.timestamp_created is None)) if self.powers: # Game loaded with powers. # Associate loaded powers with this game. for power in self.powers.values(): power.game = self else: # Begin game. self._begin() # Game loaded. # Check map powers. assert all(self.has_power(power_name) for power_name in self.map.powers) # Check role and consistency between all power roles and game role. if self.has_power(self.role): # It's a power game. Each power must be a player power. assert all(power.role == power.name for power in self.powers.values()) else: # We should have a non-power game and each power must have same role as game role. assert self.role in strings.ALL_ROLE_TYPES assert all(power.role == self.role for power in self.powers.values()) # Wrap history fields into runtime sorted dictionaries. # This is necessary to sort history fields by phase name. self._phase_wrapper_type = common.str_cmp_class(self.map.compare_phases) self.order_history = SortedDict(self._phase_wrapper_type, dict, {self._phase_wrapper_type(key): value for key, value in self.order_history.items()}) self.message_history = SortedDict(self._phase_wrapper_type, SortedDict, {self._phase_wrapper_type(key): value for key, value in self.message_history.items()}) self.state_history = SortedDict(self._phase_wrapper_type, dict, {self._phase_wrapper_type(key): value for key, value in self.state_history.items()}) self.result_history = SortedDict(self._phase_wrapper_type, dict, {self._phase_wrapper_type(key): value for key, value in self.result_history.items()}) ``` -------------------------------- ### Get Dummy Waiting Powers Source: https://diplomacy.readthedocs.io/en/stable/_modules/diplomacy/communication/requests Retrieves a list of dummy waiting power names for a given game, respecting a buffer size. ```APIDOC ## POST /api/games/{game_id}/dummy_powers ### Description This endpoint allows a client to request a list of dummy power names for a specified game. The server ensures that the total number of power names across all returned dictionaries does not exceed a given buffer size. ### Method POST ### Endpoint /api/games/{game_id}/dummy_powers ### Parameters #### Path Parameters - **game_id** (str) - Required - The ID of the game to retrieve dummy powers for. #### Query Parameters - **buffer_size** (int) - Required - The maximum total number of power names to return. ### Request Body This endpoint does not accept a request body. ### Response #### Success Response (200) - **DataGamesToPowerNames** - A dictionary mapping game IDs to a list of dummy waiting power names. The structure is designed to adhere to the specified buffer size. #### Response Example ```json { "game_123": ["PowerA", "PowerB"] } ``` ```