Пример #1
0
class PseudoHeart(Htapi):
    """
    Create a virtual game which can play faster!
    """
    game_score_cards = [Card("QS"), Card("TC"),
                        Card("2H"), Card("3H"), Card("4H"), Card("5H"), Card("6H"), 
                        Card("7H"), Card("8H"), Card("9H"), Card("TH"), Card("JH"), 
                        Card("QH"), Card("KH"), Card("AH")]
    
    # If have all penalty cards, the player shoots the moon and win a lot.
    game_penalty_cards = [Card("QS"),
                        Card("2H"), Card("3H"), Card("4H"), Card("5H"), Card("6H"), 
                        Card("7H"), Card("8H"), Card("9H"), Card("TH"), Card("JH"), 
                        Card("QH"), Card("KH"), Card("AH")]
    
    def __init__(self, player_bots):
        if len(player_bots) != 4:
            print ("Invalid player num != 4")
            sys.exit()
    
        self.db = {}  
        self.htapi = Htapi(is_debug=True)
        self.game_heart_cards = self.htapi.get_cards_by_suit(self.htapi.get52cards(), 'H')
        
        # Save bot object into self.player_bots 
        self.player_tups = []
        id = 0
        for p in player_bots:
            player_tup = {
                # Constant data
                'bot': p, 'name': p.get_name(), 'id': id,
                # Deal data
                'hand_origin': [], 'recv3': [], 'pass3': [],
                'hand': [], 'pick': [], 'round_pick': [], 'shoot': [], 'expose': False, 'score': 0, 'shoot_moon': False,
                # Game data 
                'score_game': 0,
                # MISC data 
                'score_accl': 0, 'shoot_moon_accl': 0, 'score_negative_accl': 0,
                'winner': [0, 0, 0, 0],
                            }
            self.player_tups.append(player_tup)
            self.htapi.msg("Add new player: " + player_tup['name'])
            id += 1
        
        self.db['dealNumber'] = 0
        self.db['gameNumber'] = 0
        
    def player_tups_rotate(self, shift=1):
        """
        Shift order of the players.
        """
        for i in range(shift):
            p = self.player_tups.pop(0)
            self.player_tups.append(p)
        
    def game_next_deal(self):
        self.db['dealNumber'] += 1
        self.db['heartBreak'] = False
        self.db['expose'] = False
        self.db['unusedCards'] = self.htapi.get52cards()
        self.db['usedCards'] = []
        
        self.db['roundNumber'] = 0
        self.db['is_first_play'] = True
        
        for ptup in self.player_tups:
            ptup['pick'] = []
            
            ptup['recv3'] = []
            ptup['pass3'] = []
            ptup['hand_origin'] = []
            ptup['hand'] = []
            
            ptup['shoot'] = []
            ptup['score'] = 0
            ptup['shoot_moon'] = False
            
        # Re-arrange position to default layout
        for i in range(0, 4):
            ctup = self.player_tups[0]
            if ctup['id'] == 0:
                break
            else:
                self.player_tups_rotate(1)
        
    def game_next_round(self):
        self.db['roundNumber'] += 1
        self.db['roundCards'] = []
        
        for ptup in self.player_tups:
            ptup['round_pick'] = []
            
    def _ev_new_game(self, ptup):
        """
        Event: new game
        """
        players = []
        for ptup_this in self.player_tups:
            pdata = {
                'playerName': ptup_this['name'],
                'playerNumber': ptup_this['id'],
                'status': 0 
                     }
            players.append(pdata)            
        
        data = {
            'players': players
            }
        
        pbot = ptup['bot']
        pbot.new_game(data)

    def _ev_receive_cards(self, ptup):
            """
            Event: receive_cards
            
            data = {"players": [{"playerName": "hac", "cards": ["3S", "8S", "9S", "TS", "JS", "4H", "6H", "9H", "3D", "7D", "9D", "JD", "8C"], "dealNumber": 1, "gameNumber": 1}]}
            """
            data = {
                    'players': [
                        {
                            'playerName': ptup['name'],
                            'cards': self.htapi.clone_cards([x.toString() for x in ptup['hand']]),
                            
                            'gameNumber': self.db['gameNumber'],
                            'dealNumber': self.db['dealNumber'],
                        },
                        {
                            'playerName': 'self',
                            'cards': self.htapi.clone_cards([x.toString() for x in ptup['hand']]),
                            
                            'gameNumber': self.db['gameNumber'],
                            'dealNumber': self.db['dealNumber'],
                        },
                        # TBD: Add other players' data? Not necessary, I guess.
                    ]
                }

            # Call player method.            
            pbot = ptup['bot']
            pbot.receive_cards(data)
    
    def _ev_deal_end(self, ptup):
        """
        End of a deal
        """
        data = {}
        data['dealNumber'] = self.db['dealNumber']
        data['roundNumber'] = self.db['roundNumber']
        data['gameNumber'] = self.db['gameNumber']
        
        data['players'] = []
        data_players = data['players']
        
        for ptup_this in self.player_tups:
            # Setup this player data. 
            pld = {}
            
            pld['playerNumber'] = ptup_this['id']
            pld['playerName'] = ptup_this['name']
            pld['dealScore'] = ptup_this['score']
            pld['gameScore'] = ptup_this['score_game']
            
            pld['scoreCards'] = self.htapi.clone_cards([x.toString() for x in ptup_this['pick']])
            pld['initialCards'] = self.htapi.clone_cards([x.toString() for x in ptup_this['hand_origin']]) 
            pld['receivedCards'] = self.htapi.clone_cards([x.toString() for x in ptup_this['recv3']])
            pld['pickedCards'] = self.htapi.clone_cards([x.toString() for x in ptup_this['pass3']])
            pld['shootingTheMoon'] = ptup_this['shoot_moon']
            
            # Add data into list
            data_players.append(pld)
        
        pbot = ptup['bot']
        pbot.deal_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 _ev_receive_opponent_cards(self, ptup, picked, received):
        """
        Pass 3 cards to the player
        """
        data = {
                'players': [
                    {
                        'playerName': ptup['name'],
                        'cards': self.htapi.clone_cards([x.toString() for x in ptup['hand']]),
                        'pickedCards': self.htapi.clone_cards([x.toString() for x in picked]),
                        'receivedCards': self.htapi.clone_cards([x.toString() for x in received]),
                        
                        'gameNumber': self.db['gameNumber'],
                        'dealNumber': self.db['dealNumber'],
                    },
                    {
                        'playerName': 'self',
                        'cards': self.htapi.clone_cards([x.toString() for x in ptup['hand']]),
                        'pickedCards': self.htapi.clone_cards([x.toString() for x in picked]),
                        'receivedCards': self.htapi.clone_cards([x.toString() for x in received]),
                        
                        'gameNumber': self.db['gameNumber'],
                        'dealNumber': self.db['dealNumber'],
                    },
                    # TBD: Add other players' data? Not necessary, I guess.
                ]
            }
        
        pbot = ptup['bot']
        pbot.receive_opponent_cards(data)
        
    def _ev_expose_ah(self, ptup):
        """
        Ask the player if he wants to expose AH.
        """
        data = {
            'dealNumber': self.db['dealNumber'],
            'cards': ['AH'] 
            }
                                      
        pbot = ptup['bot']
        card = pbot.expose_my_cards(data)
        if card == None:
            # The player rejects to expose AH
            return False
        
        return True
    
    def _ev_turn_end(self, ptup, turn_ptup, card2shoot):
        data_players = []
        
        data_player = {}
        data_player['playerName'] = turn_ptup['name']
        data_player['cards'] = self.htapi.clone_cards([card2shoot.toString()]) 
        
        data_players.append(data_player)

        data = {
            'turnCard': card2shoot.toString(),
            'turnPlayer': turn_ptup['name'],
            'players': data_players,
            'serverRandom': str(False)
            }
        
        pbot = ptup['bot']
        pbot.turn_end(data)

    def _ev_round_end(self, ptup, next_lead_ptup):
        """
        Inform the user the end of a round
        """
        data = {'roundPlayers': [], 'roundPlayer': next_lead_ptup['name'], 'players': []}
        
        data_round_players = data['roundPlayers']
        for ptup_this in self.player_tups:
            data_round_players.append(ptup_this['name'])
        
        data_players = data['players']    
        for ptup_this in self.player_tups:
            dp = {}
            
            dp['playerNumber'] = ptup_this['id']
            dp['playerName'] = ptup_this['name']
            dp['gameScore'] = ptup_this['score_game']
            dp['dealScore'] = ptup_this['score']
            dp['shootingTheMoon'] = ptup_this['shoot_moon']
            dp['roundCard'] = ptup_this['shoot'][-1].toString()
            
            data_players.append(dp)
        
        pbot = ptup['bot']
        pbot.round_end(data)  
        
    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_game_end(self, ptup):
        """
        Inform the player the game result.
        """
        data = {'players': []}
        data_players = data['players']
        
        for ptup_this in self.player_tups:
            data_this = {}
            
            data_this['playerName'] = ptup_this['name']
            data_this['gameScore'] = ptup_this['score_accl']
                
            data_players.append(data_this)
            
        pbot = ptup['bot']
        pbot.game_over(data)
        
    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 game_new_deal_random_deliver(self):   
        unused_card = self.htapi.get52cards()
        unused_card = self.htapi.shuffle_cards(unused_card)
        
        if len(self.player_tups) != 4:
            self.htapi.errmsg("Invalid player bot num")
        
        # Save 13 cards
        for ptup in self.player_tups:
            picked = []
            for i in range(13):
                picked.append(unused_card.pop())
            
            # The player get 13 cards. Generate event: 'receive_cards'
            picked = self.htapi.arrange_cards(picked)
            ptup['hand'] = picked
            ptup['hand_origin'] = self.htapi.clone_cards(picked)

    def game_new_deal(self):
        """
        Deliver 13 cards to each player
        """             
        manual_deliver = False
        if manual_deliver == True:
            self.htapi.msg(" *** WARNING: You are running in manual-deliver mode")
            self.game_new_deal_manual_deliver()
        else:
            self.game_new_deal_random_deliver()

        # Inform every player            
        for ptup in self.player_tups:
            self._ev_receive_cards(ptup)
        
    def game_pass3cards(self):
        """
        Each player has to pick 3 cards and pass to one opponent.
        """
        
        picked = {}
        for ptup in self.player_tups:
            picked[ptup['name']] = self._ev_pass3cards(ptup)
            
            # Remove the picked 3 cards!
            removed = self.htapi.remove_cards(ptup['hand'], picked[ptup['name']])
            if len(removed) != 3:
                self.htapi.errmsg("Cannot pop picked 3 cards of user: "******"""
        Get position of a player. (position=1 ~ 4)
        
        position = 1 means he is the lead playerr.
        """
        position = 1
        for p in self.player_tups:
            if p['name'] == ptup['name']:
                return position
            
            position += 1
            
        self.errmsg("Cannot find player position")
        return None
            
    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
    
    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 game_shoot1card(self, ptup):
        """
        Make the player shoot 1 card!
        """

        card2shoot = self._ev_pick_card(ptup)
        if self.htapi.find_card(ptup['hand'], card2shoot) == None:
            self.errmsg("Cannot shoot un-existed card at player: " + ptup['name'])
            
        # Shoot the card.
        removed = self.htapi.remove_card(ptup['hand'], card2shoot)
        if removed == None:
            self.errmsg("(BUG) Cannot remove player card: " + card2shoot.toString() + ", " + ptup['name']) 
        
        ptup['shoot'].append(card2shoot)
           
        self.db['roundCards'].append(card2shoot)
        self.db['usedCards'].append(card2shoot)
        self.db['unusedCards'].remove(card2shoot)

        if card2shoot.get_suit() == 'H':
            self.db['heartBreak'] = True
            
        for ptup_this in self.player_tups:
            self._ev_turn_end(ptup_this, ptup, card2shoot)
            
    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 game_round_end(self, round_num):
        """
        Decide round player, round player = the player "win" the round.
        """
        round_cards = self.db['roundCards']
        if len(round_cards) != 4:
            self.htapi.errmsg("Invalid cards of this round.")

        lead_card = round_cards[0]
        lead_ptup = self.player_tups[0]
        
        lead_card_suit = lead_card.get_suit_num()
        lead_card_rank = lead_card.get_rank_num()

        idx = 0
        rotate = 0
        next_lead_ptup = lead_ptup
        highest_rank = lead_card_rank
        for ptup in self.player_tups:
            if idx == 0:
                # This is lead player. Skip
                idx += 1
                continue         
            
            shoot_card = round_cards[idx]
            shoot_card_suit = shoot_card.get_suit_num()
            shoot_card_rank = shoot_card.get_rank_num()
            
            if shoot_card_suit == lead_card_suit:
                if shoot_card_rank > highest_rank:
                    next_lead_ptup = ptup
                    rotate = idx
                    highest_rank = shoot_card_rank
                    
            idx += 1
        
        # The cards belong to the next lead player. Give him the cards.
        next_lead_ptup['pick'] += round_cards
        next_lead_ptup['round_pick'] = round_cards
        
        """
        Calculate scores of this round and store the result.
        """
        for ptup in self.player_tups:
            self._recalculate_round_score(ptup)
             
        
        """
        Inform the user an event
        """
        for ptup in self.player_tups:
            self._ev_round_end(ptup, next_lead_ptup)
        
        """
        Rotate ptup position for next round.
        """
        if rotate > 0:
            self.player_tups_rotate(rotate)
            
    def show_score(self):
        for ptup in self.player_tups:
            self.htapi.dbg(
                "Player: " + ptup['name'] + 
                ", score: " + str(ptup['score']) + 
                ", score_accl: " + str(ptup['score_accl']) +
                ", score_negative_accl:" + str(ptup['score_negative_accl']) + 
                ", shoot_moon_accl: " + str(ptup['shoot_moon_accl']) +
                ", winner: " + str(ptup['winner'])
                )
       
    def game_round(self, round_num):
        """
        Play 1 round = 4 turn
        """
        self.htapi.msg("Round: " + str(self.db['roundNumber']) + 
                       ", Deal: " + str(self.db['dealNumber']) + 
                       ", Game: " + str(self.db['gameNumber']))
        
        for ptup in self.player_tups:
            self.game_shoot1card(ptup)
            
        self.game_round_end(round_num)

    def game_finish_deal(self):
        """
        The end of a single deal.
        """
        score_list = []
        for ptup in self.player_tups:
             
            if ptup['score'] < 0:
                ptup['score_negative_accl'] += ptup['score']
                
            ptup['score_accl'] += ptup['score']
            ptup['score_game'] += ptup['score']
            if ptup['shoot_moon'] == True:
                ptup['shoot_moon_accl'] += 1
            
            score_list.append({'name': ptup['name'], 'score': ptup['score'], 'ptup': ptup})
        
        score_list_sorted = sorted(score_list, key=lambda v: v['score'])

        winner = score_list_sorted[3]['ptup']
        winner['winner'][0] += 1 # winner
        winner = score_list_sorted[2]['ptup']
        winner['winner'][1] += 1 # 2nd winner
        winner = score_list_sorted[1]['ptup']
        winner['winner'][2] += 1 # 3rd...
        winner = score_list_sorted[0]['ptup']
        winner['winner'][3] += 1 # loser...
            
        # Inform players
        for ptup in self.player_tups:
            self._ev_deal_end(ptup)
    
    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 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 game_play1deal(self):
        """
        event: new_deal
        """
        self.game_new_deal()
        
        """
        event: receive_opponent_cards & pass_cards
        """
        self.game_pass3cards()
        
        self.game_decide_lead_player()
        
        """
        event: Ask if the player wants to expose AH
        """
        self.game_expose_ah()
        
        """
        event: your_turn & turn_end & expose_cards & expose_cards_end && round_end
        """
        for round in range(1, 14):
            # Round 1 to 13
            self.game_next_round()
            self.game_round(round)
            
        self.game_finish_deal()
        
    def game_next_game(self):
        self.db['gameNumber'] += 1
        self.db['dealNumber'] = 0
                
        for ptup in self.player_tups:
            # Reset game-specific data
            ptup['score_game'] = 0
            
    def game_over(self):
        """
        playerName, gameScore
        """
        for ptup in self.player_tups:
            self._ev_game_end(ptup)
            
    def game_single(self):
        """
        There're 16 deals in a game
        """
        self.game_next_game()
        
        # Inform the players there's a new game to start.
        for ptup in self.player_tups:
            self._ev_new_game(ptup)
        
        DEAL_PER_GAME = 16
        for deal in range(1, DEAL_PER_GAME + 1):
            self.game_next_deal()
            self.game_play1deal()
            
        self.game_over()
        
        self.show_score()

        random.shuffle(self.player_tups)

    def game_loop(self, loop_max=1):
        for loop in range(1, loop_max + 1):
            self.game_single()
Пример #2
0
class RandomBot(PokerBot, Htapi):
    """
    Random bot. Life is luck. Life is random. Life is life.
    """
    def __init__(self, name, is_debug=False):
        super(RandomBot, self).__init__(name)

        self.htapi = Htapi(is_debug=is_debug)

        self.stat = {}

    def new_game(self, data):
        """
        Event: The start of a new game.
        """
        pass

    def receive_cards(self, data):
        """
        Event: Receive my 13 cards.
        """
        self.stat['hand'] = self.get_cards(data)

    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 receive_opponent_cards(self, data):
        """
        Event: Recv 3 cards from one opponent
        """
        pass

    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 expose_cards_end(self, data):
        """
        Event: Check if somebody expose AH. Damn. 
        """
        pass

    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 turn_end(self, data):
        """
        Event: turn end
        """
        pass

    def pick_history(self, data, is_timeout, pick_his):
        """
        Event: turn end
        """
        self.turn_end(data)

    def round_end(self, data):
        """
        Event: round end
        """
        pass

    def deal_end(self, data):
        """
        Event: deal end
        """
        pass

    def game_over(self, data):
        """
        Event: game end
        """
        pass