Games

Different negotiation scenario implementations for various research contexts.

Negotiation Games

Complete collection of negotiation game implementations for the platform.

This module provides access to all available negotiation game types, from simple bilateral price negotiations to complex multi-issue resource allocation scenarios. Each game implements the BaseGame interface while providing unique mechanics, scoring systems, and strategic challenges.

Available Games:
  • BaseGame: Abstract foundation for all negotiation implementations

  • CompanyCarGame: Bilateral price negotiation with market dynamics

  • ResourceAllocationGame: Multi-resource distribution between teams

  • IntegrativeNegotiationsGame: Multi-issue office space and responsibility allocation

Game Categories:
  1. Bilateral Negotiations: Two-party scenarios with clear opposing interests - CompanyCarGame: Buyer vs. Seller price negotiations

  2. Multi-Issue Negotiations: Complex scenarios with multiple decision points - IntegrativeNegotiationsGame: IT vs. Marketing office resource allocation

  3. Resource Distribution: Allocation of limited resources between parties - ResourceAllocationGame: Development vs. Marketing team resource sharing

Design Philosophy:

All games follow consistent design principles: - Clear role definitions with distinct interests and priorities - Realistic constraints and market dynamics - BATNA (Best Alternative to Negotiated Agreement) mechanisms - Win-win outcome possibilities requiring creative problem-solving - Structured proposal systems for clear communication - Comprehensive utility tracking and performance analysis

Usage Patterns:

Games can be used individually for specific research questions or combined in comparative studies to analyze negotiation strategies across different scenarios and complexity levels.

Example

>>> from negotiation_platform.games import (
...     CompanyCarGame, ResourceAllocationGame, IntegrativeNegotiationsGame
... )
>>>
>>> # Simple bilateral price negotiation
>>> car_config = {"starting_price": 42000, "rounds": 5}
>>> car_game = CompanyCarGame(car_config)
>>>
>>> # Complex multi-resource allocation
>>> resource_config = {"total_gpus": 10, "total_budget": 100000}
>>> resource_game = ResourceAllocationGame(resource_config)
>>>
>>> # Multi-issue integrative negotiation
>>> office_config = {"rounds": 8, "batna_decay": 0.02}
>>> office_game = IntegrativeNegotiationsGame(office_config)
Research Applications:
  • AI negotiation strategy development and testing

  • Comparative analysis of negotiation algorithms

  • Human-AI negotiation interaction studies

  • Game theory and mechanism design research

  • Organizational behavior and team dynamics analysis

class negotiation_platform.games.BaseGame(game_id: str, config: Dict[str, Any])[source]

Bases: ABC

Abstract base class defining the interface and common infrastructure for all negotiation games.

BaseGame provides the template and shared functionality for all negotiation game types within the platform. It implements common game management features while defining abstract methods that concrete games must implement for game-specific logic.

Design Pattern:

Implements the Template Method pattern where this base class handles common game lifecycle management (state tracking, action history, round counting) while delegating game-specific logic to concrete implementations.

Key Responsibilities:
  • Game state management and lifecycle tracking

  • Player registration and management

  • Action history maintenance and validation

  • Round counting and termination detection

  • Common configuration parameter handling

  • Abstract interface definition for game-specific logic

game_id

Unique identifier for this game instance.

Type:

str

config

Game configuration parameters.

Type:

Dict[str, Any]

state

Current game state (WAITING, ACTIVE, COMPLETED, FAILED).

Type:

GameState

players

List of registered player identifiers.

Type:

List[str]

current_round

Current round number (0-based).

Type:

int

max_rounds

Maximum allowed rounds before forced termination.

Type:

int

actions_history

Complete chronological action log.

Type:

List[PlayerAction]

game_data

Game-specific state and data storage.

Type:

Dict[str, Any]

Abstract Methods:

Concrete games must implement: - initialize_game(): Set up initial game state with players - is_valid_action(): Validate player actions against game rules - process_action(): Update game state based on valid actions - check_end_conditions(): Determine if game should terminate - calculate_scores(): Compute final player scores - get_game_prompt(): Generate player-specific prompts

Game Lifecycle:
  1. Construction: Game created with configuration

  2. Initialization: Players assigned and game state prepared

  3. Active Phase: Players take turns, actions processed

  4. Termination: End conditions met or max rounds reached

  5. Scoring: Final scores calculated and results prepared

Example

>>> class CustomGame(BaseGame):
...     def initialize_game(self, players):
...         self.players = players
...         self.state = GameState.ACTIVE
...         return True
...     # ... implement other abstract methods
>>> game = CustomGame("game_1", {"max_rounds": 5})
>>> success = game.initialize_game(["player1", "player2"])

Note

This is an abstract class and cannot be instantiated directly. Use concrete implementations like CompanyCarGame, ResourceAllocationGame, etc.

__init__(game_id: str, config: Dict[str, Any])[source]

Initialize a new game instance with identifier and configuration.

Sets up the basic game infrastructure including state tracking, player management, and configuration storage. The game starts in WAITING state until players are assigned via initialize_game().

Parameters:
  • game_id (str) – Unique identifier for this game instance. Used for logging, result tracking, and debugging. Should be unique across all concurrent game sessions.

  • config (Dict[str, Any]) –

    Configuration dictionary containing game parameters. Common parameters include:

    • max_rounds (int): Maximum negotiation rounds (default: 10)

    • time_limit (int): Session time limit in seconds

    • game_specific_params: Parameters unique to the game type

Initialization Process:
  1. Stores game identifier and configuration

  2. Sets initial state to WAITING

  3. Initializes empty player list

  4. Resets round counter to 0

  5. Sets up empty action history

  6. Prepares game data dictionary for game-specific state

Example

>>> config = {"max_rounds": 5, "time_limit": 1800}
>>> game = ConcreteGame("negotiation_001", config)
>>> print(game.state)
GameState.WAITING
>>> print(game.max_rounds)
5

Note

After construction, call initialize_game() to assign players and transition to ACTIVE state before game play can begin.

abstract initialize_game(players: List[str]) bool[source]

Initialize the game with given players

abstract is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Check if an action is valid in current game state

abstract process_action(action: PlayerAction) Dict[str, Any][source]

Process a player action and update game state

abstract check_end_conditions() bool[source]

Check if the game should end

abstract calculate_scores() Dict[str, float][source]

Calculate final scores for all players

abstract get_game_prompt(player_id: str) str[source]

Get the current game prompt for a specific player

add_action(action: PlayerAction)[source]

Add a player action to the game’s chronological history log.

Maintains a complete record of all player actions taken during the negotiation session for analysis, metrics calculation, and debugging.

Parameters:

action (PlayerAction) – The player action to add to history. Must contain player_id, action_type, action_data, timestamp, and round_number for complete action tracking.

Example

>>> action = PlayerAction(
...     player_id="player1",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> game.add_action(action)
get_game_info() Dict[str, Any][source]

Retrieve comprehensive information about the current game state.

Provides a structured overview of the game’s current status including identifiers, state information, player list, round tracking, and configuration parameters. Useful for debugging, logging, and analysis.

Returns:

Dictionary containing:
  • game_id (str): Unique game identifier

  • state (str): Current game state (waiting/active/completed/failed)

  • players (List[str]): List of participating player identifiers

  • current_round (int): Current round number (0-based)

  • max_rounds (int): Maximum rounds before forced termination

  • config (Dict[str, Any]): Complete game configuration parameters

Return type:

Dict[str, Any]

Example

>>> info = game.get_game_info()
>>> print(f"Game {info['game_id']} is in {info['state']} state")
>>> print(f"Round {info['current_round']}/{info['max_rounds']}")
Game negotiation_001 is in active state
Round 3/5
class negotiation_platform.games.CompanyCarGame(config: Dict[str, Any])[source]

Bases: BaseGame

Company car price negotiation game implementing realistic bilateral bargaining dynamics.

This class manages structured price negotiations between a buyer and seller for a company vehicle purchase. The game incorporates realistic market dynamics, time pressure through BATNA decay, and strategic guidance to create authentic negotiation experiences.

The game simulates a common business scenario where organizations must negotiate vehicle purchases, balancing budget constraints with value optimization. Both parties have alternatives (BATNAs) that become less attractive over time, encouraging timely agreement.

Key Features:
  • Realistic price negotiation with market constraints

  • Dynamic BATNA values that decay to simulate time pressure

  • Strategic guidance system with contextual prompts

  • JSON-based structured proposal system for clear communication

  • Win-win outcome detection based on surplus above BATNA values

  • Comprehensive utility tracking and performance analysis

Game Mechanics:
  1. Buyer and seller alternate making price proposals

  2. Each proposal is validated against budget and cost constraints

  3. Players can make offers, counteroffers, or accept/reject proposals

  4. BATNA values decay each round to encourage timely resolution

  5. Game ends on acceptance or maximum rounds reached

  6. Final utilities calculated based on achieved price vs. BATNA

starting_price

Initial vehicle price for negotiation reference.

Type:

int

buyer_budget

Maximum amount buyer can afford to pay.

Type:

int

seller_cost

Minimum amount seller needs to receive.

Type:

int

buyer_batna

Buyer’s best alternative option value.

Type:

float

seller_batna

Seller’s best alternative option value.

Type:

float

batna_decay

Per-round decay rate for BATNA values.

Type:

float

current_price

Most recent proposed price.

Type:

Optional[int]

agreement_reached

Whether parties have reached agreement.

Type:

bool

final_price

Agreed upon price if deal completed.

Type:

Optional[int]

Example

>>> config = {
...     "starting_price": 42000,
...     "buyer_budget": 45000,
...     "seller_cost": 38000,
...     "buyer_batna": 41000,
...     "seller_batna": 39000,
...     "rounds": 5,
...     "batna_decay": 0.02
... }
>>> game = CompanyCarGame(config)
>>> game.initialize_game(["buyer_agent", "seller_agent"])
>>>
>>> # Buyer makes initial offer
>>> action = {"type": "offer", "price": 40000}
>>> valid = game.is_valid_action("buyer_agent", action)
>>> if valid:
...     game.process_actions({"buyer_agent": action}, game_state)
Strategic Considerations:
  • Buyer Strategy: Start low but stay above seller’s likely cost

  • Seller Strategy: Start high but consider buyer’s budget limits

  • Both: Monitor BATNA decay and time pressure effects

  • Optimal: Find price range where both parties gain vs. their BATNAs

Outcome Analysis:

Game success measured by: - Agreement reached within round limit - Both parties achieve positive surplus above BATNA - Efficient price discovery within feasible range - Balanced utility distribution between parties

__init__(config: Dict[str, Any])[source]

Initialize company car negotiation game with configuration parameters.

Sets up the bilateral price negotiation environment with buyer and seller roles, BATNA values, budget constraints, and time decay mechanisms. Validates that all required configuration parameters are provided.

Parameters:

config (Dict[str, Any]) – Configuration dictionary containing: - starting_price (int): Initial vehicle price for reference - buyer_budget (int): Maximum amount buyer can afford - seller_cost (int): Minimum amount seller needs to receive - buyer_batna (float): Buyer’s best alternative value - seller_batna (float): Seller’s best alternative value - rounds (int): Maximum negotiation rounds allowed - batna_decay (float): Per-round BATNA decay rate (0.0-1.0)

Raises:

ValueError – If any required configuration field is missing.

Example

>>> config = {
...     "starting_price": 42000,
...     "buyer_budget": 45000,
...     "seller_cost": 38000,
...     "buyer_batna": 41000,
...     "seller_batna": 39000,
...     "rounds": 5,
...     "batna_decay": 0.02
... }
>>> game = CompanyCarGame(config)
validate_json_response(response: str) bool[source]

Validate that a response string contains properly formatted JSON.

Checks if the provided response can be parsed as valid JSON and contains the required “type” field for action identification. Used for input validation before processing player responses.

Parameters:

response (str) – Raw response string from player to validate.

Returns:

True if response is valid JSON with “type” field,

False otherwise.

Return type:

bool

Example

>>> valid_response = '{"type": "offer", "price": 42000}'
>>> game.validate_json_response(valid_response)
True
>>> invalid_response = 'I want to offer 42000'
>>> game.validate_json_response(invalid_response)
False
parse_json_response(response: str) Dict[str, Any][source]

Parse and normalize JSON response from players into standard format.

Extracts decision data from various JSON response formats, handling both direct action format and structured response format. Provides robust error recovery with fallback parsing for malformed responses.

Parameters:

response (str) – Raw JSON response string from player.

Returns:

Parsed response containing:
  • decision (Dict[str, Any]): Extracted action data with “type” field

  • raw_response (str): Original response for debugging

Return type:

Dict[str, Any]

Example

>>> response = '{"type": "offer", "price": 42000}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
offer
>>> print(parsed["decision"]["price"])
42000

Note

Falls back to {“type”: “reject”} for unparseable responses to ensure graceful handling of malformed input.

initialize_game(players: List[str]) Dict[str, Any][source]

Process a single player action and update the game state accordingly.

Handles individual player actions by adding them to history and delegating to the batch process_actions method. Required by BaseGame interface for single-action processing.

Parameters:

action (PlayerAction) – Player action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="buyer",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> new_state = game.process_action(action)
get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value for specified player and round.

Applies exponential decay to the player’s initial BATNA value based on the current round number, simulating decreasing value of alternatives over time. This creates time pressure encouraging earlier agreements.

Parameters:
  • player (str) – Player identifier (buyer or seller).

  • round_num (int) – Current round number (1-based).

Returns:

Time-adjusted BATNA value for the specified round.

Return type:

float

Example

>>> # Initial buyer BATNA: 41000, decay rate: 0.02
>>> round_1_batna = game.get_current_batna("buyer", 1)
>>> print(f"Round 1 BATNA: €{round_1_batna:,.0f}")
Round 1 BATNA: €40,180
>>> round_3_batna = game.get_current_batna("buyer", 3)
>>> print(f"Round 3 BATNA: €{round_3_batna:,.0f}")
Round 3 BATNA: €39,572

Note

BATNA decay formula: initial_batna * (1 - decay_rate)^round_num

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate player action against game rules with flexible format support.

Validates negotiation actions including offers, acceptances, and rejections. Supports both direct action format and structured response format with “decision” wrapper. Ensures actions comply with game constraints including proposal limits and valid action types.

Parameters:
  • player (str) – Identifier of the player taking the action. Must be registered buyer or seller.

  • action (Dict[str, Any]) – Action data to validate. Supported formats: - Direct: {“type”: “offer”, “price”: 42000} - Structured: {“decision”: {“type”: “offer”, “price”: 42000}}

  • game_state (Dict[str, Any]) – Current game state containing round information, proposal counts, and negotiation history.

Returns:

True if action is valid and can be processed, False otherwise.

Return type:

bool

Validation Rules:
  • Action must have valid “type” field (offer, accept, reject)

  • Offers must include numeric “price” field

  • Player must not exceed proposal limits

  • Price offers must be positive numeric values

Example

>>> # Valid offer action
>>> action = {"type": "offer", "price": 42000}
>>> is_valid = game.is_valid_action("buyer", action, game_state)
>>> print(is_valid)
True
>>> # Valid structured format
>>> structured = {"decision": {"type": "accept"}}
>>> is_valid = game.is_valid_action("seller", structured, game_state)
>>> print(is_valid)
True

Note

Invalid actions are logged but do not raise exceptions, allowing graceful handling of malformed AI model responses.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process simultaneous player actions with proposal tracking and validation.

Handles bilateral negotiation actions including offers, acceptances, and rejections. Enforces proposal limits, validates action compatibility, and determines negotiation outcomes. Updates game state with action results and manages agreement detection.

Parameters:
  • actions (Dict[str, Dict[str, Any]]) – Mapping of player identifiers to their action data. Expected format: {“player_id”: {“type”: “offer”, “price”: 42000}}

  • game_state (Dict[str, Any]) – Current game state containing: - current_round: Round number for tracking - proposal counts: Limits for each player - negotiation history: Previous actions and offers

Returns:

Updated game state containing:
  • agreement_reached: Boolean indicating successful negotiation

  • final_price: Agreed price if agreement reached

  • final_utilities: Utility scores for each player

  • game_over: Boolean indicating termination

  • Updated proposal counts and action history

Return type:

Dict[str, Any]

Processing Logic:
  1. Initialize and validate proposal counters

  2. Process each player’s action with validation

  3. Check for mutual acceptances (agreement)

  4. Handle offers and update last offer tracking

  5. Update proposal counts and game state

  6. Determine if negotiation should continue

Agreement Detection:
  • Mutual acceptance: Both players accept in same round

  • Offer acceptance: One player accepts other’s previous offer

  • Price agreement: Players converge on acceptable price

Example

>>> actions = {
...     "buyer": {"type": "offer", "price": 41000},
...     "seller": {"type": "offer", "price": 43000}
... }
>>> new_state = game.process_actions(actions, current_state)
>>> print(new_state["agreement_reached"])
False  # No agreement, continue negotiating

Note

Players exceeding proposal limits receive rejection responses. Invalid actions are logged and may result in negotiation failure.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the negotiation game has reached a terminal state.

Checks for various end conditions including agreement reached, maximum rounds exceeded, or explicit rejections that end negotiation.

Parameters:

game_state (Dict[str, Any]) – Current game state to evaluate.

Returns:

True if game should terminate, False if negotiation continues.

Return type:

bool

Example

>>> # Agreement reached
>>> game_state = {"agreement_reached": True}
>>> game.is_game_over(game_state)
True
>>> # Maximum rounds exceeded
>>> game_state = {"current_round": 6, "agreement_reached": False}
>>> game.is_game_over(game_state)  # max_rounds = 5
True
get_winner(game_state: Dict[str, Any]) str | None[source]

Determine the winning player based on positive utility surplus analysis.

Evaluates final utilities and surplus values to identify the player who achieved the highest positive surplus above their BATNA. Only players with positive surplus can be considered winners.

Parameters:

game_state (Dict[str, Any]) – Final game state with utility data.

Returns:

Player identifier of winner, or None if:
  • No agreement was reached

  • No player has positive surplus

  • Utilities are tied or unavailable

Return type:

Optional[str]

Example

>>> # Buyer achieved higher surplus
>>> game_state = {
...     "agreement_reached": True,
...     "utility_surplus": {"buyer": 1000, "seller": 500}
... }
>>> winner = game.get_winner(game_state)
>>> print(f"Winner: {winner}")
Winner: buyer
process_action(action: PlayerAction) Dict[str, Any][source]

Process a single player action and update the game state accordingly.

Handles individual player actions by adding them to history and delegating to the batch process_actions method. Required by BaseGame interface for single-action processing.

Parameters:

action (PlayerAction) – Player action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="buyer",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> new_state = game.process_action(action)
check_end_conditions() bool[source]

Check if the negotiation game should terminate based on current state.

Evaluates termination conditions by delegating to the is_game_over method. Required by BaseGame interface for consistent end condition checking across all game implementations.

Returns:

True if game should end, False if negotiation continues.

Return type:

bool

Example

>>> game.check_end_conditions()
True  # If agreement reached or max rounds exceeded
calculate_scores() Dict[str, float][source]

Calculate final utility scores for all participating players.

Computes final negotiation outcomes based on whether agreement was reached. If successful agreement occurred, returns actual utility values achieved by each player. If negotiation failed, returns zero scores for all players to reflect lack of value creation.

Returns:

Mapping of player identifiers to final utility scores.

For successful negotiations, contains actual utility values. For failed negotiations, contains 0.0 for all players.

Return type:

Dict[str, float]

Example

>>> # Successful price agreement at $42,000
>>> scores = game.calculate_scores()
>>> print(scores)
{'buyer_player': 7.5, 'seller_player': 8.2}
>>> # Failed negotiation (no agreement)
>>> scores = game.calculate_scores()
>>> print(scores)
{'buyer_player': 0.0, 'seller_player': 0.0}

Note

Required by BaseGame interface for consistent scoring across all negotiation game implementations. Scores reflect relative success in achieving negotiation objectives.

get_game_prompt(player_id: str) str[source]

Generate comprehensive negotiation prompt with neutral role terminology.

Creates detailed, contextual prompts for car price negotiations using neutral role labels (“Party A”/”Party B”) instead of loaded terms (“buyer”/”seller”) to reduce cognitive bias and role-based behavioral influences. Includes current game state, strategic guidance, and structured action formatting requirements.

Parameters:

player_id (str) – Identifier of the player requesting the prompt. Must be one of the registered players (buyer or seller).

Returns:

Comprehensive negotiation prompt containing:
  • Neutral role context and scenario description

  • Current round and proposal count information

  • BATNA thresholds and acceptance criteria

  • Opponent’s latest offer (if available)

  • Available actions and JSON formatting requirements

  • Strategic guidance for decision making

Return type:

str

Prompt Elements:
  • Bias-reduced role terminology (Party A/B vs buyer/seller)

  • Current negotiation state and round tracking

  • BATNA-based decision criteria and thresholds

  • Offer history and opponent action visibility

  • Structured JSON response format requirements

  • Strategic guidance for proposal and acceptance decisions

Example

>>> prompt = game.get_game_prompt("player1")
>>> print("Party A" in prompt)  # Neutral terminology
True
>>> print("JSON" in prompt)     # Format requirements
True
>>> print("BATNA" in prompt)    # Strategic guidance
True

Note

Returns error message if game is not properly initialized with buyer and seller assignments. Prompts adapt to current game state including round limits and proposal constraints.

class negotiation_platform.games.ResourceAllocationGame(config: Dict[str, Any])[source]

Bases: BaseGame

Complex multi-resource allocation negotiation between Development and Marketing teams.

This class implements a sophisticated resource distribution scenario where two organizational teams must negotiate the allocation of limited computational and human resources for a shared project. The game simulates realistic organizational resource conflicts with complex interdependencies and trade-offs.

The negotiation involves multiple resource types with different valuations for each team, requiring creative resource sharing and package deals to achieve mutually beneficial outcomes. Teams must balance their specific needs against organizational constraints and counterpart requirements.

Key Features:
  • Multi-resource negotiation (GPUs, developers, budget allocation)

  • Team-specific utility functions with different resource valuations

  • Complex resource interdependencies and constraints

  • BATNA values representing alternative resource sources

  • Structured JSON proposal system for resource requests

  • Win-win solution detection based on efficient resource utilization

Resource Types:
  1. GPU Hours: Computational resources for processing tasks - Development Team: High priority for model training and testing - Marketing Team: Moderate priority for data analysis

  2. Developer Hours: Human resource allocation - Development Team: Critical for implementation work - Marketing Team: Needed for integration and campaign development

  3. Budget Allocation: Financial resources for project components - Development Team: Infrastructure and tool costs - Marketing Team: Campaign execution and market research

Game Mechanics:
  1. Teams propose resource allocation packages

  2. Proposals validated against total resource constraints

  3. Utility calculated based on team-specific resource valuations

  4. Teams can negotiate, trade, or share resources creatively

  5. BATNA decay encourages timely resolution

  6. Success measured by total utility maximization

total_gpus

Total GPU hours available for allocation.

Type:

int

total_developers

Total developer hours available.

Type:

int

total_budget

Total budget available for distribution.

Type:

int

team_utilities

Team-specific utility functions defining how each team values different resource combinations.

Type:

Dict[str, Dict]

batna_values

Alternative resource source values.

Type:

Dict[str, float]

resource_weights

Team-specific importance weights for each resource type in utility calculations.

Type:

Dict[str, Dict[str, float]]

Example

>>> config = {
...     "max_rounds": 5,
...     "total_gpus": 10,
...     "total_developers": 8,
...     "total_budget": 100000,
...     "batna_decay": 0.02
... }
>>> game = ResourceAllocationGame(config)
>>> game.initialize_game(["dev_team", "marketing_team"])
>>>
>>> # Development team proposes resource allocation
>>> proposal = {
...     "gpu_hours": 7,      # High GPU need for development
...     "developer_hours": 5, # Core development team
...     "budget": 60000      # Infrastructure costs
... }
>>> action = {"type": "proposal", "allocation": proposal}
>>> valid = game.is_valid_action("dev_team", action)
Strategic Considerations:
  • Development Team: Prioritize GPU and developer resources

  • Marketing Team: Focus on budget and developer support

  • Both teams: Identify resource trades that create mutual value

  • Optimal: Find allocations where total utility exceeds individual BATNAs

Resource Efficiency:

Game encourages: - Creative resource sharing arrangements - Time-based resource allocation (sequential usage) - Hybrid solutions combining different resource types - Recognition of complementary resource needs between teams

__init__(config: Dict[str, Any])[source]

Initialize resource allocation negotiation game with team configurations.

Sets up multi-resource negotiation between Development and Marketing teams with utility functions, BATNA values, resource constraints, and time decay mechanisms. Validates required configuration parameters.

Parameters:

config (Dict[str, Any]) – Configuration dictionary containing: - batnas (Dict[str, float]): BATNA values for each team - rounds (int): Maximum negotiation rounds allowed - batna_decay (float): Per-round BATNA decay rate (0.0-1.0) - total_resources (Dict[str, int]): Available resource pools - constraints (Dict): Resource allocation constraints - utility_functions (Dict): Team-specific utility parameters - uncertainty (Dict, optional): Uncertainty parameters

Raises:

ValueError – If any required configuration field is missing.

Example

>>> config = {
...     "batnas": {"development": 50, "marketing": 45},
...     "rounds": 5,
...     "batna_decay": 0.02,
...     "total_resources": {"gpu": 100, "cpu": 100},
...     "constraints": {"max_gpu_per_team": 80},
...     "utility_functions": {
...         "development": {"gpu_coefficient": 0.8, "cpu_coefficient": 0.2},
...         "marketing": {"gpu_coefficient": 0.3, "cpu_coefficient": 0.7}
...     }
... }
>>> game = ResourceAllocationGame(config)
validate_json_response(response: str) bool[source]

Validate that a response string contains properly formatted JSON.

Checks if the provided response can be parsed as valid JSON and contains the required “type” field for action identification. Used for input validation before processing team responses.

Parameters:

response (str) – Raw response string from team to validate.

Returns:

True if response is valid JSON with “type” field,

False otherwise.

Return type:

bool

Example

>>> valid_response = '{"type": "propose", "gpu": 60, "cpu": 40}'
>>> game.validate_json_response(valid_response)
True
>>> invalid_response = 'We want 60 GPU hours'
>>> game.validate_json_response(invalid_response)
False
parse_json_response(response: str) Dict[str, Any][source]

Parse and normalize JSON response from teams into standard format.

Extracts decision data from various JSON response formats, handling both direct action format and structured response format. Provides robust error recovery with fallback parsing for malformed responses.

Parameters:

response (str) – Raw JSON response string from team.

Returns:

Parsed response containing:
  • decision (Dict[str, Any]): Extracted action data with “type” field

  • raw_response (str): Original response for debugging

Return type:

Dict[str, Any]

Example

>>> response = '{"type": "propose", "gpu": 60, "cpu": 40}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
propose
>>> print(parsed["decision"]["gpu"])
60

Note

Falls back to {“type”: “reject”} for unparseable responses to ensure graceful handling of malformed input.

initialize_game(players: List[str]) Dict[str, Any][source]

Initialize multi-resource allocation negotiation between development and marketing teams.

Sets up the negotiation environment with randomized role assignments to minimize order bias, initializes team-specific utility functions, establishes resource constraints, and prepares the game state for active negotiation.

Parameters:

players (List[str]) – List of exactly 2 player identifiers representing the negotiating teams. Order is randomized for role assignment.

Returns:

Initial game state containing:
  • players: List of player identifiers with assigned roles

  • current_round: Starting round number (1)

  • max_rounds: Maximum negotiation rounds allowed

  • total_gpu_hours: Total GPU resources available (10)

  • total_cpu_hours: Total CPU resources available (10)

  • private_info: Team-specific utility functions and preferences

  • resource_history: Empty history for tracking allocations

  • agreement_reached: False (negotiation not yet concluded)

Return type:

Dict[str, Any]

Initialization Process:
  1. Validate exactly 2 players provided

  2. Randomly assign development and marketing roles

  3. Set up team-specific utility functions and preferences

  4. Initialize resource constraints and tracking

  5. Create private information for each team

  6. Prepare negotiation state tracking

Role Assignment:
  • Development Team: Higher GPU preference, moderate CPU needs

  • Marketing Team: Higher CPU preference, moderate GPU needs

  • Random assignment prevents order bias effects

Resource Setup:
  • Total GPU Hours: 10 (must be allocated between teams)

  • Total CPU Hours: 10 (must be allocated between teams)

  • Team-specific utility functions for each resource type

Example

>>> players = ["model_a", "model_b"]
>>> initial_state = game.initialize_game(players)
>>> print(initial_state["total_gpu_hours"])
10
>>> print("private_info" in initial_state)
True
Raises:

ValueError – If number of players is not exactly 2.

Note

Role assignments are logged for debugging but kept private from players to maintain negotiation authenticity.

get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value for specified team and round.

Applies exponential decay to the team’s initial BATNA value based on the current round number, simulating decreasing value of alternative resource sources over time. Creates time pressure encouraging agreement.

Parameters:
  • player (str) – Team identifier (“development” or “marketing”).

  • round_num (int) – Current round number (1-based).

Returns:

Time-adjusted BATNA value for the specified round.

Return type:

float

Example

>>> # Initial development BATNA: 50, decay rate: 0.02
>>> round_1_batna = game.get_current_batna("development", 1)
>>> print(f"Round 1 BATNA: {round_1_batna:.1f}")
Round 1 BATNA: 49.0
>>> round_3_batna = game.get_current_batna("development", 3)
>>> print(f"Round 3 BATNA: {round_3_batna:.1f}")
Round 3 BATNA: 48.0

Note

BATNA decay formula: initial_batna * (1 - decay_rate)^round_num

calculate_utility(player: str, gpu_hours: float, cpu_hours: float, round_num: int) float[source]

Calculate team-specific utility value for proposed resource allocation.

Computes utility scores using configurable team-specific coefficients and uncertainty factors. Each team has different preferences for GPU vs CPU resources based on their operational needs and strategic priorities.

Parameters:
  • player (str) – Team identifier (development or marketing).

  • gpu_hours (float) – Proposed GPU resource allocation for the team.

  • cpu_hours (float) – Proposed CPU resource allocation for the team.

  • round_num (int) – Current negotiation round (used for future extensions).

Returns:

Total utility value including base utility and uncertainty factor.

Higher values indicate more attractive proposals for the team.

Return type:

float

Utility Calculation:

Base utility = (gpu_coeff × gpu_hours) + (cpu_coeff × cpu_hours) Final utility = base_utility + random_uncertainty_factor

Team Coefficients:
  • Development: Higher GPU coefficient, moderate CPU coefficient

  • Marketing: Higher CPU coefficient, moderate GPU coefficient

  • Configurable via utility_functions in game setup

Uncertainty Factor:

Random value within team-specific bounds to model negotiation uncertainty and prevent deterministic outcomes.

Example

>>> # Development team evaluating GPU-heavy allocation
>>> utility = game.calculate_utility("dev_team", 8.0, 2.0, 1)
>>> print(f"Development utility: {utility:.1f}")
Development utility: 28.3  # Including uncertainty

Note

Uncertainty factors add realism but may cause slight result variations between identical runs. Set narrow bounds for more predictable behavior.

check_constraints_and_update(gpu_hours: float, cpu_hours: float) None[source]

Validate resource allocation against all constraints and update game state.

Performs comprehensive validation of proposed resource allocation against multiple constraint types including total resource limits, bandwidth constraints, and resource coupling requirements. Updates game state with detailed validation results and error messages.

Parameters:
  • gpu_hours (float) – Proposed GPU resource allocation to validate.

  • cpu_hours (float) – Proposed CPU resource allocation to validate.

Side Effects:

Updates self.game_data[‘constraint_check’] with detailed validation results including constraint status, violation messages, and resource utilization analysis.

Constraint Validation:
  1. Total Resource Limit: gpu_hours + cpu_hours ≤ total_resources

  2. GPU Bandwidth: 4×gpu_hours + 4×cpu_hours ≤ gpu_bandwidth

  3. Individual Resource Bounds: Non-negative allocations

  4. Resource Coupling: Interdependency constraints

Game State Updates:
Creates or updates ‘constraint_check’ entry containing:
  • constraints_met: Boolean overall validation result

  • messages: List of specific constraint violation descriptions

  • gpu_hours: Validated GPU allocation

  • cpu_hours: Validated CPU allocation

  • total_usage: Combined resource utilization

Example

>>> # Valid allocation within all constraints
>>> game.check_constraints_and_update(4.0, 6.0)
>>> print(game.game_data['constraint_check']['constraints_met'])
True
>>> # Invalid allocation exceeding total resources
>>> game.check_constraints_and_update(8.0, 12.0)
>>> print(game.game_data['constraint_check']['constraints_met'])
False
>>> print(game.game_data['constraint_check']['messages'])
['Total resources exceeded: 20.0 > 10.0']

Note

This method provides detailed constraint analysis for debugging and user feedback, supporting complex multi-constraint validation scenarios in resource allocation negotiations.

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate team action against resource allocation rules and constraints.

Comprehensive validation of negotiation actions including proposals and acceptances. Supports both direct action format and structured response format with “decision” wrapper. Ensures actions comply with resource constraints, proposal limits, and valid action types.

Parameters:
  • player (str) – Identifier of the team taking the action. Must be registered development or marketing team.

  • action (Dict[str, Any]) – Action data to validate. Supported formats: - Direct: {“type”: “propose”, “gpu”: 6, “cpu”: 4} - Structured: {“decision”: {“type”: “propose”, “gpu”: 6, “cpu”: 4}}

  • game_state (Dict[str, Any]) – Current game state containing round information, proposal counts, and resource constraints.

Returns:

True if action is valid and can be processed, False otherwise.

Return type:

bool

Validation Rules:
  • Action must have valid “type” field (propose, accept)

  • Proposals must include numeric “gpu” and “cpu” fields

  • Resource allocations must respect total resource constraints

  • GPU + CPU allocations must not exceed available pools

  • Resource values must be non-negative numbers

  • Player must not exceed proposal limits

Resource Constraints:
  • Total GPU hours available: 10

  • Total CPU hours available: 10

  • Individual allocations must be ≤ total resources

  • Combined team allocations must sum to ≤ totals

Example

>>> # Valid resource proposal
>>> action = {"type": "propose", "gpu": 6, "cpu": 4}
>>> is_valid = game.is_valid_action("dev_team", action, game_state)
>>> print(is_valid)
True
>>> # Invalid proposal exceeding resources
>>> invalid = {"type": "propose", "gpu": 12, "cpu": 8}
>>> is_valid = game.is_valid_action("mkt_team", invalid, game_state)
>>> print(is_valid)
False

Note

Invalid actions are logged but do not raise exceptions, allowing graceful handling of malformed AI model responses and constraint violations.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process player actions with proposal limits and enhanced validation.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the resource allocation negotiation has reached a terminal state.

Checks for various end conditions including resource agreement reached, maximum rounds exceeded, or explicit rejections that end negotiation.

Parameters:

game_state (Dict[str, Any]) – Current game state to evaluate.

Returns:

True if game should terminate, False if negotiation continues.

Return type:

bool

Example

>>> # Agreement reached
>>> game_state = {"agreement_reached": True}
>>> game.is_game_over(game_state)
True
>>> # Maximum rounds exceeded
>>> game_state = {"current_round": 6, "agreement_reached": False}
>>> game.is_game_over(game_state)  # max_rounds = 5
True
get_game_prompt(player_id: str) str[source]

Generate comprehensive resource allocation negotiation prompt for teams.

Creates detailed, contextual prompts for GPU and CPU resource negotiations between Development and Marketing teams. Includes current game state, resource constraints, utility calculations, and structured action formatting requirements. Uses neutral role terminology to minimize cognitive bias.

Parameters:

player_id (str) – Identifier of the team requesting the prompt. Must be either development or marketing team identifier.

Returns:

Comprehensive negotiation prompt containing:
  • Team-specific role context and resource priorities

  • Current resource allocation status and constraints

  • BATNA thresholds and utility calculations

  • Opponent’s latest proposal (if available)

  • Available actions and JSON formatting requirements

  • Strategic guidance for resource optimization

  • Proposal limits and round tracking information

Return type:

str

Prompt Components:
  • Neutral role terminology (Team A/B vs development/marketing)

  • Resource constraint specifications (GPU/CPU limits)

  • Team-specific utility functions and preferences

  • Current negotiation state and round progression

  • BATNA-based acceptance criteria

  • Structured JSON response format requirements

  • Strategic recommendations for win-win solutions

Resource Context:
  • Total GPU hours: 10 (split between teams)

  • Total CPU hours: 10 (split between teams)

  • Team-specific utility calculations

  • Time-decaying BATNA values

Example

>>> prompt = game.get_game_prompt("dev_team")
>>> print("GPU hours" in prompt)    # Resource context
True
>>> print("Team A" in prompt)       # Neutral terminology
True
>>> print("JSON" in prompt)         # Format requirements
True

Note

Returns error message if game is not properly initialized with team assignments. Prompts adapt to current resource constraints and proposal limits.

process_action(action: PlayerAction) Dict[str, Any][source]

Process a single team action and update the game state accordingly.

Handles individual team actions by converting to batch format and delegating to the process_actions method. Required by BaseGame interface for single-action processing compatibility.

Parameters:

action (PlayerAction) – Team action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="development",
...     action_type="propose",
...     action_data={"gpu": 60, "cpu": 40},
...     timestamp=1609459200.0,
...     round_number=2
... )
>>> new_state = game.process_action(action)
check_end_conditions() bool[source]

Check if the resource allocation negotiation should terminate.

Evaluates termination conditions by delegating to the is_game_over method. Required by BaseGame interface for consistent end condition checking across all game implementations.

Returns:

True if game should end, False if negotiation continues.

Return type:

bool

Example

>>> game.check_end_conditions()
True  # If agreement reached or max rounds exceeded
calculate_scores() Dict[str, float][source]

Calculate final utility scores for all participating teams.

Returns final utility values if resource agreement was reached, or BATNA values for both teams if negotiation failed. Required by BaseGame interface for consistent scoring across implementations.

Returns:

Mapping of team identifiers to final utility

scores. Positive values indicate successful resource allocation.

Return type:

Dict[str, float]

Example

>>> # Successful negotiation
>>> scores = game.calculate_scores()
>>> print(scores)
{'development': 56.0, 'marketing': 44.0}
>>> # Failed negotiation
>>> scores = game.calculate_scores()
>>> print(scores)
{'development': 50.0, 'marketing': 45.0}  # BATNA values
class negotiation_platform.games.IntegrativeNegotiationsGame(config: Dict[str, Any])[source]

Bases: BaseGame

Integrative negotiations game between IT and Marketing teams with price bargaining logic.

Four issues with point values (unchanged from original): - Server Room Size: 50 sqm (10), 100 sqm (30), 150 sqm (60) - Meeting Room Access: 2 days/week (10), 4 days/week (30), 7 days/week (60) - Cleaning Responsibility: IT handles (10), Shared (30), Outsourced (60) - Branding Visibility: Minimal (10), Moderate (30), Prominent (60)

__init__(config: Dict[str, Any])[source]

Initialize integrative negotiations game with configuration parameters.

Sets up multi-issue office space negotiation between IT and Marketing teams. Configures team preferences, BATNA values, issue structures, and decay rates based on provided configuration dictionary.

Parameters:

config (Dict[str, Any]) – Game configuration containing: - batnas (Dict[str, float]): BATNA values for IT and Marketing teams - rounds (int): Maximum negotiation rounds allowed - batna_decay (float or Dict): Decay rate(s) for time pressure - issues (Dict, optional): Issue configurations and point values - weights (Dict, optional): Team preference weights by issue

Raises:

ValueError – If required configuration fields are missing.

Example

>>> config = {
...     "batnas": {"IT": 35, "Marketing": 30},
...     "rounds": 8,
...     "batna_decay": 0.02
... }
>>> game = IntegrativeNegotiationsGame(config)

Note

Supports both hardcoded fallback values and flexible configuration for research customization and parameter sensitivity analysis.

validate_json_response(response: str) bool[source]

Validate that AI model response is properly formatted JSON with required structure.

Performs structural validation of negotiation responses to ensure they contain the minimum required fields for processing. Used as a quick validation step before detailed parsing and action processing.

Parameters:

response (str) – Raw response string from AI model to validate.

Returns:

True if response is valid JSON dict with “type” field,

False for malformed JSON or missing required structure.

Return type:

bool

Validation Criteria:
  • Must be valid JSON syntax

  • Must parse to a dictionary object

  • Must contain “type” field for action identification

Example

>>> game.validate_json_response('{"type": "propose", "proposal": {}}')
True
>>> game.validate_json_response('invalid json')
False
>>> game.validate_json_response('{"proposal": {}}')
False

Note

This is a lightweight validation step. Full semantic validation of proposals and action types occurs in subsequent processing steps.

parse_json_response(response: str) Dict[str, Any][source]

Parse and extract decision data from AI model JSON responses with error recovery.

Handles multiple response formats and provides robust parsing with graceful error recovery for malformed responses. Extracts decision data and preserves raw response for debugging purposes.

Parameters:

response (str) – Raw JSON response string from AI model containing negotiation decision and potentially surrounding text.

Returns:

Parsed response containing:
  • decision (Dict): Extracted action data with type and parameters

  • raw_response (str): Original unmodified response for debugging

Return type:

Dict[str, Any]

Response Format Handling:
  • Pure JSON: {“type”: “propose”, “proposal”: {…}}

  • Embedded JSON: Text containing JSON objects

  • Malformed JSON: Fallback to regex extraction and default rejection

Error Recovery:
  • JSON parsing errors: Attempts regex extraction of key fields

  • Missing type field: Defaults to “reject” action

  • Invalid structure: Returns safe rejection response

Example

>>> response = '{"type": "propose", "proposal": {"server_room": 150}}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
"propose"
>>> print(parsed["decision"]["proposal"])
{"server_room": 150}

Note

Designed for robustness with AI model responses that may include explanatory text, formatting inconsistencies, or parsing errors.

initialize_game(players: List[str]) Dict[str, Any][source]

Initialize the integrative negotiation game with randomized role assignments.

Sets up a multi-issue office space negotiation between IT and Marketing teams with randomized role assignment to minimize positional bias. Establishes complete game state including private information, utility functions, and BATNA parameters.

Parameters:

players (List[str]) – List of exactly 2 player identifiers to participate in the bilateral negotiation.

Returns:

Complete initialized game state containing:
  • game_type (str): “integrative_negotiations”

  • players (List[str]): Player identifiers

  • role_assignments (Dict[str, str]): Mapping of roles to players

  • private_info (Dict[str, Dict]): Individual BATNAs and preferences

  • public_info (Dict[str, Any]): Shared issue descriptions

  • game_config (Dict[str, Any]): Configuration parameters

Return type:

Dict[str, Any]

Raises:

ValueError – If number of players is not exactly 2.

Example

>>> game = IntegrativeNegotiationsGame(config)
>>> state = game.initialize_game(["alice", "bob"])
>>> state["role_assignments"]
{"IT": "alice", "Marketing": "bob"}

Note

Role assignment is randomized to prevent systematic positional advantages. The first player is not always IT team.

get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value accounting for negotiation urgency.

Computes the Best Alternative to a Negotiated Agreement with exponential decay to model increasing time pressure and opportunity costs as rounds progress. Different decay rates can be applied per team role.

Parameters:
  • player (str) – Player identifier to calculate BATNA for.

  • round_num (int) – Current round number (1-indexed) for time adjustment.

Returns:

Time-adjusted BATNA value for the specified player and round.

Always less than or equal to the initial BATNA value.

Return type:

float

Formula:

BATNA(t) = base_BATNA * (1 - decay_rate)^(round - 1)

Example

>>> game.get_current_batna("alice", 1)  # Round 1
85.0
>>> game.get_current_batna("alice", 5)  # Round 5
79.8  # Decreased due to time pressure

Note

Supports both uniform decay rates (float) and role-specific decay rates (dict) for asymmetric time pressure modeling.

calculate_utility(player: str, proposal: Dict[str, Any]) float[source]

Calculate total weighted utility for a player given a specific proposal.

Computes utility by evaluating each negotiation issue against the player’s preferences and applying role-specific weights. Uses the additive utility model where total utility is the sum of weighted issue utilities.

Parameters:
  • player (str) – Player identifier to calculate utility for.

  • proposal (Dict[str, Any]) – Proposal dictionary containing selections for each negotiation issue (server_room, meeting_access, etc.).

Returns:

Total weighted utility value for the player. Higher values

indicate more preferred outcomes.

Return type:

float

Utility Calculation:

For each issue: utility += issue_points * role_weight Where issue_points are determined by option selection and role_weights reflect strategic importance to the player’s team.

Example

>>> proposal = {"server_room": 150, "meeting_access": 4,
...            "cleaning": "Shared", "branding": "Moderate"}
>>> game.calculate_utility("alice", proposal)
87.5

Note

Returns 0.0 for invalid proposals or unrecognized players. Role assignment determines which weight set is applied.

is_valid_proposal(proposal: Dict[str, Any]) bool[source]

Validate that a proposal contains valid selections for all negotiation issues.

Performs comprehensive validation to ensure proposals are complete and contain only valid options. Checks both completeness (all issues addressed) and validity (selections exist in defined option sets).

Parameters:

proposal (Dict[str, Any]) – Proposal dictionary to validate containing issue names as keys and selected options as values.

Returns:

True if proposal is complete and contains only valid selections,

False if missing issues or invalid options detected.

Return type:

bool

Validation Requirements:
  • Must be non-empty dictionary

  • Must contain all required issues (server_room, meeting_access, etc.)

  • All selections must exist in the corresponding issue option sets

Example

>>> valid = {"server_room": 150, "meeting_access": 4,
...          "cleaning": "Shared", "branding": "Moderate"}
>>> game.is_valid_proposal(valid)
True
>>> invalid = {"server_room": 200}  # Missing issues, invalid size
>>> game.is_valid_proposal(invalid)
False

Note

This method validates structure and options but not semantic reasonableness or strategic value of proposals.

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate player action with enhanced structured format support and proposal limits.

validate_response(response: Dict[str, Any]) bool[source]

Validate AI model response structure for required negotiation components.

Performs comprehensive validation of parsed responses to ensure they contain all necessary fields and valid action types for multi-issue negotiation processing.

Parameters:

response (Dict[str, Any]) – Parsed response dictionary to validate containing action type and associated parameters.

Returns:

True if response contains valid action structure,

False if missing required fields or invalid action types.

Return type:

bool

Validation Rules:
  • Must contain “type” and “proposal” keys

  • Action type must be “propose”, “accept”, or “reject”

  • Proposal validation handled separately by is_valid_proposal()

Example

>>> response = {"type": "propose", "proposal": {"server_room": 150}}
>>> game.validate_response(response)
True
>>> invalid = {"type": "invalid_action"}
>>> game.validate_response(invalid)
False

Note

This method validates response structure but not semantic validity of proposals. Content validation occurs in downstream processing.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process player actions with proposal limits and enhanced JSON validation.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the negotiation has reached a terminal state.

Checks multiple termination conditions to determine if the game should end. Used by the game engine to control round progression and trigger final result calculations.

Parameters:

game_state (Dict[str, Any]) – Current game state containing round information and agreement status.

Returns:

True if game should terminate, False if negotiation

should continue with additional rounds.

Return type:

bool

Termination Conditions:
  • Agreement reached between players

  • Game explicitly marked as ended

  • Maximum rounds exceeded

Example

>>> game.is_game_over({"agreement_reached": True})
True
>>> game.is_game_over({"current_round": 10})  # max_rounds=8
True
>>> game.is_game_over({"current_round": 3})
False

Note

Multiple termination conditions ensure robust game state management across different negotiation scenarios.

get_winner(game_state: Dict[str, Any]) str | None[source]

Determine negotiation winner based on utility surplus over BATNA.

Identifies the player who achieved the greatest benefit from the negotiation by comparing their utility gain above their Best Alternative to a Negotiated Agreement (BATNA). No winner is declared for failed negotiations.

Parameters:

game_state (Dict[str, Any]) – Final game state containing agreement details and utility calculations.

Returns:

Player identifier of the winner, or None if:
  • No agreement was reached

  • Both players have equal utility surplus

Return type:

Optional[str]

Winner Criteria:

Winner = max(utility - time_adjusted_BATNA) for each player Only positive surpluses indicate successful negotiation outcomes.

Example

>>> # Player utilities: alice=85, bob=78; BATNAs: alice=75, bob=80
>>> game.get_winner(final_state)
"alice"  # Surplus: alice=10, bob=-2
>>> game.get_winner(no_agreement_state)
None  # No agreement reached

Note

Winner determination encourages value-creating negotiations rather than purely competitive zero-sum outcomes.

get_game_summary(game_state: Dict[str, Any]) Dict[str, Any][source]

Generate comprehensive summary of negotiation results for analysis.

Creates a structured summary containing all key negotiation outcomes, player roles, agreement details, and utility calculations. Used for research analysis, reporting, and comparative studies.

Parameters:

game_state (Dict[str, Any]) – Final game state containing complete negotiation history and outcomes.

Returns:

Comprehensive summary containing:
  • game_type: “Integrative Negotiations”

  • players: Mapping of player IDs to role names

  • agreement_reached: Boolean success indicator

  • agreement_details: Final proposal if successful

  • utilities: Final utility values for each player

  • failure_reason: Explanation if negotiation failed

Return type:

Dict[str, Any]

Summary Structure:

Successful negotiations include agreement round, final proposal, utilities, and detailed breakdowns. Failed negotiations include failure reasons and context.

Example

>>> summary = game.get_game_summary(final_state)
>>> summary["agreement_reached"]
True
>>> summary["final_agreement"]
{"server_room": 150, "cleaning": "Shared"}

Note

Provides standardized output format for research data collection and comparative analysis across different negotiation scenarios.

process_action(action) Dict[str, Any][source]

Process a single player action (required by BaseGame interface).

Implements the abstract BaseGame method for single-action processing. In integrative negotiations, multi-player action processing via process_actions() is preferred. This method serves as a compatibility interface for the base class contract.

Parameters:

action – Single player action to process (format varies).

Returns:

Processing result indicating successful handling.

Return type:

Dict[str, Any]

Implementation Note:

This game uses simultaneous bilateral action processing through process_actions() rather than sequential single-action processing. This method provides base class compatibility.

Example

>>> result = game.process_action({"type": "propose"})
>>> result["processed"]
True

Note

For actual negotiation processing, use process_actions() which handles simultaneous bilateral actions appropriately.

check_end_conditions() bool[source]

Check if the game should end (required by BaseGame interface).

Implements the abstract BaseGame method for termination checking. Delegates to the state-based is_game_over() method when game data is available, providing base class compatibility.

Returns:

True if game should terminate, False otherwise.

Delegates to is_game_over() when game state exists.

Return type:

bool

Implementation Note:

This game uses state-based termination checking through is_game_over() which analyzes current game state for termination conditions.

Example

>>> game.check_end_conditions()
True  # If agreement reached or rounds exceeded

Note

Primary termination logic resides in is_game_over() which requires game state for proper condition evaluation.

calculate_scores() Dict[str, float][source]

Calculate final scores for all players (required by BaseGame interface).

Implements the abstract BaseGame method for score calculation. Returns final utilities from completed negotiations or zero scores for failed negotiations, providing base class compatibility.

Returns:

Dictionary mapping player IDs to final scores:
  • Successful negotiations: actual utility values

  • Failed negotiations: 0.0 for all players

  • No game data: 0.0 for all players

Return type:

Dict[str, float]

Score Calculation:

Scores are the final utility values calculated during agreement creation, representing negotiated value for each player.

Example

>>> scores = game.calculate_scores()
>>> scores
{"alice": 87.5, "bob": 78.3}  # After successful negotiation

Note

Scores represent utility values rather than competitive rankings. Both players can achieve positive scores in value-creating negotiations.

get_game_prompt(player_id: str, game_state: Dict[str, Any] | None = None) str[source]

Generate structured negotiation prompt for AI model interaction.

Creates comprehensive, role-specific prompts that provide players with all necessary context for strategic decision-making. Includes current situation, available options, utility guidance, and proper JSON response formatting requirements.

Parameters:
  • player_id (str) – Identifier of the player to generate prompt for.

  • game_state (Dict[str, Any], optional) – Current game state to use for prompt generation. If None, uses internal game_data.

Returns:

Complete formatted prompt string containing:
  • Current round and role information

  • Available options and point values

  • Role-specific priorities and preferences

  • Proposal history and opponent actions

  • Response format requirements and examples

Return type:

str

Prompt Components:
  • Header with round/role identification

  • BATNA and remaining proposal information

  • Option descriptions with utility values

  • Strategic guidance based on current situation

  • JSON format requirements and examples

Example

>>> prompt = game.get_game_prompt("alice", game_state)
>>> "OFFICE SPACE NEGOTIATION" in prompt
True
>>> "RESPONSE FORMAT" in prompt
True

Note

Prompts use neutral role labels to minimize cognitive bias while providing complete strategic context for informed decisions.

Game Implementations

Submodules

Abstract base class defining the interface for all negotiation games.

Base Game Interface

Defines the abstract interface and data structures for all negotiation games within the platform. This module provides the foundation for plug-and-play game integration with consistent APIs and type safety.

Key Components:
  • BaseGame: Abstract base class for all negotiation game implementations

  • GameState: Enumeration of possible game states throughout lifecycle

  • PlayerAction: Data structure representing individual player actions

  • GameResult: Data structure containing complete game outcomes

Architecture:

The base game interface follows the Template Method pattern, where concrete games implement specific game logic while inheriting common infrastructure. This enables consistent behavior across different negotiation scenarios.

Game Lifecycle:
  1. WAITING: Game created but not yet initialized with players

  2. ACTIVE: Game in progress with players taking turns

  3. COMPLETED: Game finished successfully with final results

  4. FAILED: Game terminated due to errors or violations

Design Patterns:
  • Template Method: Common game infrastructure with specific implementations

  • State Machine: Clear state transitions and lifecycle management

  • Data Transfer Objects: Structured data containers for actions and results

class negotiation_platform.games.base_game.GameState(value)[source]

Bases: Enum

Enumeration of possible game states throughout the negotiation lifecycle.

Defines the complete state machine for negotiation games, enabling proper state tracking and transition validation throughout the game lifecycle.

States:
WAITING: Game instance created but not yet initialized with players.

No actions can be taken in this state.

ACTIVE: Game is in progress with players actively negotiating.

Actions are validated and processed in this state.

COMPLETED: Game finished successfully with valid final results.

No further actions are accepted.

FAILED: Game terminated abnormally due to errors or rule violations.

Game data may be incomplete or invalid.

State Transitions:

WAITING → ACTIVE: When game is initialized with valid players ACTIVE → COMPLETED: When end conditions are met successfully ACTIVE → FAILED: When unrecoverable errors occur Any state → FAILED: When critical failures are detected

Example

>>> game = ConcreteGame("game_1", {})
>>> print(game.state)
GameState.WAITING
>>> game.initialize_game(["player1", "player2"])
>>> print(game.state)
GameState.ACTIVE
WAITING = 'waiting'
ACTIVE = 'active'
COMPLETED = 'completed'
FAILED = 'failed'
class negotiation_platform.games.base_game.PlayerAction(player_id: str, action_type: str, action_data: Dict[str, Any], timestamp: float, round_number: int)[source]

Bases: object

Data structure representing a single player action within a negotiation game.

PlayerAction serves as a standardized container for all player interactions during negotiations. It captures both the action content and contextual metadata necessary for game processing and analysis.

player_id

Unique identifier of the player who took this action. Must match one of the registered players in the game.

Type:

str

action_type

Category or type of action taken. Common types include: - “proposal”: Player making an offer or suggestion - “acceptance”: Player accepting a previous proposal - “rejection”: Player rejecting a previous proposal - “counter_proposal”: Player modifying a previous proposal - “message”: General communication or clarification

Type:

str

action_data

Action-specific data and parameters. Structure varies by action_type and game type. Examples: - Proposal: {“price”: 45000, “terms”: “cash_payment”} - Acceptance: {“accepted_proposal_id”: “prop_123”} - Message: {“text”: “I need to consider this offer”}

Type:

Dict[str, Any]

timestamp

Unix timestamp when the action was taken. Used for timing analysis and action ordering.

Type:

float

round_number

The negotiation round when this action occurred. Enables round-based analysis and game flow tracking.

Type:

int

Example

>>> action = PlayerAction(
...     player_id="player_1",
...     action_type="proposal",
...     action_data={"price": 42000, "warranty": True},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> print(action.action_data["price"])
42000

Note

PlayerAction objects are immutable once created (dataclass with frozen=False by default, but should be treated as read-only after creation).

player_id: str
action_type: str
action_data: Dict[str, Any]
timestamp: float
round_number: int
__init__(player_id: str, action_type: str, action_data: Dict[str, Any], timestamp: float, round_number: int) None
class negotiation_platform.games.base_game.GameResult(game_id: str, players: List[str], winner: str | None, final_scores: Dict[str, float], total_rounds: int, game_data: Dict[str, Any], success: bool)[source]

Bases: object

Data structure containing the complete outcome and results of a negotiation game.

GameResult serves as the authoritative record of a completed negotiation, containing all final state information needed for analysis, metrics calculation, and reporting. It provides a standardized format for game outcomes across different negotiation types.

game_id

Unique identifier for this specific game session. Used to correlate results with logs and analysis data.

Type:

str

players

Complete list of all players who participated. Maintains original player order for consistent analysis.

Type:

List[str]

winner

Identifier of the winning player, if applicable. None for games without clear winners (mutual agreements, ties, etc.). Some games may have multiple winners or no winner concept.

Type:

Optional[str]

final_scores

Final scores for each player. Maps player_id to their game-specific score. Score interpretation varies by game type (utility values, points, satisfaction ratings, etc.).

Type:

Dict[str, float]

total_rounds

Total number of negotiation rounds completed. Includes all rounds from game start to termination.

Type:

int

game_data

Complete final game state and additional data. Contains game-specific information such as: - final_agreement: Terms of any reached agreement - batna_values: Best alternatives for each player - resource_allocations: Final resource distributions - negotiation_history: Detailed interaction log

Type:

Dict[str, Any]

success

Whether the game completed successfully. True for normal completion (agreement or deadline reached). False for abnormal termination (errors, rule violations, crashes).

Type:

bool

Example

>>> result = GameResult(
...     game_id="session_2023_001",
...     players=["model_a", "model_b"],
...     winner="model_a",
...     final_scores={"model_a": 8.5, "model_b": 6.2},
...     total_rounds=4,
...     game_data={"agreement_reached": True, "final_price": 43500},
...     success=True
... )
>>> print(result.final_scores["model_a"])
8.5
Usage:

GameResult objects are created by game implementations upon completion and consumed by the metrics system, reporting tools, and analysis scripts. They provide the primary interface between game execution and result analysis.

game_id: str
players: List[str]
winner: str | None
final_scores: Dict[str, float]
total_rounds: int
game_data: Dict[str, Any]
success: bool
__init__(game_id: str, players: List[str], winner: str | None, final_scores: Dict[str, float], total_rounds: int, game_data: Dict[str, Any], success: bool) None
class negotiation_platform.games.base_game.BaseGame(game_id: str, config: Dict[str, Any])[source]

Bases: ABC

Abstract base class defining the interface and common infrastructure for all negotiation games.

BaseGame provides the template and shared functionality for all negotiation game types within the platform. It implements common game management features while defining abstract methods that concrete games must implement for game-specific logic.

Design Pattern:

Implements the Template Method pattern where this base class handles common game lifecycle management (state tracking, action history, round counting) while delegating game-specific logic to concrete implementations.

Key Responsibilities:
  • Game state management and lifecycle tracking

  • Player registration and management

  • Action history maintenance and validation

  • Round counting and termination detection

  • Common configuration parameter handling

  • Abstract interface definition for game-specific logic

game_id

Unique identifier for this game instance.

Type:

str

config

Game configuration parameters.

Type:

Dict[str, Any]

state

Current game state (WAITING, ACTIVE, COMPLETED, FAILED).

Type:

GameState

players

List of registered player identifiers.

Type:

List[str]

current_round

Current round number (0-based).

Type:

int

max_rounds

Maximum allowed rounds before forced termination.

Type:

int

actions_history

Complete chronological action log.

Type:

List[PlayerAction]

game_data

Game-specific state and data storage.

Type:

Dict[str, Any]

Abstract Methods:

Concrete games must implement: - initialize_game(): Set up initial game state with players - is_valid_action(): Validate player actions against game rules - process_action(): Update game state based on valid actions - check_end_conditions(): Determine if game should terminate - calculate_scores(): Compute final player scores - get_game_prompt(): Generate player-specific prompts

Game Lifecycle:
  1. Construction: Game created with configuration

  2. Initialization: Players assigned and game state prepared

  3. Active Phase: Players take turns, actions processed

  4. Termination: End conditions met or max rounds reached

  5. Scoring: Final scores calculated and results prepared

Example

>>> class CustomGame(BaseGame):
...     def initialize_game(self, players):
...         self.players = players
...         self.state = GameState.ACTIVE
...         return True
...     # ... implement other abstract methods
>>> game = CustomGame("game_1", {"max_rounds": 5})
>>> success = game.initialize_game(["player1", "player2"])

Note

This is an abstract class and cannot be instantiated directly. Use concrete implementations like CompanyCarGame, ResourceAllocationGame, etc.

__init__(game_id: str, config: Dict[str, Any])[source]

Initialize a new game instance with identifier and configuration.

Sets up the basic game infrastructure including state tracking, player management, and configuration storage. The game starts in WAITING state until players are assigned via initialize_game().

Parameters:
  • game_id (str) – Unique identifier for this game instance. Used for logging, result tracking, and debugging. Should be unique across all concurrent game sessions.

  • config (Dict[str, Any]) –

    Configuration dictionary containing game parameters. Common parameters include:

    • max_rounds (int): Maximum negotiation rounds (default: 10)

    • time_limit (int): Session time limit in seconds

    • game_specific_params: Parameters unique to the game type

Initialization Process:
  1. Stores game identifier and configuration

  2. Sets initial state to WAITING

  3. Initializes empty player list

  4. Resets round counter to 0

  5. Sets up empty action history

  6. Prepares game data dictionary for game-specific state

Example

>>> config = {"max_rounds": 5, "time_limit": 1800}
>>> game = ConcreteGame("negotiation_001", config)
>>> print(game.state)
GameState.WAITING
>>> print(game.max_rounds)
5

Note

After construction, call initialize_game() to assign players and transition to ACTIVE state before game play can begin.

abstract initialize_game(players: List[str]) bool[source]

Initialize the game with given players

abstract is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Check if an action is valid in current game state

abstract process_action(action: PlayerAction) Dict[str, Any][source]

Process a player action and update game state

abstract check_end_conditions() bool[source]

Check if the game should end

abstract calculate_scores() Dict[str, float][source]

Calculate final scores for all players

abstract get_game_prompt(player_id: str) str[source]

Get the current game prompt for a specific player

add_action(action: PlayerAction)[source]

Add a player action to the game’s chronological history log.

Maintains a complete record of all player actions taken during the negotiation session for analysis, metrics calculation, and debugging.

Parameters:

action (PlayerAction) – The player action to add to history. Must contain player_id, action_type, action_data, timestamp, and round_number for complete action tracking.

Example

>>> action = PlayerAction(
...     player_id="player1",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> game.add_action(action)
get_game_info() Dict[str, Any][source]

Retrieve comprehensive information about the current game state.

Provides a structured overview of the game’s current status including identifiers, state information, player list, round tracking, and configuration parameters. Useful for debugging, logging, and analysis.

Returns:

Dictionary containing:
  • game_id (str): Unique game identifier

  • state (str): Current game state (waiting/active/completed/failed)

  • players (List[str]): List of participating player identifiers

  • current_round (int): Current round number (0-based)

  • max_rounds (int): Maximum rounds before forced termination

  • config (Dict[str, Any]): Complete game configuration parameters

Return type:

Dict[str, Any]

Example

>>> info = game.get_game_info()
>>> print(f"Game {info['game_id']} is in {info['state']} state")
>>> print(f"Round {info['current_round']}/{info['max_rounds']}")
Game negotiation_001 is in active state
Round 3/5

Company Car Game (Price Bargaining)

Bilateral car price negotiation with time-adjusted BATNAs and strategic guidance.

Company Car Price Bargaining Game

Bilateral negotiation game for vehicle price negotiations with realistic market dynamics.

This module implements a structured car buying/selling negotiation where a buyer and seller negotiate the price of a company vehicle. The game includes realistic elements such as:

  • Time-decaying BATNAs (Best Alternatives to Negotiated Agreement)

  • Strategic guidance and structured prompts

  • Market-realistic price ranges and constraints

  • JSON-based proposal system for structured interactions

Key Features:
  • Bilateral negotiation between buyer and seller roles

  • Dynamic BATNA values that decay over time to simulate urgency

  • Structured proposal system with validation

  • Strategic prompts to guide realistic negotiation behavior

  • Win-win outcome detection and scoring

Game Parameters:
  • Starting Price: Initial vehicle price for negotiation

  • Buyer Budget: Maximum amount buyer can afford

  • Seller Cost: Minimum acceptable amount for seller

  • BATNA Values: Alternative options for both parties

  • Time Decay: How BATNAs change over negotiation rounds

Example

>>> config = {
...     "starting_price": 42000,
...     "buyer_budget": 45000,
...     "seller_cost": 38000,
...     "buyer_batna": 41000,
...     "seller_batna": 39000,
...     "rounds": 5,
...     "batna_decay": 0.02
... }
>>> game = CompanyCarGame(config)
>>> game.initialize_game(["buyer_agent", "seller_agent"])
class negotiation_platform.games.price_bargaining.CompanyCarGame(config: Dict[str, Any])[source]

Bases: BaseGame

Company car price negotiation game implementing realistic bilateral bargaining dynamics.

This class manages structured price negotiations between a buyer and seller for a company vehicle purchase. The game incorporates realistic market dynamics, time pressure through BATNA decay, and strategic guidance to create authentic negotiation experiences.

The game simulates a common business scenario where organizations must negotiate vehicle purchases, balancing budget constraints with value optimization. Both parties have alternatives (BATNAs) that become less attractive over time, encouraging timely agreement.

Key Features:
  • Realistic price negotiation with market constraints

  • Dynamic BATNA values that decay to simulate time pressure

  • Strategic guidance system with contextual prompts

  • JSON-based structured proposal system for clear communication

  • Win-win outcome detection based on surplus above BATNA values

  • Comprehensive utility tracking and performance analysis

Game Mechanics:
  1. Buyer and seller alternate making price proposals

  2. Each proposal is validated against budget and cost constraints

  3. Players can make offers, counteroffers, or accept/reject proposals

  4. BATNA values decay each round to encourage timely resolution

  5. Game ends on acceptance or maximum rounds reached

  6. Final utilities calculated based on achieved price vs. BATNA

starting_price

Initial vehicle price for negotiation reference.

Type:

int

buyer_budget

Maximum amount buyer can afford to pay.

Type:

int

seller_cost

Minimum amount seller needs to receive.

Type:

int

buyer_batna

Buyer’s best alternative option value.

Type:

float

seller_batna

Seller’s best alternative option value.

Type:

float

batna_decay

Per-round decay rate for BATNA values.

Type:

float

current_price

Most recent proposed price.

Type:

Optional[int]

agreement_reached

Whether parties have reached agreement.

Type:

bool

final_price

Agreed upon price if deal completed.

Type:

Optional[int]

Example

>>> config = {
...     "starting_price": 42000,
...     "buyer_budget": 45000,
...     "seller_cost": 38000,
...     "buyer_batna": 41000,
...     "seller_batna": 39000,
...     "rounds": 5,
...     "batna_decay": 0.02
... }
>>> game = CompanyCarGame(config)
>>> game.initialize_game(["buyer_agent", "seller_agent"])
>>>
>>> # Buyer makes initial offer
>>> action = {"type": "offer", "price": 40000}
>>> valid = game.is_valid_action("buyer_agent", action)
>>> if valid:
...     game.process_actions({"buyer_agent": action}, game_state)
Strategic Considerations:
  • Buyer Strategy: Start low but stay above seller’s likely cost

  • Seller Strategy: Start high but consider buyer’s budget limits

  • Both: Monitor BATNA decay and time pressure effects

  • Optimal: Find price range where both parties gain vs. their BATNAs

Outcome Analysis:

Game success measured by: - Agreement reached within round limit - Both parties achieve positive surplus above BATNA - Efficient price discovery within feasible range - Balanced utility distribution between parties

__init__(config: Dict[str, Any])[source]

Initialize company car negotiation game with configuration parameters.

Sets up the bilateral price negotiation environment with buyer and seller roles, BATNA values, budget constraints, and time decay mechanisms. Validates that all required configuration parameters are provided.

Parameters:

config (Dict[str, Any]) – Configuration dictionary containing: - starting_price (int): Initial vehicle price for reference - buyer_budget (int): Maximum amount buyer can afford - seller_cost (int): Minimum amount seller needs to receive - buyer_batna (float): Buyer’s best alternative value - seller_batna (float): Seller’s best alternative value - rounds (int): Maximum negotiation rounds allowed - batna_decay (float): Per-round BATNA decay rate (0.0-1.0)

Raises:

ValueError – If any required configuration field is missing.

Example

>>> config = {
...     "starting_price": 42000,
...     "buyer_budget": 45000,
...     "seller_cost": 38000,
...     "buyer_batna": 41000,
...     "seller_batna": 39000,
...     "rounds": 5,
...     "batna_decay": 0.02
... }
>>> game = CompanyCarGame(config)
validate_json_response(response: str) bool[source]

Validate that a response string contains properly formatted JSON.

Checks if the provided response can be parsed as valid JSON and contains the required “type” field for action identification. Used for input validation before processing player responses.

Parameters:

response (str) – Raw response string from player to validate.

Returns:

True if response is valid JSON with “type” field,

False otherwise.

Return type:

bool

Example

>>> valid_response = '{"type": "offer", "price": 42000}'
>>> game.validate_json_response(valid_response)
True
>>> invalid_response = 'I want to offer 42000'
>>> game.validate_json_response(invalid_response)
False
parse_json_response(response: str) Dict[str, Any][source]

Parse and normalize JSON response from players into standard format.

Extracts decision data from various JSON response formats, handling both direct action format and structured response format. Provides robust error recovery with fallback parsing for malformed responses.

Parameters:

response (str) – Raw JSON response string from player.

Returns:

Parsed response containing:
  • decision (Dict[str, Any]): Extracted action data with “type” field

  • raw_response (str): Original response for debugging

Return type:

Dict[str, Any]

Example

>>> response = '{"type": "offer", "price": 42000}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
offer
>>> print(parsed["decision"]["price"])
42000

Note

Falls back to {“type”: “reject”} for unparseable responses to ensure graceful handling of malformed input.

initialize_game(players: List[str]) Dict[str, Any][source]

Process a single player action and update the game state accordingly.

Handles individual player actions by adding them to history and delegating to the batch process_actions method. Required by BaseGame interface for single-action processing.

Parameters:

action (PlayerAction) – Player action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="buyer",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> new_state = game.process_action(action)
get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value for specified player and round.

Applies exponential decay to the player’s initial BATNA value based on the current round number, simulating decreasing value of alternatives over time. This creates time pressure encouraging earlier agreements.

Parameters:
  • player (str) – Player identifier (buyer or seller).

  • round_num (int) – Current round number (1-based).

Returns:

Time-adjusted BATNA value for the specified round.

Return type:

float

Example

>>> # Initial buyer BATNA: 41000, decay rate: 0.02
>>> round_1_batna = game.get_current_batna("buyer", 1)
>>> print(f"Round 1 BATNA: €{round_1_batna:,.0f}")
Round 1 BATNA: €40,180
>>> round_3_batna = game.get_current_batna("buyer", 3)
>>> print(f"Round 3 BATNA: €{round_3_batna:,.0f}")
Round 3 BATNA: €39,572

Note

BATNA decay formula: initial_batna * (1 - decay_rate)^round_num

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate player action against game rules with flexible format support.

Validates negotiation actions including offers, acceptances, and rejections. Supports both direct action format and structured response format with “decision” wrapper. Ensures actions comply with game constraints including proposal limits and valid action types.

Parameters:
  • player (str) – Identifier of the player taking the action. Must be registered buyer or seller.

  • action (Dict[str, Any]) – Action data to validate. Supported formats: - Direct: {“type”: “offer”, “price”: 42000} - Structured: {“decision”: {“type”: “offer”, “price”: 42000}}

  • game_state (Dict[str, Any]) – Current game state containing round information, proposal counts, and negotiation history.

Returns:

True if action is valid and can be processed, False otherwise.

Return type:

bool

Validation Rules:
  • Action must have valid “type” field (offer, accept, reject)

  • Offers must include numeric “price” field

  • Player must not exceed proposal limits

  • Price offers must be positive numeric values

Example

>>> # Valid offer action
>>> action = {"type": "offer", "price": 42000}
>>> is_valid = game.is_valid_action("buyer", action, game_state)
>>> print(is_valid)
True
>>> # Valid structured format
>>> structured = {"decision": {"type": "accept"}}
>>> is_valid = game.is_valid_action("seller", structured, game_state)
>>> print(is_valid)
True

Note

Invalid actions are logged but do not raise exceptions, allowing graceful handling of malformed AI model responses.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process simultaneous player actions with proposal tracking and validation.

Handles bilateral negotiation actions including offers, acceptances, and rejections. Enforces proposal limits, validates action compatibility, and determines negotiation outcomes. Updates game state with action results and manages agreement detection.

Parameters:
  • actions (Dict[str, Dict[str, Any]]) – Mapping of player identifiers to their action data. Expected format: {“player_id”: {“type”: “offer”, “price”: 42000}}

  • game_state (Dict[str, Any]) – Current game state containing: - current_round: Round number for tracking - proposal counts: Limits for each player - negotiation history: Previous actions and offers

Returns:

Updated game state containing:
  • agreement_reached: Boolean indicating successful negotiation

  • final_price: Agreed price if agreement reached

  • final_utilities: Utility scores for each player

  • game_over: Boolean indicating termination

  • Updated proposal counts and action history

Return type:

Dict[str, Any]

Processing Logic:
  1. Initialize and validate proposal counters

  2. Process each player’s action with validation

  3. Check for mutual acceptances (agreement)

  4. Handle offers and update last offer tracking

  5. Update proposal counts and game state

  6. Determine if negotiation should continue

Agreement Detection:
  • Mutual acceptance: Both players accept in same round

  • Offer acceptance: One player accepts other’s previous offer

  • Price agreement: Players converge on acceptable price

Example

>>> actions = {
...     "buyer": {"type": "offer", "price": 41000},
...     "seller": {"type": "offer", "price": 43000}
... }
>>> new_state = game.process_actions(actions, current_state)
>>> print(new_state["agreement_reached"])
False  # No agreement, continue negotiating

Note

Players exceeding proposal limits receive rejection responses. Invalid actions are logged and may result in negotiation failure.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the negotiation game has reached a terminal state.

Checks for various end conditions including agreement reached, maximum rounds exceeded, or explicit rejections that end negotiation.

Parameters:

game_state (Dict[str, Any]) – Current game state to evaluate.

Returns:

True if game should terminate, False if negotiation continues.

Return type:

bool

Example

>>> # Agreement reached
>>> game_state = {"agreement_reached": True}
>>> game.is_game_over(game_state)
True
>>> # Maximum rounds exceeded
>>> game_state = {"current_round": 6, "agreement_reached": False}
>>> game.is_game_over(game_state)  # max_rounds = 5
True
get_winner(game_state: Dict[str, Any]) str | None[source]

Determine the winning player based on positive utility surplus analysis.

Evaluates final utilities and surplus values to identify the player who achieved the highest positive surplus above their BATNA. Only players with positive surplus can be considered winners.

Parameters:

game_state (Dict[str, Any]) – Final game state with utility data.

Returns:

Player identifier of winner, or None if:
  • No agreement was reached

  • No player has positive surplus

  • Utilities are tied or unavailable

Return type:

Optional[str]

Example

>>> # Buyer achieved higher surplus
>>> game_state = {
...     "agreement_reached": True,
...     "utility_surplus": {"buyer": 1000, "seller": 500}
... }
>>> winner = game.get_winner(game_state)
>>> print(f"Winner: {winner}")
Winner: buyer
process_action(action: PlayerAction) Dict[str, Any][source]

Process a single player action and update the game state accordingly.

Handles individual player actions by adding them to history and delegating to the batch process_actions method. Required by BaseGame interface for single-action processing.

Parameters:

action (PlayerAction) – Player action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="buyer",
...     action_type="offer",
...     action_data={"price": 42000},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> new_state = game.process_action(action)
check_end_conditions() bool[source]

Check if the negotiation game should terminate based on current state.

Evaluates termination conditions by delegating to the is_game_over method. Required by BaseGame interface for consistent end condition checking across all game implementations.

Returns:

True if game should end, False if negotiation continues.

Return type:

bool

Example

>>> game.check_end_conditions()
True  # If agreement reached or max rounds exceeded
calculate_scores() Dict[str, float][source]

Calculate final utility scores for all participating players.

Computes final negotiation outcomes based on whether agreement was reached. If successful agreement occurred, returns actual utility values achieved by each player. If negotiation failed, returns zero scores for all players to reflect lack of value creation.

Returns:

Mapping of player identifiers to final utility scores.

For successful negotiations, contains actual utility values. For failed negotiations, contains 0.0 for all players.

Return type:

Dict[str, float]

Example

>>> # Successful price agreement at $42,000
>>> scores = game.calculate_scores()
>>> print(scores)
{'buyer_player': 7.5, 'seller_player': 8.2}
>>> # Failed negotiation (no agreement)
>>> scores = game.calculate_scores()
>>> print(scores)
{'buyer_player': 0.0, 'seller_player': 0.0}

Note

Required by BaseGame interface for consistent scoring across all negotiation game implementations. Scores reflect relative success in achieving negotiation objectives.

get_game_prompt(player_id: str) str[source]

Generate comprehensive negotiation prompt with neutral role terminology.

Creates detailed, contextual prompts for car price negotiations using neutral role labels (“Party A”/”Party B”) instead of loaded terms (“buyer”/”seller”) to reduce cognitive bias and role-based behavioral influences. Includes current game state, strategic guidance, and structured action formatting requirements.

Parameters:

player_id (str) – Identifier of the player requesting the prompt. Must be one of the registered players (buyer or seller).

Returns:

Comprehensive negotiation prompt containing:
  • Neutral role context and scenario description

  • Current round and proposal count information

  • BATNA thresholds and acceptance criteria

  • Opponent’s latest offer (if available)

  • Available actions and JSON formatting requirements

  • Strategic guidance for decision making

Return type:

str

Prompt Elements:
  • Bias-reduced role terminology (Party A/B vs buyer/seller)

  • Current negotiation state and round tracking

  • BATNA-based decision criteria and thresholds

  • Offer history and opponent action visibility

  • Structured JSON response format requirements

  • Strategic guidance for proposal and acceptance decisions

Example

>>> prompt = game.get_game_prompt("player1")
>>> print("Party A" in prompt)  # Neutral terminology
True
>>> print("JSON" in prompt)     # Format requirements
True
>>> print("BATNA" in prompt)    # Strategic guidance
True

Note

Returns error message if game is not properly initialized with buyer and seller assignments. Prompts adapt to current game state including round limits and proposal constraints.

Resource Allocation Game

Multi-resource distribution negotiation between development and marketing teams.

Resource Allocation Negotiation Game

Multi-resource distribution negotiation between development and marketing teams.

This module implements a complex resource allocation scenario where two teams (Development and Marketing) negotiate the distribution of limited resources including GPUs, developers, and budget allocation for a project.

The game simulates realistic organizational resource conflicts where: - Teams have different priorities and valuation of resources - Resources are limited and must be allocated efficiently - Teams must balance their needs against organizational constraints - Win-win solutions require creative resource sharing and trade-offs

Key Features:
  • Multi-resource negotiation (GPUs, developers, budget)

  • Team-based roles with different resource priorities

  • Complex utility calculations based on resource combinations

  • BATNA values representing alternative resource sources

  • Structured JSON proposal system for resource requests

Game Components:
  • Development Team: Focuses on GPU resources and technical staff

  • Marketing Team: Prioritizes budget and developer support

  • Resource Pool: Limited resources that must be allocated

  • Utility Functions: Team-specific valuation of resource combinations

Example

>>> config = {
...     "max_rounds": 5,
...     "total_gpus": 10,
...     "total_developers": 8,
...     "total_budget": 100000
... }
>>> game = ResourceAllocationGame(config)
>>> game.initialize_game(["dev_team", "marketing_team"])
class negotiation_platform.games.resource_allocation.ResourceAllocationGame(config: Dict[str, Any])[source]

Bases: BaseGame

Complex multi-resource allocation negotiation between Development and Marketing teams.

This class implements a sophisticated resource distribution scenario where two organizational teams must negotiate the allocation of limited computational and human resources for a shared project. The game simulates realistic organizational resource conflicts with complex interdependencies and trade-offs.

The negotiation involves multiple resource types with different valuations for each team, requiring creative resource sharing and package deals to achieve mutually beneficial outcomes. Teams must balance their specific needs against organizational constraints and counterpart requirements.

Key Features:
  • Multi-resource negotiation (GPUs, developers, budget allocation)

  • Team-specific utility functions with different resource valuations

  • Complex resource interdependencies and constraints

  • BATNA values representing alternative resource sources

  • Structured JSON proposal system for resource requests

  • Win-win solution detection based on efficient resource utilization

Resource Types:
  1. GPU Hours: Computational resources for processing tasks - Development Team: High priority for model training and testing - Marketing Team: Moderate priority for data analysis

  2. Developer Hours: Human resource allocation - Development Team: Critical for implementation work - Marketing Team: Needed for integration and campaign development

  3. Budget Allocation: Financial resources for project components - Development Team: Infrastructure and tool costs - Marketing Team: Campaign execution and market research

Game Mechanics:
  1. Teams propose resource allocation packages

  2. Proposals validated against total resource constraints

  3. Utility calculated based on team-specific resource valuations

  4. Teams can negotiate, trade, or share resources creatively

  5. BATNA decay encourages timely resolution

  6. Success measured by total utility maximization

total_gpus

Total GPU hours available for allocation.

Type:

int

total_developers

Total developer hours available.

Type:

int

total_budget

Total budget available for distribution.

Type:

int

team_utilities

Team-specific utility functions defining how each team values different resource combinations.

Type:

Dict[str, Dict]

batna_values

Alternative resource source values.

Type:

Dict[str, float]

resource_weights

Team-specific importance weights for each resource type in utility calculations.

Type:

Dict[str, Dict[str, float]]

Example

>>> config = {
...     "max_rounds": 5,
...     "total_gpus": 10,
...     "total_developers": 8,
...     "total_budget": 100000,
...     "batna_decay": 0.02
... }
>>> game = ResourceAllocationGame(config)
>>> game.initialize_game(["dev_team", "marketing_team"])
>>>
>>> # Development team proposes resource allocation
>>> proposal = {
...     "gpu_hours": 7,      # High GPU need for development
...     "developer_hours": 5, # Core development team
...     "budget": 60000      # Infrastructure costs
... }
>>> action = {"type": "proposal", "allocation": proposal}
>>> valid = game.is_valid_action("dev_team", action)
Strategic Considerations:
  • Development Team: Prioritize GPU and developer resources

  • Marketing Team: Focus on budget and developer support

  • Both teams: Identify resource trades that create mutual value

  • Optimal: Find allocations where total utility exceeds individual BATNAs

Resource Efficiency:

Game encourages: - Creative resource sharing arrangements - Time-based resource allocation (sequential usage) - Hybrid solutions combining different resource types - Recognition of complementary resource needs between teams

__init__(config: Dict[str, Any])[source]

Initialize resource allocation negotiation game with team configurations.

Sets up multi-resource negotiation between Development and Marketing teams with utility functions, BATNA values, resource constraints, and time decay mechanisms. Validates required configuration parameters.

Parameters:

config (Dict[str, Any]) – Configuration dictionary containing: - batnas (Dict[str, float]): BATNA values for each team - rounds (int): Maximum negotiation rounds allowed - batna_decay (float): Per-round BATNA decay rate (0.0-1.0) - total_resources (Dict[str, int]): Available resource pools - constraints (Dict): Resource allocation constraints - utility_functions (Dict): Team-specific utility parameters - uncertainty (Dict, optional): Uncertainty parameters

Raises:

ValueError – If any required configuration field is missing.

Example

>>> config = {
...     "batnas": {"development": 50, "marketing": 45},
...     "rounds": 5,
...     "batna_decay": 0.02,
...     "total_resources": {"gpu": 100, "cpu": 100},
...     "constraints": {"max_gpu_per_team": 80},
...     "utility_functions": {
...         "development": {"gpu_coefficient": 0.8, "cpu_coefficient": 0.2},
...         "marketing": {"gpu_coefficient": 0.3, "cpu_coefficient": 0.7}
...     }
... }
>>> game = ResourceAllocationGame(config)
validate_json_response(response: str) bool[source]

Validate that a response string contains properly formatted JSON.

Checks if the provided response can be parsed as valid JSON and contains the required “type” field for action identification. Used for input validation before processing team responses.

Parameters:

response (str) – Raw response string from team to validate.

Returns:

True if response is valid JSON with “type” field,

False otherwise.

Return type:

bool

Example

>>> valid_response = '{"type": "propose", "gpu": 60, "cpu": 40}'
>>> game.validate_json_response(valid_response)
True
>>> invalid_response = 'We want 60 GPU hours'
>>> game.validate_json_response(invalid_response)
False
parse_json_response(response: str) Dict[str, Any][source]

Parse and normalize JSON response from teams into standard format.

Extracts decision data from various JSON response formats, handling both direct action format and structured response format. Provides robust error recovery with fallback parsing for malformed responses.

Parameters:

response (str) – Raw JSON response string from team.

Returns:

Parsed response containing:
  • decision (Dict[str, Any]): Extracted action data with “type” field

  • raw_response (str): Original response for debugging

Return type:

Dict[str, Any]

Example

>>> response = '{"type": "propose", "gpu": 60, "cpu": 40}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
propose
>>> print(parsed["decision"]["gpu"])
60

Note

Falls back to {“type”: “reject”} for unparseable responses to ensure graceful handling of malformed input.

initialize_game(players: List[str]) Dict[str, Any][source]

Initialize multi-resource allocation negotiation between development and marketing teams.

Sets up the negotiation environment with randomized role assignments to minimize order bias, initializes team-specific utility functions, establishes resource constraints, and prepares the game state for active negotiation.

Parameters:

players (List[str]) – List of exactly 2 player identifiers representing the negotiating teams. Order is randomized for role assignment.

Returns:

Initial game state containing:
  • players: List of player identifiers with assigned roles

  • current_round: Starting round number (1)

  • max_rounds: Maximum negotiation rounds allowed

  • total_gpu_hours: Total GPU resources available (10)

  • total_cpu_hours: Total CPU resources available (10)

  • private_info: Team-specific utility functions and preferences

  • resource_history: Empty history for tracking allocations

  • agreement_reached: False (negotiation not yet concluded)

Return type:

Dict[str, Any]

Initialization Process:
  1. Validate exactly 2 players provided

  2. Randomly assign development and marketing roles

  3. Set up team-specific utility functions and preferences

  4. Initialize resource constraints and tracking

  5. Create private information for each team

  6. Prepare negotiation state tracking

Role Assignment:
  • Development Team: Higher GPU preference, moderate CPU needs

  • Marketing Team: Higher CPU preference, moderate GPU needs

  • Random assignment prevents order bias effects

Resource Setup:
  • Total GPU Hours: 10 (must be allocated between teams)

  • Total CPU Hours: 10 (must be allocated between teams)

  • Team-specific utility functions for each resource type

Example

>>> players = ["model_a", "model_b"]
>>> initial_state = game.initialize_game(players)
>>> print(initial_state["total_gpu_hours"])
10
>>> print("private_info" in initial_state)
True
Raises:

ValueError – If number of players is not exactly 2.

Note

Role assignments are logged for debugging but kept private from players to maintain negotiation authenticity.

get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value for specified team and round.

Applies exponential decay to the team’s initial BATNA value based on the current round number, simulating decreasing value of alternative resource sources over time. Creates time pressure encouraging agreement.

Parameters:
  • player (str) – Team identifier (“development” or “marketing”).

  • round_num (int) – Current round number (1-based).

Returns:

Time-adjusted BATNA value for the specified round.

Return type:

float

Example

>>> # Initial development BATNA: 50, decay rate: 0.02
>>> round_1_batna = game.get_current_batna("development", 1)
>>> print(f"Round 1 BATNA: {round_1_batna:.1f}")
Round 1 BATNA: 49.0
>>> round_3_batna = game.get_current_batna("development", 3)
>>> print(f"Round 3 BATNA: {round_3_batna:.1f}")
Round 3 BATNA: 48.0

Note

BATNA decay formula: initial_batna * (1 - decay_rate)^round_num

calculate_utility(player: str, gpu_hours: float, cpu_hours: float, round_num: int) float[source]

Calculate team-specific utility value for proposed resource allocation.

Computes utility scores using configurable team-specific coefficients and uncertainty factors. Each team has different preferences for GPU vs CPU resources based on their operational needs and strategic priorities.

Parameters:
  • player (str) – Team identifier (development or marketing).

  • gpu_hours (float) – Proposed GPU resource allocation for the team.

  • cpu_hours (float) – Proposed CPU resource allocation for the team.

  • round_num (int) – Current negotiation round (used for future extensions).

Returns:

Total utility value including base utility and uncertainty factor.

Higher values indicate more attractive proposals for the team.

Return type:

float

Utility Calculation:

Base utility = (gpu_coeff × gpu_hours) + (cpu_coeff × cpu_hours) Final utility = base_utility + random_uncertainty_factor

Team Coefficients:
  • Development: Higher GPU coefficient, moderate CPU coefficient

  • Marketing: Higher CPU coefficient, moderate GPU coefficient

  • Configurable via utility_functions in game setup

Uncertainty Factor:

Random value within team-specific bounds to model negotiation uncertainty and prevent deterministic outcomes.

Example

>>> # Development team evaluating GPU-heavy allocation
>>> utility = game.calculate_utility("dev_team", 8.0, 2.0, 1)
>>> print(f"Development utility: {utility:.1f}")
Development utility: 28.3  # Including uncertainty

Note

Uncertainty factors add realism but may cause slight result variations between identical runs. Set narrow bounds for more predictable behavior.

check_constraints_and_update(gpu_hours: float, cpu_hours: float) None[source]

Validate resource allocation against all constraints and update game state.

Performs comprehensive validation of proposed resource allocation against multiple constraint types including total resource limits, bandwidth constraints, and resource coupling requirements. Updates game state with detailed validation results and error messages.

Parameters:
  • gpu_hours (float) – Proposed GPU resource allocation to validate.

  • cpu_hours (float) – Proposed CPU resource allocation to validate.

Side Effects:

Updates self.game_data[‘constraint_check’] with detailed validation results including constraint status, violation messages, and resource utilization analysis.

Constraint Validation:
  1. Total Resource Limit: gpu_hours + cpu_hours ≤ total_resources

  2. GPU Bandwidth: 4×gpu_hours + 4×cpu_hours ≤ gpu_bandwidth

  3. Individual Resource Bounds: Non-negative allocations

  4. Resource Coupling: Interdependency constraints

Game State Updates:
Creates or updates ‘constraint_check’ entry containing:
  • constraints_met: Boolean overall validation result

  • messages: List of specific constraint violation descriptions

  • gpu_hours: Validated GPU allocation

  • cpu_hours: Validated CPU allocation

  • total_usage: Combined resource utilization

Example

>>> # Valid allocation within all constraints
>>> game.check_constraints_and_update(4.0, 6.0)
>>> print(game.game_data['constraint_check']['constraints_met'])
True
>>> # Invalid allocation exceeding total resources
>>> game.check_constraints_and_update(8.0, 12.0)
>>> print(game.game_data['constraint_check']['constraints_met'])
False
>>> print(game.game_data['constraint_check']['messages'])
['Total resources exceeded: 20.0 > 10.0']

Note

This method provides detailed constraint analysis for debugging and user feedback, supporting complex multi-constraint validation scenarios in resource allocation negotiations.

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate team action against resource allocation rules and constraints.

Comprehensive validation of negotiation actions including proposals and acceptances. Supports both direct action format and structured response format with “decision” wrapper. Ensures actions comply with resource constraints, proposal limits, and valid action types.

Parameters:
  • player (str) – Identifier of the team taking the action. Must be registered development or marketing team.

  • action (Dict[str, Any]) – Action data to validate. Supported formats: - Direct: {“type”: “propose”, “gpu”: 6, “cpu”: 4} - Structured: {“decision”: {“type”: “propose”, “gpu”: 6, “cpu”: 4}}

  • game_state (Dict[str, Any]) – Current game state containing round information, proposal counts, and resource constraints.

Returns:

True if action is valid and can be processed, False otherwise.

Return type:

bool

Validation Rules:
  • Action must have valid “type” field (propose, accept)

  • Proposals must include numeric “gpu” and “cpu” fields

  • Resource allocations must respect total resource constraints

  • GPU + CPU allocations must not exceed available pools

  • Resource values must be non-negative numbers

  • Player must not exceed proposal limits

Resource Constraints:
  • Total GPU hours available: 10

  • Total CPU hours available: 10

  • Individual allocations must be ≤ total resources

  • Combined team allocations must sum to ≤ totals

Example

>>> # Valid resource proposal
>>> action = {"type": "propose", "gpu": 6, "cpu": 4}
>>> is_valid = game.is_valid_action("dev_team", action, game_state)
>>> print(is_valid)
True
>>> # Invalid proposal exceeding resources
>>> invalid = {"type": "propose", "gpu": 12, "cpu": 8}
>>> is_valid = game.is_valid_action("mkt_team", invalid, game_state)
>>> print(is_valid)
False

Note

Invalid actions are logged but do not raise exceptions, allowing graceful handling of malformed AI model responses and constraint violations.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process player actions with proposal limits and enhanced validation.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the resource allocation negotiation has reached a terminal state.

Checks for various end conditions including resource agreement reached, maximum rounds exceeded, or explicit rejections that end negotiation.

Parameters:

game_state (Dict[str, Any]) – Current game state to evaluate.

Returns:

True if game should terminate, False if negotiation continues.

Return type:

bool

Example

>>> # Agreement reached
>>> game_state = {"agreement_reached": True}
>>> game.is_game_over(game_state)
True
>>> # Maximum rounds exceeded
>>> game_state = {"current_round": 6, "agreement_reached": False}
>>> game.is_game_over(game_state)  # max_rounds = 5
True
get_game_prompt(player_id: str) str[source]

Generate comprehensive resource allocation negotiation prompt for teams.

Creates detailed, contextual prompts for GPU and CPU resource negotiations between Development and Marketing teams. Includes current game state, resource constraints, utility calculations, and structured action formatting requirements. Uses neutral role terminology to minimize cognitive bias.

Parameters:

player_id (str) – Identifier of the team requesting the prompt. Must be either development or marketing team identifier.

Returns:

Comprehensive negotiation prompt containing:
  • Team-specific role context and resource priorities

  • Current resource allocation status and constraints

  • BATNA thresholds and utility calculations

  • Opponent’s latest proposal (if available)

  • Available actions and JSON formatting requirements

  • Strategic guidance for resource optimization

  • Proposal limits and round tracking information

Return type:

str

Prompt Components:
  • Neutral role terminology (Team A/B vs development/marketing)

  • Resource constraint specifications (GPU/CPU limits)

  • Team-specific utility functions and preferences

  • Current negotiation state and round progression

  • BATNA-based acceptance criteria

  • Structured JSON response format requirements

  • Strategic recommendations for win-win solutions

Resource Context:
  • Total GPU hours: 10 (split between teams)

  • Total CPU hours: 10 (split between teams)

  • Team-specific utility calculations

  • Time-decaying BATNA values

Example

>>> prompt = game.get_game_prompt("dev_team")
>>> print("GPU hours" in prompt)    # Resource context
True
>>> print("Team A" in prompt)       # Neutral terminology
True
>>> print("JSON" in prompt)         # Format requirements
True

Note

Returns error message if game is not properly initialized with team assignments. Prompts adapt to current resource constraints and proposal limits.

process_action(action: PlayerAction) Dict[str, Any][source]

Process a single team action and update the game state accordingly.

Handles individual team actions by converting to batch format and delegating to the process_actions method. Required by BaseGame interface for single-action processing compatibility.

Parameters:

action (PlayerAction) – Team action to process containing player_id, action_type, action_data, timestamp, and round_number.

Returns:

Updated game state after processing the action.

Return type:

Dict[str, Any]

Example

>>> action = PlayerAction(
...     player_id="development",
...     action_type="propose",
...     action_data={"gpu": 60, "cpu": 40},
...     timestamp=1609459200.0,
...     round_number=2
... )
>>> new_state = game.process_action(action)
check_end_conditions() bool[source]

Check if the resource allocation negotiation should terminate.

Evaluates termination conditions by delegating to the is_game_over method. Required by BaseGame interface for consistent end condition checking across all game implementations.

Returns:

True if game should end, False if negotiation continues.

Return type:

bool

Example

>>> game.check_end_conditions()
True  # If agreement reached or max rounds exceeded
calculate_scores() Dict[str, float][source]

Calculate final utility scores for all participating teams.

Returns final utility values if resource agreement was reached, or BATNA values for both teams if negotiation failed. Required by BaseGame interface for consistent scoring across implementations.

Returns:

Mapping of team identifiers to final utility

scores. Positive values indicate successful resource allocation.

Return type:

Dict[str, float]

Example

>>> # Successful negotiation
>>> scores = game.calculate_scores()
>>> print(scores)
{'development': 56.0, 'marketing': 44.0}
>>> # Failed negotiation
>>> scores = game.calculate_scores()
>>> print(scores)
{'development': 50.0, 'marketing': 45.0}  # BATNA values

Integrative Negotiation Game

Multi-issue collaborative negotiation focusing on mutual value creation.

class negotiation_platform.games.integrative_negotiation.IntegrativeNegotiationsGame(config: Dict[str, Any])[source]

Bases: BaseGame

Integrative negotiations game between IT and Marketing teams with price bargaining logic.

Four issues with point values (unchanged from original): - Server Room Size: 50 sqm (10), 100 sqm (30), 150 sqm (60) - Meeting Room Access: 2 days/week (10), 4 days/week (30), 7 days/week (60) - Cleaning Responsibility: IT handles (10), Shared (30), Outsourced (60) - Branding Visibility: Minimal (10), Moderate (30), Prominent (60)

__init__(config: Dict[str, Any])[source]

Initialize integrative negotiations game with configuration parameters.

Sets up multi-issue office space negotiation between IT and Marketing teams. Configures team preferences, BATNA values, issue structures, and decay rates based on provided configuration dictionary.

Parameters:

config (Dict[str, Any]) – Game configuration containing: - batnas (Dict[str, float]): BATNA values for IT and Marketing teams - rounds (int): Maximum negotiation rounds allowed - batna_decay (float or Dict): Decay rate(s) for time pressure - issues (Dict, optional): Issue configurations and point values - weights (Dict, optional): Team preference weights by issue

Raises:

ValueError – If required configuration fields are missing.

Example

>>> config = {
...     "batnas": {"IT": 35, "Marketing": 30},
...     "rounds": 8,
...     "batna_decay": 0.02
... }
>>> game = IntegrativeNegotiationsGame(config)

Note

Supports both hardcoded fallback values and flexible configuration for research customization and parameter sensitivity analysis.

validate_json_response(response: str) bool[source]

Validate that AI model response is properly formatted JSON with required structure.

Performs structural validation of negotiation responses to ensure they contain the minimum required fields for processing. Used as a quick validation step before detailed parsing and action processing.

Parameters:

response (str) – Raw response string from AI model to validate.

Returns:

True if response is valid JSON dict with “type” field,

False for malformed JSON or missing required structure.

Return type:

bool

Validation Criteria:
  • Must be valid JSON syntax

  • Must parse to a dictionary object

  • Must contain “type” field for action identification

Example

>>> game.validate_json_response('{"type": "propose", "proposal": {}}')
True
>>> game.validate_json_response('invalid json')
False
>>> game.validate_json_response('{"proposal": {}}')
False

Note

This is a lightweight validation step. Full semantic validation of proposals and action types occurs in subsequent processing steps.

parse_json_response(response: str) Dict[str, Any][source]

Parse and extract decision data from AI model JSON responses with error recovery.

Handles multiple response formats and provides robust parsing with graceful error recovery for malformed responses. Extracts decision data and preserves raw response for debugging purposes.

Parameters:

response (str) – Raw JSON response string from AI model containing negotiation decision and potentially surrounding text.

Returns:

Parsed response containing:
  • decision (Dict): Extracted action data with type and parameters

  • raw_response (str): Original unmodified response for debugging

Return type:

Dict[str, Any]

Response Format Handling:
  • Pure JSON: {“type”: “propose”, “proposal”: {…}}

  • Embedded JSON: Text containing JSON objects

  • Malformed JSON: Fallback to regex extraction and default rejection

Error Recovery:
  • JSON parsing errors: Attempts regex extraction of key fields

  • Missing type field: Defaults to “reject” action

  • Invalid structure: Returns safe rejection response

Example

>>> response = '{"type": "propose", "proposal": {"server_room": 150}}'
>>> parsed = game.parse_json_response(response)
>>> print(parsed["decision"]["type"])
"propose"
>>> print(parsed["decision"]["proposal"])
{"server_room": 150}

Note

Designed for robustness with AI model responses that may include explanatory text, formatting inconsistencies, or parsing errors.

initialize_game(players: List[str]) Dict[str, Any][source]

Initialize the integrative negotiation game with randomized role assignments.

Sets up a multi-issue office space negotiation between IT and Marketing teams with randomized role assignment to minimize positional bias. Establishes complete game state including private information, utility functions, and BATNA parameters.

Parameters:

players (List[str]) – List of exactly 2 player identifiers to participate in the bilateral negotiation.

Returns:

Complete initialized game state containing:
  • game_type (str): “integrative_negotiations”

  • players (List[str]): Player identifiers

  • role_assignments (Dict[str, str]): Mapping of roles to players

  • private_info (Dict[str, Dict]): Individual BATNAs and preferences

  • public_info (Dict[str, Any]): Shared issue descriptions

  • game_config (Dict[str, Any]): Configuration parameters

Return type:

Dict[str, Any]

Raises:

ValueError – If number of players is not exactly 2.

Example

>>> game = IntegrativeNegotiationsGame(config)
>>> state = game.initialize_game(["alice", "bob"])
>>> state["role_assignments"]
{"IT": "alice", "Marketing": "bob"}

Note

Role assignment is randomized to prevent systematic positional advantages. The first player is not always IT team.

get_current_batna(player: str, round_num: int) float[source]

Calculate time-adjusted BATNA value accounting for negotiation urgency.

Computes the Best Alternative to a Negotiated Agreement with exponential decay to model increasing time pressure and opportunity costs as rounds progress. Different decay rates can be applied per team role.

Parameters:
  • player (str) – Player identifier to calculate BATNA for.

  • round_num (int) – Current round number (1-indexed) for time adjustment.

Returns:

Time-adjusted BATNA value for the specified player and round.

Always less than or equal to the initial BATNA value.

Return type:

float

Formula:

BATNA(t) = base_BATNA * (1 - decay_rate)^(round - 1)

Example

>>> game.get_current_batna("alice", 1)  # Round 1
85.0
>>> game.get_current_batna("alice", 5)  # Round 5
79.8  # Decreased due to time pressure

Note

Supports both uniform decay rates (float) and role-specific decay rates (dict) for asymmetric time pressure modeling.

calculate_utility(player: str, proposal: Dict[str, Any]) float[source]

Calculate total weighted utility for a player given a specific proposal.

Computes utility by evaluating each negotiation issue against the player’s preferences and applying role-specific weights. Uses the additive utility model where total utility is the sum of weighted issue utilities.

Parameters:
  • player (str) – Player identifier to calculate utility for.

  • proposal (Dict[str, Any]) – Proposal dictionary containing selections for each negotiation issue (server_room, meeting_access, etc.).

Returns:

Total weighted utility value for the player. Higher values

indicate more preferred outcomes.

Return type:

float

Utility Calculation:

For each issue: utility += issue_points * role_weight Where issue_points are determined by option selection and role_weights reflect strategic importance to the player’s team.

Example

>>> proposal = {"server_room": 150, "meeting_access": 4,
...            "cleaning": "Shared", "branding": "Moderate"}
>>> game.calculate_utility("alice", proposal)
87.5

Note

Returns 0.0 for invalid proposals or unrecognized players. Role assignment determines which weight set is applied.

is_valid_proposal(proposal: Dict[str, Any]) bool[source]

Validate that a proposal contains valid selections for all negotiation issues.

Performs comprehensive validation to ensure proposals are complete and contain only valid options. Checks both completeness (all issues addressed) and validity (selections exist in defined option sets).

Parameters:

proposal (Dict[str, Any]) – Proposal dictionary to validate containing issue names as keys and selected options as values.

Returns:

True if proposal is complete and contains only valid selections,

False if missing issues or invalid options detected.

Return type:

bool

Validation Requirements:
  • Must be non-empty dictionary

  • Must contain all required issues (server_room, meeting_access, etc.)

  • All selections must exist in the corresponding issue option sets

Example

>>> valid = {"server_room": 150, "meeting_access": 4,
...          "cleaning": "Shared", "branding": "Moderate"}
>>> game.is_valid_proposal(valid)
True
>>> invalid = {"server_room": 200}  # Missing issues, invalid size
>>> game.is_valid_proposal(invalid)
False

Note

This method validates structure and options but not semantic reasonableness or strategic value of proposals.

is_valid_action(player: str, action: Dict[str, Any], game_state: Dict[str, Any]) bool[source]

Validate player action with enhanced structured format support and proposal limits.

validate_response(response: Dict[str, Any]) bool[source]

Validate AI model response structure for required negotiation components.

Performs comprehensive validation of parsed responses to ensure they contain all necessary fields and valid action types for multi-issue negotiation processing.

Parameters:

response (Dict[str, Any]) – Parsed response dictionary to validate containing action type and associated parameters.

Returns:

True if response contains valid action structure,

False if missing required fields or invalid action types.

Return type:

bool

Validation Rules:
  • Must contain “type” and “proposal” keys

  • Action type must be “propose”, “accept”, or “reject”

  • Proposal validation handled separately by is_valid_proposal()

Example

>>> response = {"type": "propose", "proposal": {"server_room": 150}}
>>> game.validate_response(response)
True
>>> invalid = {"type": "invalid_action"}
>>> game.validate_response(invalid)
False

Note

This method validates response structure but not semantic validity of proposals. Content validation occurs in downstream processing.

process_actions(actions: Dict[str, Dict[str, Any]], game_state: Dict[str, Any]) Dict[str, Any][source]

Process player actions with proposal limits and enhanced JSON validation.

is_game_over(game_state: Dict[str, Any]) bool[source]

Determine if the negotiation has reached a terminal state.

Checks multiple termination conditions to determine if the game should end. Used by the game engine to control round progression and trigger final result calculations.

Parameters:

game_state (Dict[str, Any]) – Current game state containing round information and agreement status.

Returns:

True if game should terminate, False if negotiation

should continue with additional rounds.

Return type:

bool

Termination Conditions:
  • Agreement reached between players

  • Game explicitly marked as ended

  • Maximum rounds exceeded

Example

>>> game.is_game_over({"agreement_reached": True})
True
>>> game.is_game_over({"current_round": 10})  # max_rounds=8
True
>>> game.is_game_over({"current_round": 3})
False

Note

Multiple termination conditions ensure robust game state management across different negotiation scenarios.

get_winner(game_state: Dict[str, Any]) str | None[source]

Determine negotiation winner based on utility surplus over BATNA.

Identifies the player who achieved the greatest benefit from the negotiation by comparing their utility gain above their Best Alternative to a Negotiated Agreement (BATNA). No winner is declared for failed negotiations.

Parameters:

game_state (Dict[str, Any]) – Final game state containing agreement details and utility calculations.

Returns:

Player identifier of the winner, or None if:
  • No agreement was reached

  • Both players have equal utility surplus

Return type:

Optional[str]

Winner Criteria:

Winner = max(utility - time_adjusted_BATNA) for each player Only positive surpluses indicate successful negotiation outcomes.

Example

>>> # Player utilities: alice=85, bob=78; BATNAs: alice=75, bob=80
>>> game.get_winner(final_state)
"alice"  # Surplus: alice=10, bob=-2
>>> game.get_winner(no_agreement_state)
None  # No agreement reached

Note

Winner determination encourages value-creating negotiations rather than purely competitive zero-sum outcomes.

get_game_summary(game_state: Dict[str, Any]) Dict[str, Any][source]

Generate comprehensive summary of negotiation results for analysis.

Creates a structured summary containing all key negotiation outcomes, player roles, agreement details, and utility calculations. Used for research analysis, reporting, and comparative studies.

Parameters:

game_state (Dict[str, Any]) – Final game state containing complete negotiation history and outcomes.

Returns:

Comprehensive summary containing:
  • game_type: “Integrative Negotiations”

  • players: Mapping of player IDs to role names

  • agreement_reached: Boolean success indicator

  • agreement_details: Final proposal if successful

  • utilities: Final utility values for each player

  • failure_reason: Explanation if negotiation failed

Return type:

Dict[str, Any]

Summary Structure:

Successful negotiations include agreement round, final proposal, utilities, and detailed breakdowns. Failed negotiations include failure reasons and context.

Example

>>> summary = game.get_game_summary(final_state)
>>> summary["agreement_reached"]
True
>>> summary["final_agreement"]
{"server_room": 150, "cleaning": "Shared"}

Note

Provides standardized output format for research data collection and comparative analysis across different negotiation scenarios.

process_action(action) Dict[str, Any][source]

Process a single player action (required by BaseGame interface).

Implements the abstract BaseGame method for single-action processing. In integrative negotiations, multi-player action processing via process_actions() is preferred. This method serves as a compatibility interface for the base class contract.

Parameters:

action – Single player action to process (format varies).

Returns:

Processing result indicating successful handling.

Return type:

Dict[str, Any]

Implementation Note:

This game uses simultaneous bilateral action processing through process_actions() rather than sequential single-action processing. This method provides base class compatibility.

Example

>>> result = game.process_action({"type": "propose"})
>>> result["processed"]
True

Note

For actual negotiation processing, use process_actions() which handles simultaneous bilateral actions appropriately.

check_end_conditions() bool[source]

Check if the game should end (required by BaseGame interface).

Implements the abstract BaseGame method for termination checking. Delegates to the state-based is_game_over() method when game data is available, providing base class compatibility.

Returns:

True if game should terminate, False otherwise.

Delegates to is_game_over() when game state exists.

Return type:

bool

Implementation Note:

This game uses state-based termination checking through is_game_over() which analyzes current game state for termination conditions.

Example

>>> game.check_end_conditions()
True  # If agreement reached or rounds exceeded

Note

Primary termination logic resides in is_game_over() which requires game state for proper condition evaluation.

calculate_scores() Dict[str, float][source]

Calculate final scores for all players (required by BaseGame interface).

Implements the abstract BaseGame method for score calculation. Returns final utilities from completed negotiations or zero scores for failed negotiations, providing base class compatibility.

Returns:

Dictionary mapping player IDs to final scores:
  • Successful negotiations: actual utility values

  • Failed negotiations: 0.0 for all players

  • No game data: 0.0 for all players

Return type:

Dict[str, float]

Score Calculation:

Scores are the final utility values calculated during agreement creation, representing negotiated value for each player.

Example

>>> scores = game.calculate_scores()
>>> scores
{"alice": 87.5, "bob": 78.3}  # After successful negotiation

Note

Scores represent utility values rather than competitive rankings. Both players can achieve positive scores in value-creating negotiations.

get_game_prompt(player_id: str, game_state: Dict[str, Any] | None = None) str[source]

Generate structured negotiation prompt for AI model interaction.

Creates comprehensive, role-specific prompts that provide players with all necessary context for strategic decision-making. Includes current situation, available options, utility guidance, and proper JSON response formatting requirements.

Parameters:
  • player_id (str) – Identifier of the player to generate prompt for.

  • game_state (Dict[str, Any], optional) – Current game state to use for prompt generation. If None, uses internal game_data.

Returns:

Complete formatted prompt string containing:
  • Current round and role information

  • Available options and point values

  • Role-specific priorities and preferences

  • Proposal history and opponent actions

  • Response format requirements and examples

Return type:

str

Prompt Components:
  • Header with round/role identification

  • BATNA and remaining proposal information

  • Option descriptions with utility values

  • Strategic guidance based on current situation

  • JSON format requirements and examples

Example

>>> prompt = game.get_game_prompt("alice", game_state)
>>> "OFFICE SPACE NEGOTIATION" in prompt
True
>>> "RESPONSE FORMAT" in prompt
True

Note

Prompts use neutral role labels to minimize cognitive bias while providing complete strategic context for informed decisions.

Negotiation Tools

Supporting utilities and tools for game implementations.

Negotiation Tools

Reusable utility functions and algorithms for all negotiation game types.

This module provides a comprehensive toolkit of mathematical functions, validation utilities, and strategic algorithms that support negotiation game implementations. These tools are designed to be game-agnostic and reusable across different negotiation scenarios and game types.

Key Features:
  • Mathematical utility functions for offer analysis

  • BATNA comparison and evaluation tools

  • Strategic suggestion algorithms for offer generation

  • Constraint validation systems for proposal checking

  • Generic utility calculation for multi-issue negotiations

  • Percentage-based comparison utilities for fairness analysis

Function Categories:
  1. Comparison Functions: Mathematical analysis of offers and values

  2. BATNA Tools: Best Alternative to Negotiated Agreement evaluation

  3. Strategic Functions: Algorithmic suggestions for negotiation moves

  4. Validation Tools: Constraint checking and proposal validation

  5. Utility Calculators: Multi-issue scoring and preference evaluation

Design Philosophy:

These tools follow functional programming principles with pure functions that have no side effects. Each function is self-contained and can be used independently or composed together for complex game logic.

Example Usage:
>>> # Calculate offer attractiveness
>>> offer_value = 42000
>>> batna_value = 40000
>>> is_attractive = is_offer_above_batna(offer_value, batna_value)
>>>
>>> # Suggest strategic next move
>>> next_offer = suggest_next_offer(42000, 40000, True, 0.05)
>>>
>>> # Calculate multi-issue utility
>>> proposal = {"server_room": 100, "meeting_access": 4}
>>> weights = {"server_room": 0.6, "meeting_access": 0.4}
>>> points = {"server_room": {100: 30}, "meeting_access": {4: 30}}
>>> utility = calculate_utility(proposal, weights, points)
negotiation_platform.games.negotiation_tools.calculate_percentage_difference(a: float, b: float) float[source]

Calculate the percentage difference between two values.

Computes the relative difference between two numeric values as a percentage of the second value. Useful for analyzing offer changes, price movements, and comparative value assessments in negotiations.

Parameters:
  • a (float) – First value for comparison (typically the new or proposed value).

  • b (float) – Second value for comparison (typically the reference or base value).

Returns:

Percentage difference as a decimal (0.0 to infinity).

Returns 0.0 if the reference value b is zero to avoid division errors.

Return type:

float

Example

>>> # 10% increase from base price
>>> diff = calculate_percentage_difference(44000, 40000)
>>> print(f"{diff:.1f}%")
10.0%
>>> # Price reduction analysis
>>> old_price = 45000
>>> new_price = 42000
>>> reduction = calculate_percentage_difference(new_price, old_price)
>>> print(f"Price reduced by {reduction:.1f}%")
Price reduced by 6.7%

Note

The function returns the absolute percentage difference. Use additional logic to determine if the change is an increase or decrease.

negotiation_platform.games.negotiation_tools.is_offer_above_batna(offer: float, batna: float) bool[source]

Check if an offer value is above or equal to the BATNA threshold.

Determines whether a proposed offer meets the minimum acceptable threshold defined by the Best Alternative to Negotiated Agreement (BATNA). This is a fundamental decision criterion in negotiation theory.

Parameters:
  • offer (float) – The proposed offer value to evaluate.

  • batna (float) – The BATNA threshold value for comparison.

Returns:

True if offer is greater than or equal to BATNA, False otherwise.

Return type:

bool

Example

>>> # Buyer evaluating a seller's offer
>>> seller_offer = 41000
>>> buyer_batna = 40000  # Best alternative option
>>> should_consider = is_offer_above_batna(seller_offer, buyer_batna)
>>> print(f"Offer worth considering: {should_consider}")
Offer worth considering: True
>>> # Seller evaluating buyer's offer
>>> buyer_offer = 38000
>>> seller_batna = 39000  # Alternative buyer option
>>> should_accept = is_offer_above_batna(buyer_offer, seller_batna)
>>> print(f"Offer acceptable: {should_accept}")
Offer acceptable: False
Strategic Usage:
  • Accept offers above BATNA (creates positive value)

  • Reject offers below BATNA (destroys value compared to alternatives)

  • Use BATNA as minimum threshold in counteroffers

negotiation_platform.games.negotiation_tools.is_offer_below_batna(offer: float, batna: float) bool[source]

Check if an offer value is below or equal to the BATNA threshold.

Determines whether a proposed offer falls below the minimum acceptable threshold. This is useful for identifying offers that should typically be rejected as they provide less value than available alternatives.

Parameters:
  • offer (float) – The proposed offer value to evaluate.

  • batna (float) – The BATNA threshold value for comparison.

Returns:

True if offer is less than or equal to BATNA, False otherwise.

Return type:

bool

Example

>>> # Quick rejection check
>>> low_offer = 37000
>>> batna_threshold = 39000
>>> should_reject = is_offer_below_batna(low_offer, batna_threshold)
>>> print(f"Offer below threshold: {should_reject}")
Offer below threshold: True

Note

This is the logical inverse of is_offer_above_batna() but provides semantic clarity when checking for unacceptable offers.

negotiation_platform.games.negotiation_tools.suggest_next_offer(current_offer: float, batna: float, last_rejected: bool, step: float = 0.05) float[source]

Generate strategic suggestion for next negotiation offer using BATNA-based algorithm.

Provides algorithmic guidance for offer adjustment based on previous negotiation outcomes and BATNA positioning. Implements a conservative strategy that moves offers closer to BATNA when faced with rejection, encouraging agreement while maintaining value protection.

Parameters:
  • current_offer (float) – The most recent offer value made in negotiation.

  • batna (float) – Best Alternative to Negotiated Agreement value.

  • last_rejected (bool) – Whether the previous offer was rejected by counterpart.

  • step (float, optional) – Percentage adjustment toward BATNA when rejected. Defaults to 0.05 (5% movement).

Returns:

Suggested next offer value. If last offer was accepted or this is

initial offer, returns current_offer unchanged. If rejected, returns adjusted offer moved toward BATNA by the specified step percentage.

Return type:

float

Algorithm:
  1. If last offer accepted: maintain current position

  2. If last offer rejected: move toward BATNA by step percentage

  3. Direction determined by BATNA position relative to current offer

  4. Step size controls aggressiveness of concession

Example

>>> # Buyer's offer was rejected, move toward seller
>>> current = 40000  # Buyer's last offer
>>> batna = 41000    # Buyer's alternative option
>>> rejected = True
>>> next_offer = suggest_next_offer(current, batna, rejected, 0.05)
>>> print(f"Next offer: ${next_offer:,.0f}")
Next offer: $40,050
>>> # Seller's offer was rejected, move toward buyer
>>> current = 44000  # Seller's last offer
>>> batna = 42000    # Seller's alternative option
>>> rejected = True
>>> next_offer = suggest_next_offer(current, batna, rejected, 0.10)
>>> print(f"Next offer: ${next_offer:,.0f}")
Next offer: $43,800
Strategic Considerations:
  • Smaller steps (0.01-0.03): Conservative, slow concessions

  • Moderate steps (0.05-0.10): Balanced concession strategy

  • Larger steps (0.15+): Aggressive movement toward agreement

negotiation_platform.games.negotiation_tools.check_constraints(offer: Dict[str, Any], constraints: Dict[str, Any]) bool[source]

Validate offer against multiple constraint functions for proposal acceptance.

Evaluates a complex offer or proposal against a set of constraint validation functions. Each constraint represents a business rule, resource limit, or negotiation requirement that must be satisfied for the offer to be valid.

Parameters:
  • offer (Dict[str, Any]) – Proposal dictionary containing offer terms and values. Structure varies by game type but typically includes resource allocations, prices, or multi-issue terms.

  • constraints (Dict[str, Any]) – Dictionary mapping constraint names to validation functions. Each function should accept the offer dict and return boolean.

Returns:

True if offer satisfies ALL constraints, False if any constraint fails.

Return type:

bool

Constraint Function Examples:
  • Resource limits: lambda offer: offer[“gpu_hours”] <= 10

  • Budget constraints: lambda offer: offer[“total_cost”] <= 50000

  • Logical requirements: lambda offer: offer[“start_date”] < offer[“end_date”]

  • Multi-field validation: lambda offer: offer[“gpus”] + offer[“cpus”] <= offer[“budget”]/1000

Example

>>> # Resource allocation validation
>>> offer = {"gpu_hours": 6, "developer_hours": 4, "budget": 45000}
>>> constraints = {
...     "gpu_limit": lambda o: o["gpu_hours"] <= 8,
...     "dev_limit": lambda o: o["developer_hours"] <= 5,
...     "budget_limit": lambda o: o["budget"] <= 50000,
...     "resource_balance": lambda o: o["gpu_hours"] * 1000 <= o["budget"]
... }
>>> is_valid = check_constraints(offer, constraints)
>>> print(f"Offer valid: {is_valid}")
Offer valid: True
>>> # Price negotiation validation
>>> car_offer = {"price": 43000, "warranty": True, "delivery_days": 14}
>>> car_constraints = {
...     "price_range": lambda o: 35000 <= o["price"] <= 50000,
...     "delivery_time": lambda o: o["delivery_days"] <= 30
... }
>>> valid_car_deal = check_constraints(car_offer, car_constraints)
Usage Patterns:
  • Game rule validation before processing actions

  • Resource constraint checking in allocation games

  • Business logic validation for complex proposals

  • Multi-criteria decision support systems

Error Handling:

Function returns False if any constraint function raises an exception, providing graceful handling of invalid offer structures or constraint errors.

negotiation_platform.games.negotiation_tools.calculate_utility(offer: Dict[str, Any], weights: Dict[str, float], points: Dict[str, Dict[Any, float]]) float[source]

Calculate total utility value for multi-issue negotiation proposals.

Computes weighted utility scores for complex proposals involving multiple negotiation issues. Each issue contributes to total utility based on its importance weight and the point value associated with the chosen option. This enables quantitative comparison of multi-dimensional offers.

Parameters:
  • offer (Dict[str, Any]) – Proposal dictionary mapping issue names to chosen options/values for each negotiation issue.

  • weights (Dict[str, float]) – Importance weights for each issue, determining how much each issue contributes to total utility. Weights typically sum to 1.0 but not required.

  • points (Dict[str, Dict[Any, float]]) – Point value mappings for each issue. Structure: {issue: {option: point_value}}

Returns:

Total weighted utility score. Higher values indicate more

attractive proposals for the evaluating party.

Return type:

float

Calculation Formula:

utility = Σ(weight[issue] × points[issue][option]) for all issues

Example

>>> # IT team evaluating office space proposal
>>> proposal = {
...     "server_room": 150,      # 150 sqm server space
...     "meeting_access": 2,     # 2 days per week
...     "cleaning": "Shared",    # Shared cleaning responsibility
...     "branding": "Prominent"  # Prominent marketing visibility
... }
>>>
>>> # IT team's importance weights
>>> it_weights = {
...     "server_room": 0.40,    # Server space is top priority
...     "meeting_access": 0.10,  # Low meeting room needs
...     "cleaning": 0.30,       # Moderate cleaning concern
...     "branding": 0.20        # Low branding priority
... }
>>>
>>> # Point values for each option from IT perspective
>>> it_points = {
...     "server_room": {50: 10, 100: 30, 150: 60},
...     "meeting_access": {2: 10, 4: 30, 7: 60},
...     "cleaning": {"IT": 30, "Shared": 50, "Outsourced": 10},
...     "branding": {"Minimal": 10, "Moderate": 30, "Prominent": 60}
... }
>>>
>>> utility = calculate_utility(proposal, it_weights, it_points)
>>> print(f"IT team utility: {utility:.1f}")
IT team utility: 53.0
>>> # Marketing team would have different weights and potentially points
>>> marketing_weights = {
...     "server_room": 0.10,    # Low server space priority
...     "meeting_access": 0.30,  # High meeting room needs
...     "cleaning": 0.20,       # Moderate cleaning concern
...     "branding": 0.40        # Branding is top priority
... }
>>> marketing_utility = calculate_utility(proposal, marketing_weights, it_points)
>>> print(f"Marketing team utility: {marketing_utility:.1f}")
Marketing team utility: 42.0
Usage Patterns:
  • Multi-issue negotiation evaluation

  • Proposal ranking and comparison

  • Win-win solution identification

  • Pareto efficiency analysis

  • Automated offer generation and optimization

Note

Missing issues in offer, weights, or points are treated as zero contribution. This provides graceful handling of partial proposals or incomplete data.