def test_proceed_game(self): game = Game() game.init_game() while not game.is_over(): legal_actions = game.judge.get_legal_actions() action = np.random.choice(legal_actions) _, _ = game.step(action) self.assertEqual(game.actions[-1].action_id, score_player_1_action_id)
def can_gin(game: GinRummyGame) -> bool: result = False last_action = game.get_last_action() last_action_type = type(last_action) if last_action_type is DrawCardAction or last_action_type is PickUpDiscardAction: current_player = game.get_current_player() hand = current_player.hand going_out_deadwood_count = game.settings.going_out_deadwood_count meld_clusters = melding.get_meld_clusters(hand=hand, going_out_deadwood_count=going_out_deadwood_count, is_going_out=True) if meld_clusters: deadwood_counts = [utils.get_deadwood_count(hand, meld_cluster) for meld_cluster in meld_clusters] result = min(deadwood_counts) == 0 return result
def test_init_game(self): game = Game() state, current_player = game.init_game() opponent_player = (current_player + 1) % 2 self.assertEqual(len(game.round.move_sheet), 1) self.assertIn(current_player, [0, 1]) self.assertIn(game.round.dealer_id, [0, 1]) self.assertEqual(len(game.actions), 0) self.assertEqual(opponent_player, game.round.dealer_id) # opponent_player is dealer self.assertEqual(len(game.round.players[opponent_player].hand), 10) # dealer has 10 cards self.assertEqual(len(game.round.players[current_player].hand), 11) # current_player has 11 cards self.assertEqual(len(game.round.dealer.shuffled_deck), 52) self.assertEqual(len(game.round.dealer.stock_pile), 31) self.assertEqual(state['player_id'], current_player) self.assertEqual(len(state['hand']), 11)
def get_knock_cards(game: GinRummyGame) -> List[Card]: """ :param game: GinRummyGame :return: list[Card] of cards that player can knock with """ knock_cards = set() last_action = game.get_last_action() last_action_type = type(last_action) if last_action_type is DrawCardAction or last_action_type is PickUpDiscardAction: current_player = game.get_current_player() hand = current_player.hand going_out_deadwood_count = game.settings.going_out_deadwood_count meld_clusters = melding.get_meld_clusters(hand=hand, going_out_deadwood_count=going_out_deadwood_count, is_going_out=True) deadwood_cluster = [utils.get_deadwood(hand, meld_cluster) for meld_cluster in meld_clusters] for deadwood in deadwood_cluster: for card in deadwood: knock_cards.add(card) return list(knock_cards)
def test_step(self): game = Game() _, current_player = game.init_game() opponent_player = (current_player + 1) % 2 action = np.random.choice(game.judge.get_legal_actions()) self.assertIn(action.action_id, put_action_ids) # should be a put action _, next_player = game.step(action) if not game.is_over(): self.assertEqual(next_player, opponent_player) if not game.is_over(): action = np.random.choice(game.judge.get_legal_actions()) self.assertIn(action.action_id, get_action_ids) # should be a get action _, next_player = game.step(action) self.assertEqual(next_player, opponent_player) # keep turn to put card
def __init__(self, config): self.game = Game() super().__init__(config=config) self.state_shape = [5, 52] self.judge = GinRummyJudge(game=self.game) self.scorer = scorers.GinRummyScorer()
class GinRummyEnv(Env): ''' GinRummy Environment ''' def __init__(self, config): self.game = Game() super().__init__(config=config) self.state_shape = [5, 52] self.judge = GinRummyJudge(game=self.game) self.scorer = scorers.GinRummyScorer() def _extract_state(self, state): # 200213 don't use state ??? ''' Encode state Args: state (dict): dict of original state Returns: numpy array: 5 * 52 array 5 : current hand (1 if card in hand else 0) top_discard (1 if card is top discard else 0) dead_cards (1 for discards except for top_discard else 0) opponent known cards (likewise) unknown cards (likewise) # is this needed ??? 200213 ''' if self.game.is_over(): obs = np.array([utils.encode_cards([]) for _ in range(5)]) extracted_state = {'obs': obs, 'legal_actions': self._get_legal_actions()} else: discard_pile = self.game.round.dealer.discard_pile stock_pile = self.game.round.dealer.stock_pile top_discard = [] if not discard_pile else [discard_pile[-1]] dead_cards = discard_pile[:-1] current_player = self.game.get_current_player() opponent = self.game.round.players[(current_player.player_id + 1) % 2] known_cards = opponent.known_cards unknown_cards = stock_pile + [card for card in opponent.hand if card not in known_cards] hand_rep = utils.encode_cards(current_player.hand) top_discard_rep = utils.encode_cards(top_discard) dead_cards_rep = utils.encode_cards(dead_cards) known_cards_rep = utils.encode_cards(known_cards) unknown_cards_rep = utils.encode_cards(unknown_cards) rep = [hand_rep, top_discard_rep, dead_cards_rep, known_cards_rep, unknown_cards_rep] obs = np.array(rep) extracted_state = {'obs': obs, 'legal_actions': self._get_legal_actions()} 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 ''' payoffs = self.scorer.get_payoffs(game=self.game) return payoffs def _decode_action(self, action_id) -> ActionEvent: # FIXME 200213 should return str ''' 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 (ActionEvent): the action that will be passed to the game engine. ''' return self.game.decode_action(action_id=action_id) def _get_legal_actions(self): ''' Get all legal actions for current state Returns: legal_actions (list): a list of legal actions' id ''' legal_actions = self.judge.get_legal_actions() legal_actions_ids = [action_event.action_id for action_event in legal_actions] return legal_actions_ids def _load_model(self): ''' Load pretrained/rule model Returns: model (Model): A Model object ''' assert False # FIXME: stub return models.load('uno-rule-v1') # FIXME: stub def set_scorer(self, printing_configuration: bool = False, get_payoff: Callable[[GinRummyPlayer, Game], int or float] = None): if self.game.settings.scorer_name == "GinRummyScorer": self.scorer = scorers.GinRummyScorer(get_payoff=get_payoff) elif self.game.settings.scorer_name == "HighLowScorer": self.scorer = scorers.HighLowScorer(get_payoff=get_payoff) else: raise Exception("GinRummyEnv: cannot determine scorer.") if printing_configuration: print("") print("========== Scorer ==========") print("Scorer is", self.scorer.name)
def test_get_state(self): game = Game() state, _ = game.init_game() self.assertEqual(len(state), 6)
def test_get_action_num(self): game = Game() action_num = game.get_action_num() self.assertEqual(action_num, 110)
def test_get_player_num(self): game = Game() player_num = game.get_player_num() self.assertEqual(player_num, 2)
def test_get_state(self): game = Game() state, current_player = game.init_game() self.assertEqual(len(state), 6)
def test_get_num_actions(self): game = Game() num_actions = game.get_num_actions() self.assertEqual(num_actions, 110)
def test_get_num_players(self): game = Game() num_players = game.get_num_players() self.assertEqual(num_players, 2)
def __init__(self, config): self.game = Game() super().__init__(config=config) self.state_shape = [5, 52]
class GinRummyEnv(Env): ''' GinRummy Environment ''' def __init__(self, config): self.game = Game() super().__init__(config=config) self.state_shape = [5, 52] def _extract_state(self, state): # 200213 don't use state ??? ''' Encode state Args: state (dict): dict of original state Returns: numpy array: 5 * 52 array 5 : current hand (1 if card in hand else 0) top_discard (1 if card is top discard else 0) dead_cards (1 for discards except for top_discard else 0) opponent known cards (likewise) unknown cards (likewise) # is this needed ??? 200213 ''' if self.game.is_over(): obs = np.array([utils.encode_cards([]) for _ in range(5)]) extracted_state = { 'obs': obs, 'legal_actions': self._get_legal_actions() } else: discard_pile = self.game.round.dealer.discard_pile stock_pile = self.game.round.dealer.stock_pile top_discard = [] if not discard_pile else [discard_pile[-1]] dead_cards = discard_pile[:-1] current_player = self.game.get_current_player() opponent = self.game.round.players[(current_player.player_id + 1) % 2] known_cards = opponent.known_cards unknown_cards = stock_pile + [ card for card in opponent.hand if card not in known_cards ] hand_rep = utils.encode_cards(current_player.hand) top_discard_rep = utils.encode_cards(top_discard) dead_cards_rep = utils.encode_cards(dead_cards) known_cards_rep = utils.encode_cards(known_cards) unknown_cards_rep = utils.encode_cards(unknown_cards) rep = [ hand_rep, top_discard_rep, dead_cards_rep, known_cards_rep, unknown_cards_rep ] obs = np.array(rep) extracted_state = { 'obs': obs, 'legal_actions': self._get_legal_actions() } 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 ''' payoffs = self.game.judge.scorer.get_payoffs(game=self.game) return payoffs def _decode_action( self, action_id) -> ActionEvent: # FIXME 200213 should return str ''' 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 (ActionEvent): the action that will be passed to the game engine. ''' return self.game.decode_action(action_id=action_id) def _get_legal_actions(self): ''' Get all legal actions for current state Returns: legal_actions (list): a list of legal actions' id ''' legal_actions = self.game.judge.get_legal_actions() legal_actions_ids = [ action_event.action_id for action_event in legal_actions ] return legal_actions_ids def _load_model(self): ''' Load pre-trained/rule model Returns: model (Model): A Model object ''' raise NotImplementedError