def test_step(self): game = Game() state, _ = game.init_game() action = state['actions'][0] state, next_player_id = game.step(action) next_player = game.players[next_player_id] player_id = get_upstream_player_id(next_player, game.players) self.assertEqual(state['trace'][0][0], player_id) self.assertEqual(state['trace'][0][1], action)
def test_init_game(self): game = Game() state, current_player = game.init_game() total_cards = list(state['current_hand'] + state['others_hand']) total_cards.sort(key=functools.cmp_to_key(doudizhu_sort_str)) deck = list(game.round.deck_str) self.assertEqual(state['self'], current_player) self.assertIs(len(''.join(state['played_cards'])), 0) self.assertEqual(len(total_cards), 54) self.assertListEqual(total_cards, deck)
def test_proceed_game(self): game = Game() state, player_id = game.init_game() while not game.is_over(): action = state['actions'][0] state, next_player_id = game.step(action) player = game.players[player_id] self.assertEqual(get_downstream_player_id(player, game.players), next_player_id) player_id = next_player_id for player_id in range(3): state = game.get_state(player_id) self.assertIsNone(state['actions'])
def test_proceed_game(self): game = Game() state, player_id = game.init_game() while not game.is_over(): action = np.random.choice(list(state['actions'])) state, next_player_id = game.step(action) player = game.players[player_id] self.assertEqual((player.player_id + 1) % len(game.players), next_player_id) player_id = next_player_id for player_id in range(3): state = game.get_state(player_id) self.assertEqual(state['actions'], [])
def test_step_back(self): game = Game(allow_step_back=True) state, player_id = game.init_game() action = state['actions'][0] game.step(action) game.step_back() self.assertEqual(game.round.current_player, player_id) self.assertEqual(len(game.history), 0) self.assertEqual(game.step_back(), False)
def test_step_back(self): game = Game() state, player_id = game.init_game() action = state['actions'][0] game.step(action) game.step_back() self.assertEqual(game.current_player, player_id) self.assertEqual(len(game.histories), 0)
def test_get_player_num(self): game = Game() player_num = game.get_player_num() self.assertEqual(player_num, 3)
def test_get_player_id(self): game = Game() _, player_id = game.init_game() current_player_id = game.get_player_id() self.assertEqual(current_player_id, player_id)
def test_init_game(self): game = Game() state, current_player = game.init_game() self.assertEqual(state['self'], current_player) self.assertEqual(state['landlord'], current_player) self.assertIs(state['played_cards'], None)
def test_get_action_num(self): game = Game() action_num = game.get_action_num() self.assertEqual(action_num, 309)
def test_step_back(self): #case 1: action, stepback game = Game(allow_step_back=True) state, player_id = game.init_game() action = state['actions'][0] playable_cards = game.judger.playable_cards game.step(action) game.step_back() self.assertEqual(game.judger.playable_cards, playable_cards) self.assertEqual(game.round.greater_player, None) self.assertEqual(game.round.current_player, player_id) self.assertEqual(len(game.history), 0) game.state['actions'].sort() state['actions'].sort() self.assertEqual(game.state, state) self.assertEqual(game.step_back(), False) #case 2: action, pass, stepback game = Game(allow_step_back=True) state, player_id = game.init_game() action = state['actions'][0] game.step(action) actions = game.state['actions'] playable_cards = game.judger.playable_cards played_cards = game.players[game.round.current_player].played_cards game.step('pass') game.step_back() #judger.playable_cards should be the same self.assertEqual(game.judger.playable_cards, playable_cards) #players[current_player].played_cards should be the same self.assertEqual(game.players[game.round.current_player].played_cards, played_cards) #greater_player should be the same self.assertEqual(game.round.greater_player.player_id, 0) actions.sort() game.state['actions'].sort() #actions should be the same after step_back() self.assertEqual(game.state['actions'], actions) #case 3: action, pass, pass, action, stepback game = Game(allow_step_back=True) state, player_id = game.init_game() action = state['actions'][0] game.step(action) game.step('pass') game.step('pass') actions = game.state['actions'] playable_cards = game.judger.playable_cards played_cards = game.players[game.round.current_player].played_cards game.step(actions[0]) game.step_back() #judger.playable_cards should be the same self.assertEqual(game.judger.playable_cards, playable_cards) #players[current_player].played_cards should be the same self.assertEqual(game.players[game.round.current_player].played_cards, played_cards) #greater_player should be the same self.assertEqual(game.round.greater_player.player_id, 0) actions.sort() game.state['actions'].sort() #actions should be the same after step_back() self.assertEqual(game.state['actions'], actions) game.step_back() #greater_player should be the same self.assertEqual(game.round.greater_player.player_id, 0)
class DoudizhuEnv(Env): ''' Doudizhu Environment ''' def __init__(self, config): self.game = Game() super().__init__(config) self.state_shape = [6, 5, 15] def _extract_state(self, state): ''' Encode state Args: state (dict): dict of original state Returns: numpy array: 6*5*15 array 6 : current hand the union of the other two players' hand the recent three actions the union of all played cards ''' obs = np.zeros((6, 5, 15), dtype=int) for index in range(6): obs[index][0] = np.ones(15, dtype=int) encode_cards(obs[0], state['current_hand']) encode_cards(obs[1], state['others_hand']) for i, action in enumerate(state['trace'][-3:]): if action[1] != 'pass': encode_cards(obs[4 - i], action[1]) if state['played_cards'] is not None: encode_cards(obs[5], state['played_cards']) extracted_state = { 'obs': obs, 'legal_actions': self._get_legal_actions() } if self.allow_raw_data: extracted_state['raw_obs'] = state # TODO: state['actions'] can be None, may have bugs if state['actions'] == None: extracted_state['raw_legal_actions'] = [] else: extracted_state['raw_legal_actions'] = [ a for a in state['actions'] ] if self.record_action: extracted_state['action_record'] = self.action_recorder return extracted_state def get_payoffs(self): ''' Get the payoffs of players. Must be implemented in the child class. Returns: payoffs (list): a list of payoffs for each player ''' return self.game.judger.judge_payoffs(self.game.round.landlord_id, self.game.winner_id) def _decode_action(self, action_id): ''' Action id -> the action in the game. Must be implemented in the child class. Args: action_id (int): the id of the action Returns: action (string): the action that will be passed to the game engine. ''' abstract_action = ACTION_LIST[action_id] # without kicker if '*' not in abstract_action: return abstract_action # with kicker legal_actions = self.game.state['actions'] specific_actions = [] kickers = [] for legal_action in legal_actions: for abstract in SPECIFIC_MAP[legal_action]: main = abstract.strip('*') if abstract == abstract_action: specific_actions.append(legal_action) kickers.append(legal_action.replace(main, '', 1)) break # choose kicker with minimum score player_id = self.game.get_player_id() kicker_scores = [] for kicker in kickers: score = 0 for action in self.game.judger.playable_cards[player_id]: if kicker in action: score += 1 kicker_scores.append(score + CARD_RANK_STR.index(kicker[0])) min_index = 0 min_score = kicker_scores[0] for index, score in enumerate(kicker_scores): if score < min_score: min_score = score min_index = index return specific_actions[min_index] def _get_legal_actions(self): ''' Get all legal actions for current state Returns: legal_actions (list): a list of legal actions' id ''' legal_action_id = [] legal_actions = self.game.state['actions'] if legal_actions: for action in legal_actions: for abstract in SPECIFIC_MAP[action]: action_id = ACTION_SPACE[abstract] if action_id not in legal_action_id: legal_action_id.append(action_id) return legal_action_id
def __init__(self, config): self.game = Game() super().__init__(config) self.state_shape = [6, 5, 15]
def test_get_num_actions(self): game = Game() num_actions = game.get_num_actions() self.assertEqual(num_actions, 27472)
def test_get_num_players(self): game = Game() num_players = game.get_num_players() self.assertEqual(num_players, 3)