def get_suggestions(cards, n_best_splits, unique_code_levels, strategyID=1, ret_card_strs=True): deck = Deck() cards = deck.deal_custom_hand(cards) strategy = ChinesePokerPctileScoreStrategy.init_from_db( strategyID, split_gen_filter_by_score=True, sort_set_cards_by_group=True, ) best_splits, _, _ = strategy.pick_n_best_splits( cards, n_best_splits, unique_code_levels=unique_code_levels) # Insert processing - sort cards, add desciprions of groups, scores #for split in best_splits: # # inds = split[0] # cards = split[1] # codes = split[2] # scores = split[3] # weighted_score = split[4] split_code_scores = [split.StratSplitScore for split in best_splits] if ret_card_strs is True: return [[[str(c) for c in s] for s in split.Cards] for split in best_splits], split_code_scores else: return best_splits, split_code_scores
def gen_best_split_data( n_hands, strategy=None, output_progress_every=None, split_gen_strategy=None, ): if strategy is None: strategy = ChinesePokerPctileScoreStrategy(split_gen_filter_by_score = True) start = timer() deck = Deck() split_codes = [] split_scores = [] split_sup_scores = [] split_cards = [] split_gen_filter_scores = [] split_gen_filter_sup_scores = [] for hI in range(n_hands): cards = deck.deal_cards()[0] if split_gen_strategy is not None: splits_pool = split_gen_strategy.gen_all_splits(cards)[0] else: splits_pool = None best_split, _, _ = strategy.pick_single_split(cards, generated_splits=splits_pool) split_codes.append(best_split.Codes) split_sup_scores.append(best_split.StratSupScores) split_scores.append(best_split.StratSplitScore) split_gen_filter_sup_scores.append(best_split.GenFilterSupScores) split_gen_filter_scores.append(best_split.GenFilterSplitScore) temp_cards = flattened_list(best_split.Cards) split_cards.append([str(card) for card in temp_cards]) if output_progress_every is not None and (hI+1)%output_progress_every == 0: min_elapsed = (timer()-start)/60 print (f'Processed {hI+1} of {n_hands} hands. {min_elapsed} min elasped.') data = { 'Codes':split_codes, 'Scores':split_scores, 'SupScores':split_sup_scores, 'Cards':split_cards, 'GenFilterScores':split_gen_filter_scores, 'GenFilterSupScores':split_gen_filter_sup_scores, } return data
def __init__( self, game_mode='AUTO', players=None, strategies=None, random_seat=False, history=None, ): self.deck = Deck() self.n_players = len(ChinesePokerGame.player_seat_labels) # 4 self.cur_dealer_ind = ChinesePokerGame.player_seat_labels.index(ChinesePokerGame.starting_dealer) self.cur_play_seq = None self.games_played = 0 #self.games_history = ChinesePokerGameHistory() self.game_mode = game_mode self.players = {} if strategies is None: strategies = [ChinesePokerPctileScoreStrategy() for pI in range(self.n_players)] elif not isinstance(strategies, (list, tuple)): strategies = [strategies for pI in range(self.n_players)] self.reset_cur_game_info() if game_mode == 'AUTO': if not random_seat: for i,label in enumerate(self.player_seat_labels): if players is None or players[i] is None: self.players[label] = ComputerChinesePokerPlayer(strategy=strategies[i]) else: self.players[label] = players[i] else: print('Need to implement random_seating') else: raise InvalidGameModeError(f'game_mode {game_mode} not valid.') if history is None: history = ChinesePokerGameHistory() self.history = history return
def yield_dealt_hands_from_text_dump(self, text_file=None, deck_obj=Deck(), load_from=None, load_to=None): if text_file is None: text_file = self.get_latest_dealt_hands_dump() with open(text_file) as f: for line_no, line in enumerate(f): if load_from and line_no + 1 < load_from: continue yield line_no, self._convert_rep_str_to_dealt_cards( line, deck_obj) if load_to and line_no + 1 > load_to: break return
def get_splits_data_for_single_game_and_seat_from_db( game_id, seat_id, cards=None, ): """[summary] Args: game_id (int): GameID seat_id (int): Between 1 and 4 cards (List): List of Card objects or card strings. """ if cards is None: hands = next(yield_dealt_hands_from_db(game_id, game_id))[1] cards = hands[seat_id - 1] elif isinstance(cards[0], str): deck = Deck() cards = deck.deal_custom_hand(cards) splits_table = GameC.CHINESE_POKER_db_consts['splits_table'] codes_table = GameC.CHINESE_POKER_db_consts['split_codes_table'] query = f'SELECT SplitSeqNo, SplitStr, + ' \ f'c1.L1Code AS S1L1Code, c1.L2Code AS S1L2Code, c1.L3Code AS S1L3Code, c1.L4Code AS S1L4Code, c1.L5Code AS S1L5Code, c1.L6Code AS S1L6Code, ' + \ f'c2.L1Code AS S2L1Code, c2.L2Code AS S2L2Code, c2.L3Code AS S2L3Code, c2.L4Code AS S2L4Code, c2.L5Code AS S2L5Code, c2.L6Code AS S2L6Code, ' + \ f'c3.L1Code AS S3L1Code, c3.L2Code AS S3L2Code, c3.L3Code AS S3L3Code, c3.L4Code AS S3L4Code, c3.L5Code AS S3L5Code, c3.L6Code AS S3L6Code ' + \ f'FROM {splits_table} s ' + \ f'JOIN {codes_table} c1 ON s.SplitID=c1.SplitID ' + \ f'JOIN {codes_table} c2 ON s.SplitID=c2.SplitID ' + \ f'JOIN {codes_table} c3 ON s.SplitID=c3.SplitID ' + \ f'WHERE s.GameID={game_id} AND s.SeatID={seat_id} ' + \ f'AND c1.SetNo=1 AND c2.SetNo=2 AND c3.SetNo=3' db_output, _ = DBF.select_query(query) hand_splits = [] for row in db_output: split_seq_no, split_str, s1c1, s1c2, s1c3, s1c4, s1c5, s1c6, s2c1, s2c2, s2c3, s2c4, s2c5, s2c6, s3c1, s3c2, s3c3, s3c4, s3c5, s3c6 = row split_cards, split_inds = _convert_split_str_to_split_cards( cards, split_str) s1code = [s1c1, s1c2, s1c3, s1c4, s1c5, s1c6] s2code = [s2c1, s2c2, s2c3, s2c4, s2c5, s2c6] s3code = [s3c1, s3c2, s3c3, s3c4, s3c5, s3c6] s1code = CardGroupCode([code for code in s1code if code is not None]) s2code = CardGroupCode([code for code in s2code if code is not None]) s3code = CardGroupCode([code for code in s3code if code is not None]) split_info_factory = ChinesePokerStrategy.ranked_split_info_factory split_info = split_info_factory( split_inds, split_cards, (s1code, s2code, s3code), None, None, None, None, None, split_seq_no, ) hand_splits.append(split_info) hand_splits = sorted(hand_splits, key=lambda x: x.SeqNo) return hand_splits
import glob import json from deprecated import deprecated import random from ChinesePokerLib.classes.Deck import Deck from ChinesePokerLib.classes.Card import Card import ChinesePokerLib.modules.DBFunctions as DBF from ChinesePokerLib.classes.CardGroup import CardGroupCode from ChinesePokerLib.classes.Strategy import ChinesePokerStrategy import ChinesePokerLib.vars.GameConstants as GameC import ChinesePokerLib.vars.GlobalConstants as GlobC deck_type = 'STANDARD' deck_obj = Deck(deck_type) def get_latest_dealt_hands_dump(min_n_games=10000): files = glob.glob(str(GlobC.DEALT_HANDS_DUMP_DIR / '*.txt')) p = re.compile('.*?/DealtCardsDump_([0-9]*?)Games_([0-9]{8}).txt') matches = [ (p.match(filename).group(0), p.match(filename).group(1), p.match(filename).group(2)) for filename in files if p.match(filename) and int(p.match(filename).group(1)) >= min_n_games ] datetimes = [datetime.strptime(item[2], '%Y%m%d') for item in matches] max_date_ind = datetimes.index(max(datetimes))
class ChinesePokerGame: # Class attributes game_type = GConst.ChinesePokerKey player_seat_labels = GConst.GEN_seat_labels[game_type] # ('S', 'W', 'N', 'E') starting_dealer = GConst.GEN_default_starting_dealer[game_type] # 'S' hands_split_into = GConst.GEN_hands_split_into[game_type] # (3,5,5) splits_force_ascending = GConst.GEN_hands_split_ascending_required[game_type] # True hand_class = ChinesePokerHand def __init__( self, game_mode='AUTO', players=None, strategies=None, random_seat=False, history=None, ): self.deck = Deck() self.n_players = len(ChinesePokerGame.player_seat_labels) # 4 self.cur_dealer_ind = ChinesePokerGame.player_seat_labels.index(ChinesePokerGame.starting_dealer) self.cur_play_seq = None self.games_played = 0 #self.games_history = ChinesePokerGameHistory() self.game_mode = game_mode self.players = {} if strategies is None: strategies = [ChinesePokerPctileScoreStrategy() for pI in range(self.n_players)] elif not isinstance(strategies, (list, tuple)): strategies = [strategies for pI in range(self.n_players)] self.reset_cur_game_info() if game_mode == 'AUTO': if not random_seat: for i,label in enumerate(self.player_seat_labels): if players is None or players[i] is None: self.players[label] = ComputerChinesePokerPlayer(strategy=strategies[i]) else: self.players[label] = players[i] else: print('Need to implement random_seating') else: raise InvalidGameModeError(f'game_mode {game_mode} not valid.') if history is None: history = ChinesePokerGameHistory() self.history = history return def reset_cur_game_info(self): self.cur_scores = None self.cur_score_details = None self.cur_split_ranks = None self.cur_round_time = None self.cur_base_scores = None return def _create_computer_player(self): return def play_game(self, cards=None, deal_cards_from_dealer=False, splits_data=None): """Play single game of ChinesePoker """ self._pregame_processes() start = timer() if self.game_mode == 'AUTO': self.play_auto_game(cards, deal_cards_from_dealer, splits_data) self.cur_round_time = timer()-start self._postgame_processes() return def play_auto_game( self, cards=None, deal_cards_from_dealer=False, splits_data=None, # Container of 4 dicts ): """Play single auto-game of Chinese Poker """ if splits_data is not None: self._dist_splits_data(splits_data) elif splits_data is None: if cards is not None: self._deal_specific_cards(cards, deal_cards_from_dealer) elif cards is None: _ = self._deal_random_cards() # Choose hands for player_ind in self.cur_play_seq: seat_label = self.player_seat_labels[player_ind] self.players[seat_label].play_hand() # Compare splits comparison_results, self.cur_split_ranks = self._compare_splits() self.cur_scores, self.cur_score_details, self.cur_base_scores = self._score_comparison(comparison_results) return def _score_comparison(self, comparison_results): tot_scores = {} det_scores = {} base_scores = {} for seat in self.player_seat_labels: player_score = 0 player_base_score = 0 det_scores[seat] = {} for opp_seat in self.player_seat_labels: if opp_seat != seat: comp_score = sum(comparison_results[seat][opp_seat]) player_base_score += comp_score if abs(comp_score) == len(comparison_results[seat][opp_seat]): comp_score = 2*comp_score player_score += comp_score det_scores[seat][opp_seat] = comp_score tot_scores[seat] = player_score base_scores[seat] = player_base_score return tot_scores, det_scores, base_scores def _compare_splits(self): seat_pairs = list(combinations(self.player_seat_labels,2)) comparison_results = {} for seat in self.player_seat_labels: comparison_results[seat] = {} all_ranks = {label:[] for label in self.player_seat_labels} # Do it by ranks instead for set_i in range(len(self.hands_split_into)): set_codes = [self.players[label].split_info['Codes'][set_i] for label in self.player_seat_labels] ranks = ss.rankdata(set_codes) for sI, label in enumerate(self.player_seat_labels): all_ranks[label].append(ranks[sI]) for pair in seat_pairs: pair_comparison_results = self._compare_pair_of_ranks( all_ranks[pair[0]], all_ranks[pair[1]], ) #pair_comparison_results = self._compare_pair_of_splits( # self.players[pair[0]], # self.players[pair[1]], #) # classifier, comparison_results[pair[0]][pair[1]] = pair_comparison_results comparison_results[pair[1]][pair[0]] = [-result for result in pair_comparison_results] return comparison_results, all_ranks # first_set = classifier._find_n_card_set_codes( # first_set_cards, # set_size=self.split_into[0], # max_code = second_set_code, # ) # # if len(first_set) == 0: # continue # else: # first_set_code = first_set[0][0] def _get_all_codes(self): return def _compare_pair_of_ranks(self, ranks1, ranks2): n_splits = len(self.hands_split_into) comparison_results = [] for sI in range(n_splits): if ranks1[sI] > ranks2[sI]: comparison_results.append(1) elif ranks1[sI] < ranks2[sI]: comparison_results.append(-1) else: comparison_results.append(0) return comparison_results def _compare_pair_of_splits(self, player1, player2): if classifier is None: classifier = CardGroupClassifier() n_splits = len(self.hands_split_into) comparison_results = [] for sI in range(n_splits): p1_code = player1.cur_hand.split_codes[sI] p2_code = player2.cur_hand.split_codes[sI] if p1_code > p2_code: comparison_results.append(1) elif p1_code < p2_code: comparison_results.append(-1) else: comparison_results.append(0) return comparison_results def _update_history(self): # Prepare data history_data = {'Players': {}, 'Dealer': None, 'RoundTime': None, } for seat_label in self.player_seat_labels: this_player = self.players[seat_label] history_data['Players'][seat_label] = {} history_data['Players'][seat_label]['PlayerID'] = this_player.id history_data['Players'][seat_label]['SplitCards'] = this_player.split_info['Cards'] history_data['Players'][seat_label]['SplitCodes'] = this_player.split_info['Codes'] history_data['Players'][seat_label]['SplitCodeSupScores'] = this_player.split_info['SupScores'] history_data['Players'][seat_label]['SplitRanks'] = self.cur_split_ranks[seat_label] history_data['Players'][seat_label]['SplitCodeScore'] = this_player.split_info['SplitScore'] history_data['Players'][seat_label]['GameScoreDetails'] = self.cur_score_details[seat_label] history_data['Players'][seat_label]['TotGameScore'] = self.cur_scores[seat_label] history_data['Players'][seat_label]['SplitSelectionTime'] = this_player.split_info['SelectionTime'] history_data['Players'][seat_label]['SplitsGenerated'] = this_player.split_info['SplitsGenerated'] history_data['Players'][seat_label]['BaseGameScore'] = self.cur_base_scores[seat_label] history_data['Dealer'] = self.player_seat_labels[self.cur_dealer_ind] history_data['RoundTime'] = self.cur_round_time self.history.add_round(history_data) # return def _pregame_processes(self): # Play seqeuence (start with one after dealer) self.cur_play_seq = [(self.cur_dealer_ind + 1 + i) % self.n_players for i in range(self.n_players)] return def _postgame_processes(self): self.games_played += 1 # Update history/stats self._update_history() # Change dealer self._next_dealer() # Clear variables self.reset_cur_game_info() for seat_label in self.player_seat_labels: #self.players[seat_label].cur_hand.reset_split_info() self.players[seat_label].reset_cur_game_data() return def _next_dealer(self): #cur_dealer_ind = self.player_labels.index(self.cur_dealer) self.cur_dealer_ind = (self.cur_dealer_ind + 1) % self.n_players return def _deal_random_cards(self): """Deal random sets of hands Returns: [type]: [description] """ dealt_cards = self.deck.deal_cards() self._update_player_hands(dealt_cards) return dealt_cards def _deal_specific_cards(self, cards_to_deal, deal_cards_from_dealer): """Deal specific hands Args: card_to_deal ([type]): Hands to deal """ self._update_player_hands(cards_to_deal, deal_cards_from_dealer) return def _update_player_hands(self, dealt_cards, deal_cards_from_dealer): if deal_cards_from_dealer: for i, player_ind in enumerate(self.cur_play_seq): seat_label = self.player_seat_labels[player_ind] self.players[seat_label].cur_hand = self.hand_class(dealt_cards[i]) else: for i, seat_label in enumerate(self.__class__.player_seat_labels): self.players[seat_label].cur_hand = self.hand_class(dealt_cards[i]) return def _dist_splits_data(self, splits_data): for i, seat_label in enumerate(self.__class__.player_seat_labels): if 'P' in list(splits_data.keys())[0]: self.players[seat_label].cur_splits_data = splits_data[f'P{i}'] else: self.players[seat_label].cur_splits_data = splits_data[i] return
def __init__(self, deck_type='STANDARD'): self.deck_type = deck_type self.deck = Deck(deck_type) return
class Data: def __init__(self, deck_type='STANDARD'): self.deck_type = deck_type self.deck = Deck(deck_type) return """ def _find_latest_score_file(n_cards, set_size): base_filename = f'best{set_size}CardSetOf{n_cards}CardHand_' files = glob.glob(op.join(DATADIR, base_filename + '*.csv')) p = re.compile('.*?Hand_([0-9]*?)\.csv') dates = [p.match(filename).group(1) for filename in files if p.match(filename)] datetimes = [datetime.strptime(date_str, '%Y%m%d') for date_str in dates] max_date = max(datetimes) latest_file = base_filename + datetime.strftime(max_date, '%Y%m%d') + '.csv' latest_file = op.join(DATADIR, latest_file) return latest_file """ def get_latest_dealt_hands_dump(self, min_n_games=10000): files = glob.glob(str(GlobC.DEALT_HANDS_DUMP_DIR / '*.txt')) p = re.compile('.*?/DealtCardsDump_([0-9]*?)Games_([0-9]{8}).txt') matches = [(p.match(filename).group(0), p.match(filename).group(1), p.match(filename).group(2)) for filename in files if p.match(filename) and int(p.match(filename).group(1)) >= min_n_games] datetimes = [datetime.strptime(item[2], '%Y%m%d') for item in matches] max_date_ind = datetimes.index(max(datetimes)) latest_file = matches[max_date_ind][0] return latest_file def gen_dealt_hands_and_add_to_db( self, n_games, table=GameC.CHINESE_POKER_db_consts['dealt_hands_table'], write_every=1000): conn = DBF.connect_to_db() cursor = conn.cursor() start = timer() to_be_inserted = [] base_query = f'INSERT INTO {table} (DealtHandsStr) VALUES ' for i in range(1, n_games + 1): dealt_cards = self.deck.deal_cards() dealt_cards_str = self._convert_dealt_cards_to_rep_str(dealt_cards) to_be_inserted.append(dealt_cards_str) if i % write_every == 0: query = base_query for dealt_cards_str in to_be_inserted: query += f'({dealt_cards_str}),' #insert_query = """INSERT INTO random_dealt_hands (DealtHandsStr) VALUES (%s)""" #cursor.executemany(insert_query, to_be_inserted) query = query[:-1] cursor.execute(query) conn.commit() min_elapsed = (timer() - start) / 60 print( f'Inserted {i} of {n_games} DealtHandsStr rows into {table} - {min_elapsed} min elasped.' ) to_be_inserted = [] def gen_dealt_hands_text_dump(self, n_games, output_file=None, output_progress_every=1000): if output_file is None: today_str = datetime.today().strftime('%Y%m%d') output_file = pathlib.Path( GlobC.DEALT_HANDS_DUMP_DIR ) / f'DealtCardsDump_{n_games}Games_{today_str}.txt' #undealt_deck_rep = ['0' for card in self.deck.deck] with open(output_file, 'w') as f: for gI in range(n_games): if output_progress_every and (gI + 1) % output_progress_every == 0: print(f'Dealt {gI+1} of {n_games}') #dealt_deck_rep = undealt_deck_rep.copy() dealt_cards = self.deck.deal_cards() dealt_cards_str = self._convert_dealt_cards_to_rep_str( dealt_cards) f.write(dealt_cards_str + '\n') return def yield_dealt_hands_from_text_dump(self, text_file=None, deck_obj=Deck(), load_from=None, load_to=None): if text_file is None: text_file = self.get_latest_dealt_hands_dump() with open(text_file) as f: for line_no, line in enumerate(f): if load_from and line_no + 1 < load_from: continue yield line_no, self._convert_rep_str_to_dealt_cards( line, deck_obj) if load_to and line_no + 1 > load_to: break return def yield_dealt_hands_from_db( self, start_game_no, end_game_no, db_connector=None, db_load_batch_size=1000, cards_as_str=False, ): dealt_hands_table = GameC.CHINESE_POKER_db_consts["dealt_hands_table"] base_query = f'SELECT GameID, DealtHandsStr FROM {dealt_hands_table} WHERE GameID BETWEEN %s AND %s' deck_obj = self.deck if start_game_no is None: start_game_no = 1 temp_start_game_no = start_game_no while 1: temp_end_game_no = min(end_game_no, temp_start_game_no + db_load_batch_size - 1) query = base_query % (temp_start_game_no, temp_end_game_no) db_output, _ = DBF.select_query(query) for row in db_output: dealt_cards = self._convert_rep_str_to_dealt_cards( row[1], deck_obj) if cards_as_str: dealt_cards = [[str(card) for card in hand] for hand in hands] yield row[0], dealt_cards if temp_end_game_no >= end_game_no: break temp_start_game_no += db_load_batch_size yield None, None def _convert_dealt_cards_to_rep_str(self, dealt_cards): dealt_deck_rep = ['0' for card in self.deck.deck] for pI, player_cards in enumerate(dealt_cards): for card in player_cards: dealt_deck_rep[card.deck_card_ind] = str(pI + 1) dealt_cards_str = ''.join(dealt_deck_rep) return dealt_cards_str def _convert_rep_str_to_dealt_cards(self, rep_str, deck_obj, n_players=4): player_inds = [int(char) for char in rep_str.strip()] if not n_players: n_players = max(player_inds) dealt_cards = [[] for _ in range(n_players)] for card_strength_ind, player_ind in enumerate(player_inds): card_deck_ind = deck_obj.inds_of_deck_card_order[card_strength_ind] dealt_cards[player_ind - 1].append(deck_obj.deck[card_deck_ind]) return dealt_cards def yield_splits_from_dealt_hands( self, strategy, start_deal_no=None, end_deal_no=None, verbose=False, from_db=True, dealt_hands_text_file=None, ): # VC TODO: verbose -> progress_every_n_splits if from_db: dealt_cards_generator = self.yield_dealt_hands_from_db( start_deal_no, end_deal_no) else: if dealt_hands_text_file is None: dealt_hands_text_file = self.get_latest_dealt_hands_dump() dealt_cards_generator = self.yield_dealt_hands_from_text_dump( dealt_hands_text_file) while 1: deal_no, dealt_cards = next(dealt_cards_generator) if deal_no is None: break if start_deal_no is not None and deal_no < start_deal_no: continue if end_deal_no is not None and deal_no > end_deal_no: break data = {} for player_ind in range(4): #_, splits, _ = strategy.pick_single_split(dealt_cards[player_ind]) splits, sec_elapsed = strategy.gen_all_splits( dealt_cards[player_ind]) cards = [] codes = [] #scores = [] card_inds = [] split_inds_strs = [] #weighted_scores = [] for split in splits: cards.append([ str(card) for split_set in split[1] for card in split_set ]) card_inds.append( [ind for split_set in split[0] for ind in split_set]) codes.append([code.code for code in split[2]]) #scores.append(split[1][1]) #weighted_scores.append(split[1][0]) split_inds_strs.append( self._convert_card_inds_to_set_inds_str(split[0])) data[f'P{player_ind+1}'] = { 'CardInds': card_inds, 'SplitIndsStrs': split_inds_strs, 'Cards': cards, 'Codes': codes, 'DealtCards': dealt_cards[player_ind], 'SecElapsed': sec_elapsed, } yield deal_no, data yield None, None return def write_splits_data_to_db(self, game_id, splits_data): """Function for writing splits data generated by yield_splits_from_dealt_hands to db. Writes to: feasible_hand_splits - GameID, SeatID, SplitSeqNo, SplitStr, DateGen split_set_codes - SplitID, SeatID, SetNo, L1Code, L2Code, L3Code, L4Code, L5Code, L6Code Args: game_id (int): Game ID - Should match what is in random_dealt_hands splits_data ([type]): Dict with following structure: ('P{PLAYERNO}':player_splits_data) where PLAYERNO between 1 and 4 inclusive player_splits_data itself is a dict with the following structure: 'DealtCards': Dealt cards in original order 'CardInds': List of indices lists. Each outer list corresponds to a possible split. The indices refer to the indices of the DealtCards list. The order combined with the split_into attribute of the strategy object infers the split card sets. 'Codes': List of list of tuples. Each outer list corresponds to a possible split. Each inner list consists of tuples representing the card group codes of the sets. 'Scores': List of score lists. Each outer list corresponds to a possible split. Each inner list contains the set scores. 'WeightedScores': List of weighted scores. One score for each possible split. 'SplitIndsStrs': List of strings, each of length 13, the characters correspond to the dealt cards. Each string corresponds to a possible split. The characters refer to the set number where each card is split into. E.g. '1112222233333' means the first 3 cards (of DealtCards) are in the first set, the next 5 cards are in the second set and the last 5 cards are in the third set. """ date_gen = datetime.today().strftime('%Y-%m-%d') splits_table = GameC.CHINESE_POKER_db_consts['splits_table'] codes_table = GameC.CHINESE_POKER_db_consts['split_codes_table'] db_connector = DBF.connect_to_db() # First check that there are no existing splits in the DB. If there are, delete them. check_query = f"SELECT COUNT(*) FROM {splits_table} WHERE GameID={game_id} AND DateGenerated ='{date_gen}'" db_output, db_connector = DBF.select_query(check_query, db_connector) if db_output[0][0] > 0: delete_query = f"DELETE FROM {splits_table} WHERE GameID={game_id} AND DataGenerated='{date_gen}" db_connector, rows_deleted = DBF.delete_query( delete_query, db_connector) print( f'***Deleted {rows_deleted} rows with identical GameID ({game_id}) and DateGenerated ({date_gen}).***' ) for seat_ID in range(1, 5): player_splits_data = splits_data[f'P{seat_ID}'] #n_splits = len(player_splits_data['SplitIndsStrs'] for seqI, split_str in enumerate( player_splits_data['SplitIndsStrs']): splits_query = f'INSERT INTO {splits_table} (GameID, SeatID, SplitSeqNo, SplitStr, DateGenerated) VALUES (%s, %s, %s, %s, %s)' splits_query = splits_query % (game_id, seat_ID, seqI + 1, split_str, f"'{date_gen}'") db_connector, split_id = DBF.insert_query( splits_query, db_connector, False, True) base_codes_query = f'INSERT INTO {codes_table} ' + \ '(SplitID, SetNo, L1Code, L2Code, L3Code, L4Code, L5Code, L6Code) VALUES ' + \ '(%s, %s, %s, %s, %s, %s, %s, %s)' values_list = [] for setI, set_code in enumerate( player_splits_data['Codes'][seqI]): base_val = [None for i in range(8)] base_val[0] = split_id base_val[1] = setI + 1 for levelI, level_code in enumerate(set_code): base_val[2 + levelI] = level_code values_list.append(tuple(base_val)) db_connector = DBF.insert_many_query(base_codes_query, values_list, db_connector, True) db_connector = DBF.try_commit(db_connector) return def _convert_card_inds_to_set_inds_str(self, card_inds, n_cards=13): if not n_cards: n_cards = sum([len(card_set) for card_set in card_inds]) char_list = ['' for i in range(n_cards)] for set_i, card_set_inds in enumerate(card_inds): for ind in card_set_inds: char_list[ind] = str(set_i + 1) set_inds_str = ''.join(char_list) return set_inds_str def _convert_split_str_to_split_cards( self, cards, split_str, ): card_set_inds = [int(c) - 1 for c in list(split_str)] n_sets = max(card_set_inds) + 1 card_sets = [[] for _ in range(n_sets)] for cI, card in enumerate(cards): card_sets[card_set_inds[cI]].append(card) card_sets = [tuple(card_set) for card_set in card_sets] return card_sets def yield_splits_data_from_db( self, start_game_id=None, end_game_id=None, ): #db_connector = DBF.connect_to_db() splits_table = GameC.CHINESE_POKER_db_consts['splits_table'] codes_table = GameC.CHINESE_POKER_db_consts['split_codes_table'] base_query = f'SELECT SplitSeqNo, SplitStr, + ' \ f'c1.L1Code AS S1L1Code, c1.L2Code AS S1L2Code, c1.L3Code AS S1L3Code, c1.L4Code AS S1L4Code, c1.L5Code AS S1L5Code, c1.L6Code AS S1L6Code, ' + \ f'c2.L1Code AS S2L1Code, c2.L2Code AS S2L2Code, c2.L3Code AS S2L3Code, c2.L4Code AS S2L4Code, c2.L5Code AS S2L5Code, c2.L6Code AS S2L6Code, ' + \ f'c3.L1Code AS S3L1Code, c3.L2Code AS S3L2Code, c3.L3Code AS S3L3Code, c3.L4Code AS S3L4Code, c3.L5Code AS S3L5Code, c3.L6Code AS S3L6Code ' + \ f'FROM {splits_table} s ' + \ f'JOIN {codes_table} c1 ON s.SplitID=c1.SplitID ' + \ f'JOIN {codes_table} c2 ON s.SplitID=c2.SplitID ' + \ f'JOIN {codes_table} c3 ON s.SplitID=c3.SplitID ' + \ f'WHERE s.GameID=%s AND s.SeatID=%s ' + \ f'AND c1.SetNo=1 AND c2.SetNo=2 AND c3.SetNo=3' for game_id in range(start_game_id, end_game_id + 1): hands = next(self.yield_dealt_hands_from_db(game_id, game_id))[1] game_splits = [] for seat_id in range(1, 5): query = base_query % (game_id, seat_id) cards = hands[seat_id - 1] db_output, _ = DBF.select_query(query) hand_splits = [] for row in db_output: split_seq_no, split_str, s1c1, s1c2, s1c3, s1c4, s1c5, s1c6, s2c1, s2c2, s2c3, s2c4, s2c5, s2c6, s3c1, s3c2, s3c3, s3c4, s3c5, s3c6 = row split_cards = self._convert_split_str_to_split_cards( cards, split_str) s1code = [s1c1, s1c2, s1c3, s1c4, s1c5, s1c6] s2code = [s2c1, s2c2, s2c3, s2c4, s2c5, s2c6] s3code = [s3c1, s3c2, s3c3, s3c4, s3c5, s3c6] s1code = CardGroupCode( [code for code in s1code if code is not None]) s2code = CardGroupCode( [code for code in s2code if code is not None]) s3code = CardGroupCode( [code for code in s3code if code is not None]) split_info_factory = ChinesePokerStrategy.ranked_split_info_factory split_info = split_info_factory( None, split_cards, (s1code, s2code, s3code), None, None, None, None, None, split_seq_no, ) hand_splits.append(split_info) game_splits.append(hand_splits) yield game_id, game_splits # TODO Convert each row to RankedSplitInfo named tuple # (Inds, Cards, Codes, ) return @deprecated def yield_splits_data_from_json(self, json_file=None, start_deal_no=None, end_deal_no=None): """Generator that yields dictionary of splits data, one dealt hand at a time """ if json_file is None: json_file = GlobC.DATADIR / 'SplitsFromDealtHands' / 'splits_json_data_0_to_999.txt' p = re.compile('^Deal ([0-9]*?) (.*?)$') with open(json_file) as f: for line in f: deal_no = int(p.match(line).group(1)) if start_deal_no is not None and deal_no < start_deal_no: continue if end_deal_no is not None and deal_no > end_deal_no: break json_str = p.match(line).group(2) splits_data_dict = json.loads(json_str) yield deal_no, splits_data_dict yield None, None return """ def agg_splits_data_from_json_by_player( self, json_file=None, start_deal_no=None, end_deal_no=None, players=['P0','P1','P2','P3'] ): if json_file is None: json_file = GlobC.DATADIR / 'SplitsFromDealtHands' / 'splits_json_data_0_to_999.txt' if isinstance(players, str): players = [players,] player_splits_data = {player: [] for player in players} splits_data_gen = self.yield_splits_data_from_json(json_file, start_deal_no, end_deal_no) while 1: deal_no, splits_data = next(splits_data_gen) if deal_no is None: break for player in players: player_splits_data[player].append(splits_data[player]) return player_splits_data """ @classmethod def random_game_setup_from_db(cls): max_game_id = cls.max_game_id_in_splits_table() random_game_id = random.randint(1, max_game_id - 1) hand_no = random.randind(1, 4) game_setup = load_game_setup(random_game_id, hand_no) return random_game_id, hand_no, game_setup @classmethod def load_game_setups(cls, game_id, hand_no): dealt_hands_gen = yield_dealt_hands_from_db() return ########################################## ### START Useful query functions START ### ########################################## @classmethod def max_game_id_in_splits_table(cls): splits_table = GameC.CHINESE_POKER_db_consts['splits_table'] query = f'SELECT MAX(GameID) FROM {splits_table}' db_output, _ = DBF.select_query(query) return db_output[0][0] ###################################### ### END Useful query functions END ### ######################################
def random_hand(): deck = Deck() cards = [str(card) for card in deck.deal_cards()[0]] return cards
def compare_strategies_h2h_diff_hands( strats, # List of 2-4 strats n_games, hands_from_db=True, split_gen_strat=None ): all_best_splits = [] n_gen_splits_data = [] time_data = [] #all_comp_res = [] compare_timer_start = timer() n_strats = len(strats) if hands_from_db: max_game_id = Data.max_game_id_in_splits_table() game_ids = random.sample(range(1,max_game_id+1), n_games) data_obj = Data() else: deck = Deck() data_dict = { 'GameSeqNo':[], 'GameID':[], 'Strat':[], 'OppStrat':[], 'Hand':[], 'OppHand':[], 'BaseScore':[], 'BonusScore':[], 'TotScore':[], 'CompSet1':[], 'CompSet2':[], 'CompSet3':[], } for gI in range(n_games): print(f'Game {gI+1} of {n_games}:') hand_best_splits = [] hand_n_gen_splits = [] hand_times = [] # Load or gen all splits if hands_from_db is True: game_id = game_ids[gI] _, all_splits = next(data_obj.yield_splits_data_from_db(game_id, game_id)) #all_splits = all_splits[:n_strats] cards = [None for _ in range(4)] else: cards = deck.deal_cards() #[0:n_strats] if split_gen_strat is not None: all_splits = [] #for sI in range(n_strats): for hI, hand in enumerate(cards): all_splits.append(split_gen_strat.gen_all_splits(hand)[0]) hand_n_gen_splits.append(len(all_splits[-1])) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Generated {len(all_splits[-1])} feasible splits on hand {hI+1}. Cum. {min_elapsed} min elapsed.') else: all_splits = None game_strat_best_splits = [] for sI, strat in enumerate(strats): strat_best_splits = [] for hI in range(4): if hands_from_db or split_gen_strat is not None: strat_best_split, _, sec_elapsed = strat.pick_single_split(None, generated_splits=all_splits[hI]) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Picked best split on hand {hI+1} using strat {sI+1}. Cum. {min_elapsed} min elapsed.') else: strat_best_split, raw_splits_data, sec_elapsed = strat.pick_single_split(cards[hI]) hand_n_gen_splits.append(len(raw_splits_data)) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Generated {len(raw_splits_data)} splits and picked best using strat {sI+1} on hand {hI+1}. Cum. {min_elapsed} min elapsed.') hand_times.append(sec_elapsed) strat_best_splits.append(strat_best_split) game_strat_best_splits.append(strat_best_splits) h2h_matchups = list(permutations(range(4), 2)) for s1I in range(n_strats): for s2I in range(s1I+1, n_strats): for matchup in h2h_matchups: s1_split = game_strat_best_splits[s1I][matchup[0]] s2_split = game_strat_best_splits[s2I][matchup[1]] comp_res = _compare_codes(s1_split.Codes,s2_split.Codes) base_score = sum(comp_res) if abs(base_score) == 3: tot_score = base_score*2 bonus_score = base_score else: tot_score = base_score bonus_score = 0 data_dict['GameSeqNo'].append(gI+1) data_dict['GameSeqNo'].append(gI+1) if hands_from_db: data_dict['GameID'].append(game_id) data_dict['GameID'].append(game_id) else: data_dict['GameID'].append(np.nan) data_dict['GameID'].append(np.nan) data_dict['Strat'].append(s1I+1) data_dict['Strat'].append(s2I+1) data_dict['OppStrat'].append(s2I+1) data_dict['OppStrat'].append(s1I+1) data_dict['Hand'].append(matchup[0]+1) data_dict['Hand'].append(matchup[1]+1) data_dict['OppHand'].append(matchup[1]+1) data_dict['OppHand'].append(matchup[0]+1) data_dict['BaseScore'].append(base_score) data_dict['BaseScore'].append(-base_score) data_dict['BonusScore'].append(bonus_score) data_dict['BonusScore'].append(-bonus_score) data_dict['TotScore'].append(tot_score) data_dict['TotScore'].append(-tot_score) for sI in range(3): data_dict[f'CompSet{sI+1}'].append(comp_res[sI]) data_dict[f'CompSet{sI+1}'].append(-comp_res[sI]) """ strat_perms = list(permutations(range(n_strats))) base_scores = np.full((n_strats,n_strats,len(strat_perms)), np.nan) tot_scores = base_scores.copy() comp_res_det = np.full((n_strats,n_strats,len(strat_perms),3), np.nan) for permI, strat_perm in enumerate(strat_perms): # Pick best split for hI, stratI in enumerate(strat_perm): if hands_from_db or split_gen_strat is not None: strat_best_split, _, sec_elapsed = strats[stratI].pick_single_split(cards[hI], generated_splits=all_splits[hI]) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Picked best split on hand {hI+1} using strat {stratI+1}. Cum. {min_elapsed} min elapsed.') else: strat_best_split, raw_splits_data, sec_elapsed = strats[stratI].pick_single_split(cards[hI]) hand_n_gen_splits.append(len(raw_splits_data)) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Generated {len(raw_splits_data)} splits and picked best using strat {stratI+1} on hand {hI+1}. Cum. {min_elapsed} min elapsed.') hand_times.append(sec_elapsed) hand_best_splits.append(strat_best_split) # Compare best splits for s1I in range(n_strats): for s2I in range(s1I+1, n_strats): comp_res = _compare_codes(hand_best_splits[s1I].Codes,hand_best_splits[s2I].Codes) base_score = sum(comp_res) if abs(base_score) == 3: tot_score = base_score*2 else: tot_score = base_score base_scores[strat_perm[s1I], strat_perm[s2I], permI] = base_score base_scores[strat_perm[s2I], strat_perm[s1I], permI] = -base_score tot_scores[strat_perm[s1I], strat_perm[s2I], permI] = tot_score tot_scores[strat_perm[s2I], strat_perm[s1I], permI] = -tot_score comp_res_det[strat_perm[s1I], strat_perm[s2I], permI, :] = comp_res comp_res_det[strat_perm[s2I], strat_perm[s1I], permI, :] = -comp_res_det[strat_perm[s1I], strat_perm[s2I], permI, :] hand_comp_res = ( tot_scores, base_scores, comp_res_det, ) """ comp_data = pd.DataFrame(data_dict) #all_comp_res.append(hand_comp_res) all_best_splits.append(hand_best_splits) n_gen_splits_data.append(hand_n_gen_splits) time_data.append(hand_times) #if tot_score1 + tot_score2 != 0: # print('***Difference in outcome detected***') # print(f'S1H1vS2H2: {hand_best_splits[0].Codes} vs. {hand_best_splits[1].Codes}') # print(f'S1H2vS2H1: {hand_best_splits[2].Codes} vs. {hand_best_splits[3].Codes}') # print(hand_comp_res) return comp_data, all_best_splits, n_gen_splits_data, time_data ############################################# ### END Strategy comparison functions END ### #############################################
def compare_strategies_same_hand(strategy_list, n_hands, n_best_splits=1, include_split_gen=False, split_gen_strategy=None): all_best_splits = [] n_gen_splits_data = [] time_data = [] compare_timer_start = timer() for hI in range(n_hands): print(f'Hand {hI+1} of {n_hands}:') hand_best_splits = [] hand_n_gen_splits = [] hand_times = [] deck = Deck() cards = deck.deal_cards()[0] if include_split_gen is False: if split_gen_strategy is None: split_gen_strategy = ChinesePokerPctileScoreStrategy( pick_max_gen_splits=None, pick_max_elapsed_sec=None ) start = timer() all_splits = split_gen_strategy.gen_all_splits(cards, True)[0] hand_n_gen_splits = len(all_splits) hand_times.append(timer()-start) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->{len(all_splits)} feasible hands generated. Cum. {min_elapsed} min elapsed.') for sI, strategy in enumerate(strategy_list): strat_best_splits, _, sec_elapsed = strategy.pick_n_best_splits( None, n_best_splits, max_elapsed_sec=None, unique_code_levels=None, verbose=False, generated_splits=all_splits, ) hand_best_splits.append(strat_best_splits) hand_times.append(sec_elapsed) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Picked best split using strategy {sI+1}. Cum. {min_elapsed} min elapsed.') else: for sI, strategy in enumerate(strategy_list): strat_best_splits, raw_splits_data, sec_elapsed = strategy.pick_n_best_splits( cards, n_best_splits, ) hand_n_gen_splits.append(len(raw_splits_data)) hand_times.append(sec_elapsed) min_elapsed = (timer()-compare_timer_start)/60 print(f'-->Generated splits and picked best split using strategy {sI+1}. Cum. {min_elapsed} min elapsed.') all_best_splits.append(hand_best_splits) n_gen_splits_data.append(hand_n_gen_splits) time_data.append(hand_times) return all_best_splits, n_gen_splits_data, time_data
def repeated_games_with_hand( cards, n_games, strategies=None, test_n_best_splits=None, verbose=True, unique_code_levels=None, ): start = timer() deck = Deck() if strategies is None: strategy = ChinesePokerPctileScoreStrategy(split_gen_filter_by_score = True) strategies = [strategy for _ in range(4)] elif not isinstance(strategies, list): strategies = [strategies for _ in range(4)] if test_n_best_splits is None: test_n_best_splits = 1 cards = deck.deal_custom_hand(cards) if verbose: print(f'Cards: {cards}') best_splits_P0, _, _ = strategies[0].pick_n_best_splits(cards, test_n_best_splits, unique_code_levels=unique_code_levels) best_splits_P0_dict = { 'Cards': [flattened_list(split[1]) for split in best_splits_P0], 'Scores': [split[5] for split in best_splits_P0], 'Codes': [[set_code.code for set_code in split[2]] for split in best_splits_P0], } game_obj = ChinesePokerGame(strategies=strategies) for gI in range(n_games): hands = deck.deal_partially_custom_cards(cards) #other_player_best_splits = [] game_splits_data = {} for pI in range(1, 4): player_best_split, _, _ = strategies[pI].pick_single_split(hands[pI]) player_split_dict = { 'Cards': [flattened_list(player_best_split[1])], 'Scores': [player_best_split[5]], 'Codes': [[set_code.code for set_code in player_best_split[2]]], } game_splits_data[f'P{pI}'] = player_split_dict for splitI in range(len(best_splits_P0)): split_P0_dict = { 'Cards': [best_splits_P0_dict['Cards'][splitI]], 'Scores': [best_splits_P0_dict['Scores'][splitI]], 'Codes': [best_splits_P0_dict['Codes'][splitI]], } game_splits_data['P0'] = split_P0_dict game_obj.play_game(splits_data=game_splits_data) if verbose: min_elapsed = (timer()-start)/60 print(f'-->Completed game {gI+1}/{n_games}. Time elapsed={min_elapsed} min.') return game_obj.history, best_splits_P0_dict