def __lastplay(self, data): self.stat['hand'] = [Card(x) for x in data['self']['cards']] round_cards = self.stat['roundCard'] my_hand_cards = self.stat['hand'] my_avail_cards = [Card(x) for x in data['self']['candidateCards']] lead_card = round_cards[0] my_lead_suit_num = self.htapi.calc_card_num_by_suit( my_hand_cards, lead_card.get_suit()) score_card_num = self.htapi.find_cards(round_cards, self.score_cards) if my_lead_suit_num > 0: """ Have the same suit. If there's no point on board, shoot the biggest card. If there's a point, try to avoid. """ if score_card_num == 0: return self.htapi.pick_big_card(my_avail_cards) else: return self.htapi.pick_smaller_card(my_avail_cards, round_cards, auto_choose_big=True) else: """ Don't have the same suit. Play the trick. """ return self.__midplay(data)
def _recalculate_round_score(self, ptup): """ Calculate player's score in current round. """ score = 0 picked_cards = ptup['pick'] my_score_cards = self.htapi.find_cards(picked_cards, self.game_score_cards) my_heart_cards = self.htapi.find_cards(picked_cards, self.game_heart_cards) my_penalty_cards = self.htapi.find_cards(picked_cards, self.game_penalty_cards) if self.db['expose'] == True: score = len(my_heart_cards) * 2 * (-1) else: score = len(my_heart_cards) * (-1) if self.htapi.find_card(my_score_cards, Card('QS')) != None: score += -13 if self.htapi.find_card(my_score_cards, Card('TC')) != None: score *= 2 if len(self.htapi.find_cards(my_score_cards, my_penalty_cards)) == len(self.game_penalty_cards): # Shoot the moon. Score becomes postive! Score x 4! score *= -1 score *= 4 ptup['shoot_moon'] = True ptup['score'] = score
def pick_card(self, data): """ Event: My turn to shoot a card. """ self.stat['hand'] = [Card(x) for x in data['self']['cards']] self.stat['hand'] = self.htapi.arrange_cards(self.stat['hand']) self.stat['avail'] = self.htapi.arrange_cards( [Card(x) for x in data['self']['candidateCards']]) self.stat['roundPlayers'] = data['roundPlayers'][:] # Get players in next turn. round_players = self.stat['roundPlayers'] my_pos = round_players.index(self.get_name()) self.stat['nextPlayers'] = data['roundPlayers'][(my_pos + 1):] if self._pick_card_should_i_sm(data) == True: self.htapi.dbg("sm mode") card2shoot = self._pick_card_sm_mode(data) else: self.htapi.dbg("as mode") card2shoot = self._pick_card_as_mode(data) self.htapi.dbg(self.get_name() + " shoot card: " + format(card2shoot) + ", from: " + format(data['self']['cards']) + ", next players: " + format(self.stat['nextPlayers'])) return card2shoot.toString()
def expose_my_cards(self, data): """ Event: The server asks me to expose AH... """ my_hand_cards = self.stat['hand'] output = [] candidates = data['cards'] if candidates == None or len(candidates) == 0: return output candidates = [Card(x) for x in candidates] if self.htapi.find_card(candidates, Card('AH')) == None: return output if my_hand_cards == None or len(my_hand_cards) == 0: return output # Calculate the rate that I will get penalty... # The simplest calculation is to check if I have too many big-rank cards big_card_num = self.htapi.find_cards(my_hand_cards, self.big_rank_cards) if big_card_num > (len(self.big_rank_cards) / 3): # Too many big-rank cards...Give up expose. return output output = ['AH'] return output
def game_new_deal_manual_deliver(self): """ Deliever fixed 13 cards to each player. ['7C', '2C', '2D', 'JS', 'QD', '4C', 'QC', 'QS', '3C', 'TD', '2H', '7D', 'KS', '8C', 'JD', '6D', '3D', 'KC', 'AS', '9D', '8S', 'AD', 'TS', '7H', '5D', '4H', '8H', '3H', 'AC', '8D', 'KH', 'KD', '4S', '9C', '2S', '4D', 'JH', '5C', 'JC', 'AH', '9H', 'TH', '9S', '6S', '6H', '7S', 'QH', 'TC', '3S', '6C', '5H', '5S'] """ card2deliver = [ ['8C', 'JD', '6D', '3D', 'KC', 'AS', '9D', '8S', 'AH', 'TS', 'JH', '5D', 'QH'], ['7C', '2C', '2D', 'JS', 'QD', '4C', 'QC', 'QS', '3C', 'TD', '2H', '7D', 'KS'], ['8H', '3H', 'AC', '8D', 'AD', 'KD', '4S', '9C', '2S', '4D', '7H', '5C', 'JC'], ['KH', '9H', 'TH', '9S', '6S', '6H', '7S', '4H', 'TC', '3S', '6C', '5H', '5S'] ] # Avoid stupid assignment error. Check if there're 52 different cards tgt = [] card52 = self.htapi.get52cards() for card13 in card2deliver: card13 = [Card(x) for x in card13] tgt += card13 if len(self.htapi.find_cards(tgt, card52)) != 52: self.htapi.errmsg("Invalid card2deliver table.") for ptup in self.player_tups: if ptup['id'] >= 4: self.htapi.errmsg("Cannot allow player id >= 4") # Assume player id is from 0 ~ 3, so assign the cards directly. ptup['hand'] = [Card(x) for x in card2deliver[ptup['id']]] ptup['hand_origin'] = [Card(x) for x in card2deliver[ptup['id']]]
def __leadplay(self, data): """ I am the round leader. I want to avoid tacking the trick, so choose the best! """ self.stat['hand'] = [Card(x) for x in data['self']['cards']] my_hand_cards = self.stat['hand'] my_avail_cards = [Card(x) for x in data['self']['candidateCards']] opponent_cards = self._get_unused_cards_by_suits(my_hand_cards) selected = [] peak_percentage = 0 for c in my_avail_cards: # If I pick this card, will I take the trick? percentage = self._monte_carlo_predict(c, opponent_cards, round_cards=[]) if len(selected) == 0: peak_percentage = percentage selected = [c] elif percentage < peak_percentage: peak_percentage = percentage selected = [c] elif percentage == peak_percentage: selected.append(c) # Prefer a lower number suit all_suit = [] for c in selected: card_suit = c.get_suit() if all_suit.count(card_suit) == 0: all_suit.append(card_suit) self.htapi.dbg("Selected candidates: " + format(selected) + ", the suits: " + format(all_suit) + ", all cards: " + format(my_hand_cards)) prefer_suit = None min_suit_num = 0 for suit in all_suit: same_suit_num = self.htapi.get_cards_by_suit(my_hand_cards, suit) if prefer_suit == None: prefer_suit = suit min_suit_num = same_suit_num elif same_suit_num < min_suit_num: prefer_suit = suit min_suit_num = same_suit_num prefer_cards = self.htapi.arrange_cards( self.htapi.get_cards_by_suit(selected, prefer_suit)) self.htapi.dbg("Selected candidates: " + format(prefer_cards)) card2shoot = prefer_cards.pop() self.htapi.dbg("Select card" + format(card2shoot)) return card2shoot
def __midplay(self, data): round_cards = self.stat['roundCard'] my_hand_cards = self.stat['hand'] my_avail_cards = [Card(x) for x in data['self']['candidateCards']] lead_card = round_cards[0] my_lead_suit_num = self.htapi.calc_card_num_by_suit( my_hand_cards, lead_card.get_suit()) if my_lead_suit_num > 0: """ Have the same suit. Choose a smaller card to avoid the trick. """ filtered_round_cards = self.htapi.get_cards_by_suit( round_cards, lead_card.get_suit()) card2shoot = self.htapi.pick_smaller_card(my_avail_cards, filtered_round_cards, auto_choose_big=False) if card2shoot != None: return card2shoot else: # Do not have smaller card. Try a bigger one, but not biggest. return self.htapi.pick_bigger_card(my_avail_cards, filtered_round_cards) else: """ I don't have the same suit. Git rid of 'QS'. """ cardqs = self.htapi.find_card(my_avail_cards, Card('QS')) if cardqs != None: return cardqs """ I don't have the same suit. Throw dangerous high rank cards. """ high_card = self.htapi.pick_big_card(my_avail_cards) if high_card.get_rank_num() >= Card('JS').get_rank_num(): return high_card """ I don't have the same suit. My chance to throw out point cards! """ candidate_list = [] candidate_list += self.htapi.find_cards(my_avail_cards, [Card('TC')]) candidate_list += self.htapi.get_cards_by_suit(my_avail_cards, 'H') if len(candidate_list) > 0: return candidate_list.pop(0) """ Otherwise, pick the highest rank card. """ return high_card
def _ev_pick_card(self, ptup): """ Event: pick_card - Ask the player to shoot a card. """ # round cards round_cards = self.db['roundCards'] # Candidate cards candidates = self._get_candidates(ptup) candidates = self.htapi.arrange_cards(candidates) candidates = self.htapi.clone_cards(candidates) # Round players round_players = [] for ptup_this in self.player_tups: rp = {} rp = ptup_this['name'] round_players.append(rp) data = {'self': { 'cards': [x.toString() for x in ptup['hand']], 'candidateCards': [x.toString() for x in candidates], 'gameNumber': self.db['gameNumber'], 'dealNumber': self.db['dealNumber'], 'roundCard': '' }, 'roundPlayers': round_players } pbot = ptup['bot'] card2shoot = pbot.pick_card(data) card2shoot = Card(card2shoot) return card2shoot
def _ev_expose_ah_end(self, ptup): """ Inform the player the expose result. """ data = {'players': []} data_players = data['players'] for ptup_this in self.player_tups: data_this = {} data_this['playerNumber'] = ptup_this['id'] data_this['playerName'] = ptup_this['name'] if ptup_this['expose'] == True: data_this['exposedCards'] = [Card('AH').toString()] else: data_this['exposedCards'] = [] data_players.append(data_this) if ptup_this['name'] == ptup['name']: # Add a 'self'! another_data_this = dict(data_this) another_data_this['playerName'] = 'self' data['self'] = another_data_this pbot = ptup['bot'] pbot.expose_cards_end(data)
def _ev_pass3cards(self, ptup): """ Output: picked 3 cards """ data = {} data['self'] = { 'cards': self.htapi.clone_cards([x.toString() for x in ptup['hand']]) } pbot = ptup['bot'] picked = pbot.pass_cards(data) if picked == None or len(picked) != 3: self.htapi.errmsg("Invalid picked num of bot: " + ptup['name']) # Convert ['XX', 'OO', 'AA'] into Card list picked = [Card(c) for c in picked] # Verify if there's any duplicated picked card to avoid buggy bot. for c in picked: if picked.count(c) != 1: self.errmsg("Player: " + ptup['name'] + " tries to pick invalid cards: " + format(picked)) # Check picked cards are really in list to keep away from stupid bot. found_cards = self.htapi.find_cards(ptup['hand'], picked) if found_cards == None or len(found_cards) != 3: self.htapi.errmsg("Player: " + ptup['name'] + " attemps to pick invalid cards") return picked
def expose_my_cards(self, data): """ Event: The server asks me to expose AH... """ output = [] candidates = data['cards'] if candidates == None or len(candidates) == 0: return output candidates = [Card(x) for x in candidates] if self.htapi.find_card(candidates, Card('AH')) == None: return output output = ['AH'] return output
def unitest(): htapi = Htapi() allcards = htapi.get52cards() random.shuffle(allcards) print (format(allcards)) print (format(htapi.get_cards_by_suit(allcards, 'S'))) print (format(htapi.find_card(allcards, Card('2H'))))
def _select_card2pass(self, my_hand_cards): """ Pop out 1 card to pass. Anti-score mode. - Remove big rank card from shortage suit - Remove big rank card in long suit """ card_num_stat_sorted = self._calc_hand_cards_num(my_hand_cards) # card_num_stat_sorted_dict = dict(card_num_stat_sorted) if self.htapi.find_card(my_hand_cards, Card('QS')) == None: card = self.htapi.remove_card(my_hand_cards, Card('AS')) if card != None: return card # Spade in shortage. KS and AS will be dangerous. card = self.htapi.remove_card(my_hand_cards, Card('KS')) if card != None: return card # Remove big rank card from shortage suit for di in card_num_stat_sorted: suit, num = di if num == 0: continue same_suit_cards = self.htapi.get_cards_by_suit(my_hand_cards, suit) big_card = self.htapi.pick_big_card(same_suit_cards) if big_card.get_rank_num() > Card('8S').get_rank_num(): return self.htapi.remove_card(my_hand_cards, big_card) # Remove suit for di in card_num_stat_sorted: suit, num = di if num == 0: continue same_suit_cards = self.htapi.get_cards_by_suit(my_hand_cards, suit) big_card = self.htapi.pick_big_card(same_suit_cards) return self.htapi.remove_card(my_hand_cards, big_card) self.htapi.errmsg("BUG")
def expose_my_cards(self, yourcards): expose_card = [] for card in self.my_hand_cards: if card == Card("AH"): expose_card.append(card.toString()) message = "Expose Cards:{}".format(expose_card) system_log.show_message(message) system_log.save_logs(message) return expose_card
def _select_card2pass_shoot_moon_mode(self, my_hand_cards): """ Pop out 1 card to pass The rule here is to pick the small cards in shortage """ # # Find the non-empty suit but the card num is low. # # TODO: Try to remove non-heart suit can help shoot-moon ability. # card_num_stat = {'S': 0, 'H': 0, 'D': 0, 'C': 0} for c in my_hand_cards: card_num_stat[c.get_suit()] += 1 card_num_stat_sorted = sorted(card_num_stat.iteritems(), key=lambda (k, v): (v, k)) # # Try to remove a suit # for di in card_num_stat_sorted: k, v = di if v != 0: pick_suit, v = di tgt_cards = self.htapi.get_cards_by_suit( my_hand_cards, pick_suit) tgt_cards = self.htapi.arrange_cards(tgt_cards) smaller_card = self.htapi.pick_smaller_card( tgt_cards, [Card('9S')]) if smaller_card != None: return self.htapi.remove_card(my_hand_cards, smaller_card) # # In case... # for di in card_num_stat_sorted: k, v = di if v != 0: pick_suit, v = di tgt_cards = self.htapi.get_cards_by_suit( my_hand_cards, pick_suit) tgt_cards = self.htapi.arrange_cards(tgt_cards) card = tgt_cards[0] return self.htapi.remove_card(my_hand_cards, card) self.htapi.errmsg("BUG") card = my_hand_cards[0] return self.htapi.remove_card(my_hand_cards, card)
def expose_my_cards(self, data): """ Event: The server asks me to expose AH... """ my_hand_cards = self.stat['hand'] output = [] candidates = data['cards'] if candidates == None or len(candidates) == 0: return output candidates = [Card(x) for x in candidates] if self.htapi.find_card(candidates, Card('AH')) == None: return output if my_hand_cards == None or len(my_hand_cards) == 0: return output # # TODO: Be smarter... calculate shoot-moon ability, or anti-score ability # If I know I won't take any score, expose AH! # If I want to shoot the moon, expose AH! # # Calculate the rate that I will get penalty... # The simplest calculation is to check if I have too many big-rank cards my_big_cards = self.htapi.find_cards(my_hand_cards, self.big_rank_cards) my_big_card_num = len(my_big_cards) if my_big_card_num > 3 and my_big_card_num <= 5: """ Have some but not many high-rank. """ return output # # Expose AH! # output = ['AH'] return output
def game_decide_lead_player(self): """ Decide who must start the deal, i.e. the player has 2C. """ for i in range(0, 4): ptup = self.player_tups[0] card2c = self.htapi.find_card(ptup['hand'], Card('2C')) if card2c != None: break else: self.player_tups_rotate(1)
def pass_cards(self, data): cards = data['self']['cards'] self.my_hand_cards = [] for card_str in cards: card = Card(card_str) self.my_hand_cards.append(card) pass_cards = [self.my_hand_cards[0], self.my_hand_cards[1], self.my_hand_cards[2]] # count = 0 # for i in range(len(self.my_hand_cards)): # card = self.my_hand_cards[len(self.my_hand_cards) - (i + 1)] # if card == Card("QS"): # pass_cards.append(card) # count += 1 # elif card == Card("TC"): # pass_cards.append(card) # count += 1 # for i in range(len(self.my_hand_cards)): # card = self.my_hand_cards[len(self.my_hand_cards) - (i + 1)] # if card.suit_index == 2: # pass_cards.append(card) # count += 1 # if count == 3: # break # if count < 3: # for i in range(len(self.my_hand_cards)): # card = self.my_hand_cards[len(self.my_hand_cards) - (i + 1)] # if card not in self.game_score_cards: # pass_cards.append(card) # count += 1 # if count == 3: # break return_values = [] for card in pass_cards: return_values.append(card.toString()) message = "Pass Cards:{}".format(return_values) system_log.show_message(message) system_log.save_logs(message) self.my_pass_card = return_values return return_values
def _select_card2pass_sm_mode(self, my_hand_cards): """ Pop out 1 card to pass Reserve cards in long suit. Remove small cards in shortage suit. """ card_num_stat_sorted = self._calc_hand_cards_num(my_hand_cards) # Remove small cards in shortage suit. for di in card_num_stat_sorted: suit, num = di if num == 0: continue if suit == 'H': continue same_suit_cards = self.htapi.get_cards_by_suit(my_hand_cards, suit) smaller_card = self.htapi.pick_smaller_card(same_suit_cards, [Card('9S')], auto_choose_big=False) if smaller_card != None: return self.htapi.remove_card(my_hand_cards, smaller_card) # Remove suit for di in card_num_stat_sorted: suit, num = di if num == 0: continue if suit == 'H': continue same_suit_cards = self.htapi.get_cards_by_suit(my_hand_cards, suit) small_card = self.htapi.pick_small_card(same_suit_cards) return self.htapi.remove_card(my_hand_cards, small_card) # Remove suit, in case I have 13 hearts... A.A for di in card_num_stat_sorted: suit, num = di if num == 0: continue same_suit_cards = self.htapi.get_cards_by_suit(my_hand_cards, suit) small_card = self.htapi.pick_small_card(same_suit_cards) return self.htapi.remove_card(my_hand_cards, small_card) self.htapi.errmsg("BUG")
def pick_card(self, data): """ Event: My turn to shoot a card. """ # roundPlayers is in the correct order of shooting cards. round_players = data['roundPlayers'] # Identify my position in this round my_pos = round_players.index(self.get_name()) # Get players in next turn. self.stat['nextPlayers'] = data['roundPlayers'][(my_pos + 1):] self.stat['hand'] = [Card(x) for x in data['self']['cards']] my_hand_cards = self.stat['hand'] my_avail_cards = [Card(x) for x in data['self']['candidateCards']] my_avail_cards = self.htapi.shuffle_cards(my_avail_cards) card2shoot = my_avail_cards[0] return card2shoot.toString()
def pass_cards(self, data): self.stat['hand'] = [Card(x) for x in data['self']['cards']] self.stat['hand'] = self.htapi.arrange_cards(self.stat['hand']) self.htapi.dbg("Select 3 cards from: " + format(self.stat['hand'])) sm_ability = self._calc_shoot_moon_ability(data) if sm_ability > self.SM_THOLD_PASS3: self.htapi.dbg("shoot moon mode pass3: " + str(sm_ability)) return self._pass_cards_shoot_moon_mode(data) else: self.htapi.dbg("anti score mode pass3") return self._pass_cards_anti_score_mode(data)
def _do_i_have_too_many_low_rank_cards(self): my_hand_cards = self.stat['hand'] low_rank_card_num = 0 for c in my_hand_cards: if c.get_rank_num() < Card("TS").get_rank_num: low_rank_card_num += 1 # TBD if low_rank_card_num >= 9: return True else: return False
def _select_card2pass(self, my_hand_cards): """ Pop out 1 card to pass """ card = self.htapi.remove_card(my_hand_cards, Card('KS')) if card != None: return card card = self.htapi.remove_card(my_hand_cards, Card('AS')) if card != None: return card # Found the suit in shortage suit_list = ['S', 'H', 'D', 'C'] pick_suit = None pick_suit_num = 0 for suit in suit_list: this_suit_num = self.htapi.calc_card_num_by_suit( my_hand_cards, suit) if this_suit_num == 0: continue if pick_suit_num == 0: pick_suit_num = this_suit_num pick_suit = suit elif this_suit_num < pick_suit_num: pick_suit_num = this_suit_num pick_suit = suit # Remove the most large card in the target suit candidate_list = self.htapi.get_cards_by_suit(my_hand_cards, pick_suit) candidate_list = self.htapi.arrange_cards(candidate_list) card = candidate_list.pop() return self.htapi.remove_card(my_hand_cards, card)
def expose_my_cards(self, data): """ Event: The server asks me to expose AH... """ output = [] candidates = data['cards'] if candidates == None or len(candidates) == 0: return output candidates = [Card(x) for x in candidates] if self.htapi.find_card(candidates, Card('AH')) == None: return output if self.stat['pass3_sm_ability'] > self.SM_THOLD_PASS3: output = ['AH'] return output if self.stat['pass3_as_ability'] > self.AS_THOLD_PASS3: # I have confidence not taking score... output = ['AH'] return output return output
def game_expose_ah(self): for ptup in self.player_tups: hand_cards = ptup['hand'] card_ah = self.htapi.find_card(hand_cards, Card('AH')) if card_ah != None: if self._ev_expose_ah(ptup): # The player decides to expose, all heart score will double ptup['expose'] = True self.db['expose'] = True break # Inform players expose end. for ptup in self.player_tups: self._ev_expose_ah_end(ptup)
def pass_cards(self, data): """ Event: Pick 3 cards to pass to others """ self.stat['hand'] = [Card(x) for x in data['self']['cards']] my_hand_cards = self.stat['hand'] output = [] for i in range(3): card = self._select_card2pass(my_hand_cards) if card == None: self.htapi.errmsg("Cannot pick a card to pass") output.append(card.toString()) self.htapi.dbg(self.get_name() + " Pass 3 cards: " + format(output)) return output
def pass_cards(self, data): """ Event: Pick 3 cards to pass to others """ self.stat['hand'] = [Card(x) for x in data['self']['cards']] my_hand_cards = self.stat['hand'] output = [] my_hand_cards = self.htapi.shuffle_cards(my_hand_cards) output.append(my_hand_cards.pop(0)) output.append(my_hand_cards.pop(0)) output.append(my_hand_cards.pop(0)) output = [x.toString() for x in output] self.htapi.dbg(self.get_name() + " Pass 3 cards: " + format(output)) return output
def pick_card(self, data): """ Event: My turn to shoot a card. """ self.stat['hand'] = [Card(x) for x in data['self']['cards']] if self._calc_shoot_moon_ability(data) >= self.SM_THOLD_PICK: self.htapi.dbg("shoot moon mode") card = self.pick_card_shoot_moon_mode(data) else: self.htapi.dbg("aniti-score mode") card = self.pick_card_anti_score_mode(data) # NOTE: Do not remove the card in hand card, do it ad turn end event. self.htapi.dbg(self.get_name() + " shoot card: " + format(card) + ", from: " + format(data['self']['cards']) + ", next players: " + format(self.stat['nextPlayers'])) return card.toString()
def turn_end(self, data): """ Event: turn end """ data_turn_player = data['turnPlayer'] data_turn_card = data['turnCard'] data_turn_card = Card(data_turn_card) if data_turn_player != self.get_name(): self.htapi.dbg(data_turn_player + " shoot card: " + format(data_turn_card)) local_player = self.players[data_turn_player] local_player['shoot'].append(data_turn_card) self.stat['roundCard'].append(data_turn_card) self.stat['usedCard'].append(data_turn_card) self._detect_card_shortage(local_player, data_turn_card)
def _get_candidates(self, ptup): """ Help players to find candidate cards. """ if self.db['is_first_play'] == True: self.db['is_first_play'] = False candidates = [Card('2C')] return candidates player_pos = self._get_player_pos(ptup) if player_pos == 1: if self.db['heartBreak'] == True: # Can select any card after heart break. candidates = ptup['hand'] return candidates else: # Not heart break. Cannot pick heart unless there's no other suit. candidates = self.htapi.get_cards_by_suits(ptup['hand'], ['S', 'D', 'C']) if len(candidates) == 0: # Only heart suit left. Allow heart break, of course. candidates = ptup['hand'] return candidates else: # Follow the leading card unless there's no the same suit. round_cards = self.db['roundCards'] lead_card = round_cards[0] candidates = self.htapi.get_cards_by_suit(ptup['hand'], lead_card.get_suit()) if len(candidates) > 0: return candidates else: # No card in the same suit. Can pick any card. candidates = ptup['hand'] return candidates self.errmsg("Cannot get candidate cards") return None