From 9d34ec6dbbb3e84a55c5c2c5d6085551745324be Mon Sep 17 00:00:00 2001 From: big-c-note Date: Mon, 29 Jun 2020 23:18:20 -0400 Subject: [PATCH] setting up support for card type in lut --- poker_ai/ai/runner.py | 4 ++- poker_ai/ai/singleprocess/train.py | 13 +++++-- poker_ai/clustering/card_info_lut_builder.py | 4 +-- poker_ai/games/short_deck/state.py | 38 +++++++++++++++----- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/poker_ai/ai/runner.py b/poker_ai/ai/runner.py index 98e84319..fa84930d 100644 --- a/poker_ai/ai/runner.py +++ b/poker_ai/ai/runner.py @@ -205,7 +205,7 @@ def resume(server_config_path: str): ) @click.option( "--lut_path", - default="./card_info_lut.joblib", + default=".", help=( "The path to the files for clustering the infosets." ), @@ -275,6 +275,8 @@ def start( simple_search( config=config, save_path=save_path, + lut_path=lut_path, + pickle_dir=pickle_dir, strategy_interval=strategy_interval, n_iterations=n_iterations, lcfr_threshold=lcfr_threshold, diff --git a/poker_ai/ai/singleprocess/train.py b/poker_ai/ai/singleprocess/train.py index db8e2ca8..4bc147ca 100644 --- a/poker_ai/ai/singleprocess/train.py +++ b/poker_ai/ai/singleprocess/train.py @@ -39,6 +39,8 @@ def print_strategy(strategy: Dict[str, Dict[str, int]]): def simple_search( config: Dict[str, int], save_path: Path, + lut_path: Union[str, Path], + pickle_dir: bool, strategy_interval: int, n_iterations: int, lcfr_threshold: int, @@ -81,14 +83,19 @@ def simple_search( """ utils.random.seed(42) agent = Agent(use_manager=False) - info_set_lut = {} + card_info_lut = {} for t in trange(1, n_iterations + 1, desc="train iter"): if t == 2: logging.disable(logging.DEBUG) for i in range(n_players): # fixed position i # Create a new state. - state: ShortDeckPokerState = new_game(n_players, info_set_lut) - info_set_lut = state.info_set_lut + state: ShortDeckPokerState = new_game( + n_players, + card_info_lut, + lut_path=lut_path, + pickle_dir=pickle_dir + ) + card_info_lut = state.card_info_lut if t > update_threshold and t % strategy_interval == 0: ai.update_strategy(agent=agent, state=state, i=i, t=t) if t > prune_threshold: diff --git a/poker_ai/clustering/card_info_lut_builder.py b/poker_ai/clustering/card_info_lut_builder.py index 16479205..2592c240 100644 --- a/poker_ai/clustering/card_info_lut_builder.py +++ b/poker_ai/clustering/card_info_lut_builder.py @@ -64,8 +64,8 @@ def compute( """ log.info("Starting computation of clusters.") start = time.time() - if "preflop" not in self.card_info_lut: - self.card_info_lut["preflop"] = compute_preflop_lossless_abstraction( + if "pre_flop" not in self.card_info_lut: + self.card_info_lut["pre_flop"] = compute_preflop_lossless_abstraction( builder=self ) joblib.dump(self.card_info_lut, self.card_info_lut_path) diff --git a/poker_ai/games/short_deck/state.py b/poker_ai/games/short_deck/state.py index 42a13781..ab6268b4 100644 --- a/poker_ai/games/short_deck/state.py +++ b/poker_ai/games/short_deck/state.py @@ -48,11 +48,18 @@ def new_game( ] if card_info_lut: # Don't reload massive files, it takes ages. - state = ShortDeckPokerState(players=players, load_card_lut=False, **kwargs) + state = ShortDeckPokerState( + players=players, + load_card_lut=False, + **kwargs + ) state.card_info_lut = card_info_lut else: # Load massive files. - state = ShortDeckPokerState(players=players, **kwargs) + state = ShortDeckPokerState( + players=players, + **kwargs + ) return state @@ -79,8 +86,9 @@ def __init__( f"At least 2 players must be provided but only {n_players} " f"were provided." ) + self._pickle_dir = pickle_dir if load_card_lut: - self.card_info_lut = self.load_card_lut(lut_path, pickle_dir) + self.card_info_lut = self.load_card_lut(lut_path, self._pickle_dir) else: self.card_info_lut = {} # Get a reference of the pot from the first player. @@ -227,7 +235,10 @@ def apply_action(self, action_str: Optional[str]) -> ShortDeckPokerState: return new_state @staticmethod - def load_card_lut(lut_path: str = ".", pickle_dir: bool = False) -> Dict[str, Dict[Tuple[int, ...], str]]: + def load_card_lut( + lut_path: str = ".", + pickle_dir: bool = False + ) -> Dict[str, Dict[Tuple[int, ...], str]]: """ Load card information lookup table. @@ -267,7 +278,7 @@ def load_card_lut(lut_path: str = ".", pickle_dir: bool = False) -> Dict[str, Di card_info_lut[betting_stage] = joblib.load(fp) elif lut_path: logger.info(f"Loading card from single file at path: {lut_path}") - card_info_lut = joblib.load(lut_path) + card_info_lut = joblib.load(lut_path + '/card_info_lut.joblib') else: card_info_lut = {} return card_info_lut @@ -373,20 +384,29 @@ def betting_round(self) -> int: @property def info_set(self) -> str: """Get the information set for the current player.""" + if self._pickle_dir: + key = operator.attrgetter("eval_card") + else: + key = None cards = sorted( self.current_player.cards, - key=operator.attrgetter("eval_card"), + key=key, reverse=True, ) cards += sorted( self._table.community_cards, - key=operator.attrgetter("eval_card"), + key=key, reverse=True, ) - eval_cards = tuple([card.eval_card for card in cards]) + if self._pickle_dir: + lookup_cards = tuple([card.eval_card for card in cards]) + else: + lookup_cards = tuple(cards) try: - cards_cluster = self.card_info_lut[self._betting_stage][eval_cards] + cards_cluster = self.card_info_lut[self._betting_stage][lookup_cards] except KeyError: + import ipdb; + ipdb.set_trace() return "default info set, please ensure you load it correctly" # Convert history from a dict of lists to a list of dicts as I'm # paranoid about JSON's lack of care with insertion order.