File size: 3,166 Bytes
8787979
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""Simulator for Kuhn Poker.

This module implements the KuhnPokerSimulator class, which simulates games of
Kuhn Poker using the OpenSpiel framework.

For Kuhn Poker, the game mechanics involve:

- Betting rounds where decisions depend on the game state and potential strategies.
- Chance nodes, which require specific handling (e.g., dealing cards).
"""

from simulators.base_simulator import GameSimulator
from utils.llm_utils import llm_decide_move
from typing import Any
import random


class KuhnPokerSimulator(GameSimulator):
    """Simulator for Kuhn Poker."""

    def _handle_chance_node(self, state: Any):
        """Handle chance nodes for Kuhn Poker.

        Args:
            state (pyspiel.State): The current state of the game.
        """
        outcomes, probabilities = zip(*state.chance_outcomes())
        sampled_outcome = random.choices(outcomes, probabilities)[0]
        state.apply_action(sampled_outcome)

    def _get_action(self, player: int, state: Any, legal_actions: list) -> int:
        """Gets the action for the current player.

        Uses the dedicated Kuhn Poker prompt if the player type is LLM.

        Args:
            player: The index of the current player.
            state: The current game state.
            legal_actions: The legal actions available for the player.

        Returns:
            int: The action selected by the player.
        """
        # If the player type is LLM, use the specialized Kuhn Poker prompt
        if player < len(self.llms):
            model_name = list(self.llms.keys())[player]
            llm = self.llms[model_name]
            prompt = self._generate_poker_prompt(state, legal_actions, player)
            return llm_decide_move(llm, prompt, tuple(legal_actions))  # Convert to tuple

        # For all other cases, defer to the parent class's implementation
        return super()._get_action(player, state, legal_actions)



    def _generate_poker_prompt(self,state: Any, legal_actions: list, player: int) -> str:
        """Generates a detailed prompt for Kuhn Poker using OpenSpiel's state.

        Args:
            state (pyspiel.State): The current game state.
            legal_actions (list): Legal actions available to the player.
            player (int): The index of the current player.

        Returns:
            str: A natural language prompt describing the game state and options.
        """
        # Extract player-specific observation
        observation = state.observation_string(player)

        # Map actions to readable terms
        action_map = {0: "PASS (no additional bet)", 1: "BET (add to the pot)"}
        actions_str = "\n".join(f"{action}: {action_map[action]}" for action in legal_actions)

        # Build the prompt
        prompt = (
            f"You are Player {player + 1} in a game of Kuhn Poker.\n"
            f"Your private observation: {observation}\n"
            f"The goal is to maximize your winnings based on your card and the pot.\n\n"
            f"Available actions:\n{actions_str}\n\n"
            "What action do you choose? Reply with the number corresponding to your action."
        )
        return prompt