def step(state): ''' Predict the action given the current state in training data. Args: state (numpy.array): an numpy array that represents the current state Returns: action (int): the action predicted (a card with maximum deadwood value) ''' discard_action_range = range(discard_action_id, discard_action_id + 52) # 200218 wch kludge legal_actions = state['legal_actions'] actions = legal_actions.copy() discard_actions = [ action_id for action_id in actions if action_id in discard_action_range ] if discard_actions: discards = [ Card.from_card_id(card_id=action_id - discard_action_id) for action_id in discard_actions ] max_deadwood_value = max( [utils.get_deadwood_value(card) for card in discards]) best_discards = [ card for card in discards if utils.get_deadwood_value(card) == max_deadwood_value ] if best_discards: actions = [ DiscardAction(card=card).action_id for card in best_discards ] return np.random.choice(actions)
def get_knock_cards(hand: List[Card], going_out_deadwood_count: int) -> List[Card]: ''' :param hand: List[Card] -- must have 11 cards :param going_out_deadwood_count: int :return List[Card]: cards in hand that be knocked ''' assert len(hand) == 11 knock_cards = set() meld_clusters = melding.get_meld_clusters(hand=hand) for meld_cluster in meld_clusters: meld_cards = [card for meld_pile in meld_cluster for card in meld_pile] hand_deadwood = [card for card in hand if card not in meld_cards] # hand has 11 cards hand_deadwood_values = [ utils.get_deadwood_value(card) for card in hand_deadwood ] hand_deadwood_count = sum(hand_deadwood_values) max_hand_deadwood_value = max(hand_deadwood_values, default=0) if hand_deadwood_count <= 10 + max_hand_deadwood_value: for card in hand_deadwood: next_deadwood_count = hand_deadwood_count - utils.get_deadwood_value( card) if next_deadwood_count <= going_out_deadwood_count: knock_cards.add(card) return list(knock_cards)
def get_payoffs(self, game: GinRummyGame): ''' Get the payoffs of players: (100 - deadwood count) / 100 with no melds allowed Returns: payoffs (list): a list of payoffs for each player ''' payoffs = [0, 0] game_round = game.round last_action = game.actions[-1] assert game_round.is_over assert type(last_action) is ScoreSouthPlayerAction going_out_action = game_round.going_out_action for i in range(2): hand = game.round.players[i].hand if self.get_payoff: player = game.round.players[i] payoff = self.get_payoff(player, game) else: deadwood_count = sum( [utils.get_deadwood_value(card) for card in hand]) payoff = (100 - deadwood_count) / 100 payoffs[i] = payoff if type(going_out_action) is DeclareDeadHandAction: pass else: raise Exception("get_payoffs: ???") return payoffs
def _get_going_out_cards( meld_clusters: List[List[List[Card]]], hand: List[Card], going_out_deadwood_count: int) -> Tuple[List[Card], List[Card]]: ''' :param meld_clusters :param hand: List[Card] -- must have 11 cards :param going_out_deadwood_count: int :return List[Card], List[Card: cards in hand that be knocked, cards in hand that can be ginned ''' if not len(hand) == 11: raise GinRummyProgramError("len(hand) is {}: should be 11.".format( len(hand))) knock_cards = set() gin_cards = set() for meld_cluster in meld_clusters: meld_cards = [card for meld_pile in meld_cluster for card in meld_pile] hand_deadwood = [card for card in hand if card not in meld_cards] # hand has 11 cards if len(hand_deadwood) == 0: # all 11 cards are melded; # take gin_card as first card of first 4+ meld; # could also take gin_card as last card of 4+ meld, but won't do this. for meld_pile in meld_cluster: if len(meld_pile) >= 4: gin_cards.add(meld_pile[0]) break elif len(hand_deadwood) == 1: card = hand_deadwood[0] gin_cards.add(card) else: hand_deadwood_values = [ utils.get_deadwood_value(card) for card in hand_deadwood ] hand_deadwood_count = sum(hand_deadwood_values) max_hand_deadwood_value = max(hand_deadwood_values, default=0) if hand_deadwood_count <= 10 + max_hand_deadwood_value: for card in hand_deadwood: next_deadwood_count = hand_deadwood_count - utils.get_deadwood_value( card) if next_deadwood_count <= going_out_deadwood_count: knock_cards.add(card) return list(knock_cards), list(gin_cards)