Beispiel #1
0
    def init_game(self):
        ''' Initialize players and state.

        Returns:
            dict: first state in one game
            int: current player's id
        '''
        # initialize public variables
        self.winner_id = None
        self.history = []

        # initialize players
        self.players = [Player(num) for num in range(self.num_players)]

        # initialize round to deal cards and determine landlord
        self.round = Round()
        self.round.initiate(self.players)

        # initialize judger
        self.judger = Judger(self.players)

        # get state of first player
        player_id = self.round.current_player
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        actions = list(self.judger.playable_cards[player_id])
        state = player.get_state(self.round.public, others_hands, actions)
        state['all_actions'] = state['actions']

        self.state = state

        return state, player_id
Beispiel #2
0
    def test_playable_cards_from_hand(self):
        # #solo
        # in_cards, not_in_cards, hand = ('3', '4', '5', '6', '8', '9', 'J', 'Q', 'B', 'R'), (), '334445555689JQBR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #pair
        # in_cards, not_in_cards, hand = ('33', '44', '55'), (), '334445555689JQBR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #trio
        # in_cards, not_in_cards, hand = ('444', '555'), (), '334445555689JQBR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #bomb
        # in_cards, not_in_cards, hand = ('5555', ), (), '334445555689JQBR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #rocket
        # in_cards, not_in_cards, hand = ('BR', ), (), '334445555689JQBR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #solo_chain_5 -- #solo_chain_12
        # in_cards = ('34567', '345678', '3456789', '3456789T', '3456789TJ',
        #     '3456789TJQ', '3456789TJQK', '3456789TJQKA', '45678', '456789',
        #     '3456789T', '3456789TJ', '456789TJQ', '456789TJQK', '456789TJQKA',
        #     '56789', '56789T', '56789TJ', '56789TJQ', '56789TJQK', '56789TJQKA',
        #     '6789T', '6789TJ', '6789TJQ', '6789TJQK', '6789TJQKA', '789TJ',
        #     '789TJQ', '789TJQK', '789TJQKA', '89TJQ', '89TJQK',
        #     '89TJQKA', '9TJQK', '9TJQKA', 'TJQKA')
        # not_in_cards = ('JQKA2', )
        # hand = '3344455556789TJQKA2BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #pair_chain_3 -- #pair_chain_10
        # in_cards = ('334455', '33445566', '3344556677', '334455667788', '33445566778899',
        # '33445566778899TT', '33445566778899TTJJ', '33445566778899TTJJQQ', '445566', '44556677',
        # '4455667788', '445566778899', '445566778899TT', '445566778899TTJJ', '445566778899TTJJQQ',
        # '445566778899TTJJQQKK', '556677', '55667788', '5566778899', '5566778899TT',
        # '5566778899TTJJ', '5566778899TTJJQQ', '5566778899TTJJQQKK', '5566778899TTJJQQKKAA',
        # '667788', '66778899', '66778899TT', '66778899TTJJ', '66778899TTJJQQ',
        # '66778899TTJJQQKK', '66778899TTJJQQKKAA', '778899', '778899TT', '778899TTJJ',
        # '778899TTJJQQ', '778899TTJJQQKK', '778899TTJJQQKKAA', '8899TT', '8899TTJJ',
        # '8899TTJJQQ', '8899TTJJQQKK', '8899TTJJQQKKAA', '99TTJJ', '99TTJJQQ',
        # '99TTJJQQKK', '99TTJJQQKKAA', 'TTJJQQ', 'TTJJQQKK', 'TTJJQQKKAA',
        # 'JJQQKK', 'JJQQKKAA', 'QQKKAA')
        # not_in_cards = ('33445566778899TTJJQQKK', 'KKAA22')
        # hand =  '33444555566778899TTJJQQKKAA22'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #trio_chain_2 -- #trio_chain_6
        # in_cards = ('333444', '333444555', '333444555666', '333444555666777', '333444555666777888',
        # '444555', '444555666', '444555666777', '444555666777888', '444555666777888999',
        # '555666', '555666777', '555666777888', '555666777888999', '555666777888999TTT',
        # '666777', '666777888', '666777888999', '666777888999TTT', '666777888999TTTJJJ',
        # '777888', '777888999', '777888999TTT', '777888999TTTJJJ', '777888999TTTJJJQQQ',
        # '888999', '888999TTT', '888999TTTJJJ', '888999TTTJJJQQQ', '888999TTTJJJQQQKKK',
        # '999TTT', '999TTTJJJ', '999TTTJJJQQQ', '999TTTJJJQQQKKK', '999TTTJJJQQQKKKAAA',
        # 'TTTJJJ', 'TTTJJJQQQ', 'TTTJJJQQQKKK', 'TTTJJJQQQKKKAAA',
        # 'JJJQQQ', 'JJJQQQKKK', 'JJJQQQKKKAAA',
        # 'QQQKKK', 'QQQKKKAAA',
        # 'KKKAAA')
        # not_in_cards = ('333444555666777888999', 'AAA222')
        # hand =  '333444455556667778889999TTTJJJQQQKKKAAA222BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #trio_solo, trio_pair
        # in_cards = ('3777', '4777', '5777', '6777', '7778',
        # '7772', '44777', '55777', '77788', '77722')
        # not_in_cards = ()
        # hand =  '344455677778889TJQKA2222BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #trio_solo_chain_2 -- trio_solo_chain_5
        # in_cards = ('34777888', '3777888T', '3456777888999TTTJJJQ', '66777888')
        # not_in_cards = ('37777888', '777888999TTTJJJQK2BR', '777888999TTTJJJJ')
        # hand =  '34556677778888999TTTTJJJJQQQQKA2BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #trio_pair_chain_2 -- #trio_pair_chain_4
        # in_cards = ('5566777888', '55777888TT')
        # not_in_cards = ('777888QQQQ', )
        # hand =  '34556677778888999TTTTJJJJQQQQKA2BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        # #four_two_solo, #four_two_pair
        # in_cards = ('357777', '557777', '567777', '777788', '55667777', '66777799', '557777TT', '55777788')
        # not_in_cards = ('77778888', )
        # hand =  '34556677778888999TTTTJJJJQQQQKA2BR'
        # playable_cards = Judger.playable_cards_from_hand(hand)
        # for e in in_cards:
        #     self.assertIn(e, playable_cards)
        # for e in not_in_cards:
        #     self.assertNotIn(e, playable_cards)

        playable_cards = list(
            Judger.playable_cards_from_hand(
                '3333444455556666777788889999TTTTJJJJQQQQKKKKAAAA2222BR'))
        all_cards_list = CARD_TYPE[1]
        for c in playable_cards:
            # if (c not in all_cards_list):
            #     print(c)
            self.assertIn(c, all_cards_list)
        for c in all_cards_list:
            # if (c not in playable_cards):
            #     print('\t' + c)
            self.assertIn(c, playable_cards)
        self.assertEqual(len(playable_cards), len(all_cards_list))
Beispiel #3
0
class DoudizhuGame(object):
    ''' Provide game APIs for env to run doudizhu and get corresponding state
    information.

    An example of state during runtime:
            {
             'deck': '3333444455556666777788889999TTTTJJJJQQQQKKKKAAAA2222BR',
             'seen_cards': 'TQA',
             'landlord': 0,
             'self': 2,
             'initial_hand': '3456677799TJQKAAB',
             'trace': [(0, '8222'), (1, 'pass'), (2, 'pass'), (0, '6KKK'),
                       (1, 'pass'), (2, 'pass'), (0, '8'), (1, 'Q')],
             'played_cards': ['6', '8', '8', 'Q', 'K', 'K', 'K', '2', '2', '2'],
             'others_hand': '333444555678899TTTJJJQQAA2R',
             'current_hand': '3456677799TJQKAAB',
             'actions': ['pass', 'K', 'A', 'B']
            }
    '''
    def __init__(self, allow_step_back=False):
        self.allow_step_back = allow_step_back
        self.num_players = 3

    def init_game(self):
        ''' Initialize players and state.

        Returns:
            dict: first state in one game
            int: current player's id
        '''
        # initialize public variables
        self.winner_id = None
        self.history = []

        # initialize players
        self.players = [Player(num) for num in range(self.num_players)]

        # initialize round to deal cards and determine landlord
        self.round = Round()
        self.round.initiate(self.players)

        # initialize judger
        self.judger = Judger(self.players)

        # get state of first player
        player_id = self.round.current_player
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        actions = list(self.judger.playable_cards[player_id])
        state = player.get_state(self.round.public, others_hands, actions)
        state['all_actions'] = state['actions']

        self.state = state

        return state, player_id

    def step(self, action):
        ''' Perform one draw of the game

        Args:
            action (str): specific action of doudizhu. Eg: '33344'

        Returns:
            dict: next player's state
            int: next player's id
        '''
        if self.allow_step_back:
            # TODO: don't record game.round, game.players, game.judger if allow_step_back not set
            pass

        # perfrom action
        player = self.players[self.round.current_player]
        self.round.proceed_round(player, action)
        if (action != 'pass'):
            self.judger.calc_playable_cards(player)
        if self.judger.judge_game(self.players, self.round.current_player):
            self.winner_id = self.round.current_player
        next_id = get_downstream_player_id(player, self.players)
        self.round.current_player = next_id

        # get next state
        state = self.get_state(next_id)
        self.state = state

        #print("doudizhu状态:",state)

        return state, next_id

    def step_back(self):
        ''' Return to the previous state of the game

        Returns:
            (bool): True if the game steps back successfully
        '''
        if not self.round.trace:
            return False

        #winner_id will be always None no matter step_back from any case
        self.winner_id = None

        #reverse round
        player_id, cards = self.round.trace.pop()
        self.round.current_player = player_id
        if (cards != 'pass'):
            for card in cards:
                self.round.played_cards.remove(card)
        greater_player_id = self.round.find_last_greater_player_id_in_trace()
        if (greater_player_id is not None):
            self.round.greater_player = self.players[greater_player_id]
        else:
            self.round.greater_player = None

        #reverse player
        if (cards != 'pass'):
            self.players[
                player_id].played_cards = self.round.find_last_played_cards_in_trace(
                    player_id)
        self.players[player_id].play_back()

        #reverse judger.played_cards if needed
        if (cards != 'pass'):
            self.judger.restore_playable_cards(player_id)

        self.state = self.get_state(self.round.current_player)
        return True

    def get_state(self, player_id):
        ''' Return player's state

        Args:
            player_id (int): player id

        Returns:
            (dict): The state of the player
        '''
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        if self.is_over():
            actions = None
            all_actions = None
        else:
            actions, all_actions = player.available_actions(
                self.round.greater_player, self.judger)
            actions = list(actions)
            all_actions = list(all_actions)

        state = player.get_state(self.round.public, others_hands, actions)
        state['all_actions'] = all_actions
        return state

    @staticmethod
    def get_action_num():
        ''' Return the total number of abstract acitons

        Returns:
            int: the total number of abstract actions of doudizhu
        '''
        return 309

    def get_player_id(self):
        ''' Return current player's id

        Returns:
            int: current player's id
        '''
        return self.round.current_player

    def get_player_num(self):
        ''' Return the number of players in doudizhu

        Returns:
            int: the number of players in doudizhu
        '''
        return self.num_players

    def is_over(self):
        ''' Judge whether a game is over

        Returns:
            Bool: True(over) / False(not over)
        '''
        if self.winner_id is None:
            return False
        return True

    def _get_others_current_hand(self, player):
        player_up = self.players[get_upstream_player_id(player, self.players)]
        player_down = self.players[get_downstream_player_id(
            player, self.players)]
        others_hand = merge(player_up.current_hand,
                            player_down.current_hand,
                            key=functools.cmp_to_key(doudizhu_sort_card))
        return cards2str(others_hand)
Beispiel #4
0
 def test_judge_payoffs(self):
     payoffs = Judger.judge_payoffs(0, 0)
     self.assertEqual(payoffs[0], 1)
     payoffs = Judger.judge_payoffs(2, 0)
     self.assertEqual(payoffs[0], 1)
     self.assertEqual(payoffs[1], 1)
Beispiel #5
0
class DoudizhuGame(object):
    ''' Provide game APIs for env to run doudizhu and get corresponding state
    information.

    An example of state during runtime:
            {
             'deck': '3333444455556666777788889999TTTTJJJJQQQQKKKKAAAA2222BR',
             'seen_cards': 'TQA',
             'landlord': 0,
             'self': 2,
             'initial_hand': '3456677799TJQKAAB',
             'trace': [(0, '8222'), (1, 'pass'), (2, 'pass'), (0, '6KKK'),
                       (1, 'pass'), (2, 'pass'), (0, '8'), (1, 'Q')],
             'played_cards': ['6', '8', '8', 'Q', 'K', 'K', 'K', '2', '2', '2'],
             'others_hand': '333444555678899TTTJJJQQAA2R',
             'current_hand': '3456677799TJQKAAB',
             'actions': ['pass', 'K', 'A', 'B']
            }
    '''

    def __init__(self, allow_step_back=False):
        self.allow_step_back = allow_step_back
        self.num_players = 3

    def init_game(self):
        ''' Initialize players and state.

        Returns:
            dict: first state in one game
            int: current player's id
        '''
        # initialize public variables
        self.winner_id = None
        self.history = []

        # initialize players
        self.players = [Player(num)
                        for num in range(self.num_players)]

        # initialize round to deal cards and determine landlord
        self.round = Round()
        self.round.initiate(self.players)

        # initialize judger
        self.judger = Judger(self.players)

        # get state of first player
        player_id = self.round.current_player
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        actions = list(self.judger.playable_cards[player_id])
        state = player.get_state(self.round.public, others_hands, actions)
        self.state = state

        return state, player_id

    def step(self, action):
        ''' Perform one draw of the game

        Args:
            action (str): specific action of doudizhu. Eg: '33344'

        Returns:
            dict: next player's state
            int: next player's id
        '''
        if self.allow_step_back:
            # record game history
            self._record_history()

        # perfrom action
        player = self.players[self.round.current_player]
        self.round.proceed_round(player, action)
        if self.judger.judge_game(self.players, self.round.current_player):
            self.winner_id = self.round.current_player
        next_id = get_downstream_player_id(player, self.players)
        self.round.current_player = next_id

        # get next state
        state = self.get_state(next_id)
        self.state = state

        return state, next_id

    def step_back(self):
        ''' Return to the previous state of the game

        Returns:
            (bool): True if the game steps back successfully
        '''
        if not self.history:
            return False
        self.winner_id, self.players, self.round, self.judger = self.history.pop()
        return True

    def get_state(self, player_id):
        ''' Return player's state

        Args:
            player_id (int): player id

        Returns:
            (dict): The state of the player
        '''
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        if self.is_over():
            actions = None
        else:
            actions = player.available_actions(self.round.greater_player, self.judger)
        state = player.get_state(self.round.public, others_hands, actions)

        return state

    @staticmethod
    def get_action_num():
        ''' Return the total number of abstract acitons

        Returns:
            int: the total number of abstract actions of doudizhu
        '''
        return 309

    def get_player_id(self):
        ''' Return current player's id

        Returns:
            int: current player's id
        '''
        return self.round.current_player

    def get_player_num(self):
        ''' Return the number of players in doudizhu

        Returns:
            int: the number of players in doudizhu
        '''
        return self.num_players

    def is_over(self):
        ''' Judge whether a game is over

        Returns:
            Bool: True(over) / False(not over)
        '''
        if self.winner_id is None:
            return False
        return True

    def _record_history(self):
        ''' Record history
        '''
        winner_id_cp = copy.deepcopy(self.winner_id)
        players_cp = copy.deepcopy(self.players)
        round_cp = copy.deepcopy(self.round)
        judger_cp = copy.deepcopy(self.judger)
        self.history.append((winner_id_cp, players_cp, round_cp, judger_cp))

    def _get_others_current_hand(self, player):
        player_up = self.players[get_upstream_player_id(player, self.players)]
        player_down = self.players[get_downstream_player_id(
            player, self.players)]
        others_hand = (player_up.current_hand + player_down.current_hand)
        others_hand.sort(key=functools.cmp_to_key(doudizhu_sort_card))
        return cards2str(others_hand)
Beispiel #6
0
class SimpleDoudizhuGame(object):
    ''' Provide game APIs for env to run simple doudizhu and get corresponding state
    information.

    An example of state during runtime:
    '''
    def __init__(self, allow_step_back=False):
        self.allow_step_back = allow_step_back
        self.num_players = 3

    def init_game(self):
        ''' Initialize players and state.

        Returns:
            dict: first state in one game
            int: current player's id
        '''
        # initialize public variables
        self.winner_id = None
        self.history = []

        # initialize players
        self.players = [Player(num) for num in range(self.num_players)]

        # initialize round to deal cards and determine landlord
        self.round = Round()
        self.round.initiate(self.players)

        # initialize judger
        self.judger = Judger(self.players)

        # get state of first player
        player_id = self.round.current_player
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        actions = list(self.judger.playable_cards[player_id])
        state = player.get_state(self.round.public, others_hands, actions)
        self.state = state

        return state, player_id

    def step(self, action):
        ''' Perform one draw of the game

        Args:
            action (str): specific action of doudizhu. Eg: '33344'

        Returns:
            dict: next player's state
            int: next player's id
        '''
        if self.allow_step_back:
            # TODO: don't record game.round, game.players, game.judger if allow_step_back not set
            pass

        # perfrom action
        player = self.players[self.round.current_player]
        self.round.proceed_round(player, action)
        if (action != 'pass'):
            self.judger.calc_playable_cards(player)
        if self.judger.judge_game(self.players, self.round.current_player):
            self.winner_id = self.round.current_player
        next_id = get_downstream_player_id(player, self.players)
        self.round.current_player = next_id

        # get next state
        state = self.get_state(next_id)
        self.state = state

        return state, next_id

    def step_back(self):
        ''' Return to the previous state of the game

        Returns:
            (bool): True if the game steps back successfully
        '''
        if not self.round.trace:
            return False

        #winner_id will be always None no matter step_back from any case
        self.winner_id = None

        #reverse round
        player_id, cards = self.round.step_back(self.players)

        #reverse player
        if (cards != 'pass'):
            self.players[
                player_id].played_cards = self.round.find_last_played_cards_in_trace(
                    player_id)
        self.players[player_id].play_back()

        #reverse judger.played_cards if needed
        if (cards != 'pass'):
            self.judger.restore_playable_cards(player_id)

        self.state = self.get_state(self.round.current_player)
        return True

    def get_state(self, player_id):
        ''' Return player's state

        Args:
            player_id (int): player id

        Returns:
            (dict): The state of the player
        '''
        player = self.players[player_id]
        others_hands = self._get_others_current_hand(player)
        if self.is_over():
            actions = None
        else:
            actions = list(
                player.available_actions(self.round.greater_player,
                                         self.judger))
        state = player.get_state(self.round.public, others_hands, actions)

        return state

    @staticmethod
    def get_action_num():
        ''' Return the total number of abstract acitons

        Returns:
            int: the total number of abstract actions of doudizhu
        '''
        return 131

    def get_player_id(self):
        ''' Return current player's id

        Returns:
            int: current player's id
        '''
        return self.round.current_player

    def get_player_num(self):
        ''' Return the number of players in doudizhu

        Returns:
            int: the number of players in doudizhu
        '''
        return self.num_players

    def is_over(self):
        ''' Judge whether a game is over

        Returns:
            Bool: True(over) / False(not over)
        '''
        if self.winner_id is None:
            return False
        return True

    def _get_others_current_hand(self, player):
        player_up = self.players[get_upstream_player_id(player, self.players)]
        player_down = self.players[get_downstream_player_id(
            player, self.players)]
        others_hand = merge(player_up.current_hand,
                            player_down.current_hand,
                            key=functools.cmp_to_key(doudizhu_sort_card))
        return cards2str(others_hand)