Exemplo n.º 1
0
def get_meld_clusters(
        hand: List[Card],
        going_out_deadwood_count: int,
        is_going_out: bool = False,
        opponent_meld_piles: List[List[Card]] = None) -> List[List[Set[Card]]]:
    # if is_going_out is true, then return only meld_piles with deadwood count <= 10
    # opponent_meld_piles are the meld_piles for the opponent who has knocked to be used for laying off cards
    result = []
    all_run_melds = [set(x) for x in _get_all_run_melds(hand)]
    all_set_melds = [set(x) for x in _get_all_set_melds(hand)]
    all_melds = all_run_melds + all_set_melds
    all_melds_count = len(all_melds)
    for i in range(0, all_melds_count):
        first_meld = all_melds[i]
        meld_cluster_1 = [first_meld]
        if is_going_out:
            deadwood_count = utils.get_deadwood_count(
                hand=hand, meld_cluster=meld_cluster_1)
            if deadwood_count <= going_out_deadwood_count:
                result.append(meld_cluster_1)
        else:
            result.append(meld_cluster_1)
        for j in range(i + 1, all_melds_count):
            second_meld = all_melds[j]
            if not second_meld.isdisjoint(first_meld):
                continue
            meld_cluster_2 = [first_meld, second_meld]
            if is_going_out:
                deadwood_count = utils.get_deadwood_count(
                    hand=hand, meld_cluster=meld_cluster_2)
                if deadwood_count <= going_out_deadwood_count:
                    result.append(meld_cluster_2)
            else:
                result.append(meld_cluster_2)
            for k in range(j + 1, all_melds_count):
                third_meld = all_melds[k]
                if not third_meld.isdisjoint(
                        first_meld) or not third_meld.isdisjoint(second_meld):
                    continue
                meld_cluster_3 = [first_meld, second_meld, third_meld]
                if is_going_out:
                    deadwood_count = utils.get_deadwood_count(
                        hand=hand, meld_cluster=meld_cluster_3)
                    if deadwood_count <= going_out_deadwood_count:
                        result.append(meld_cluster_3)
                else:
                    result.append(meld_cluster_3)
    return result
Exemplo n.º 2
0
def get_payoff_gin_rummy_v1(player: GinRummyPlayer,
                            game: 'GinRummyGame') -> int or float:
    ''' Get the payoff of player:
            a) 1.0 if player gins
            b) 0.2 if player knocks
            c) -deadwood_count / 100 otherwise

    Returns:
        payoff (int or float): payoff for player
    '''
    # payoff is 1.0 if player gins
    # payoff is 0.2 if player knocks
    # payoff is -deadwood_count / 100 if otherwise
    # The goal is to have the agent learn how to knock and gin.
    # The negative payoff when the agent fails to knock or gin should encourage the agent to form melds.
    # The payoff is scaled to lie between -1 and 1.
    going_out_action = game.round.going_out_action
    going_out_player_id = game.round.going_out_player_id
    if going_out_player_id == player.player_id and type(
            going_out_action) is KnockAction:
        payoff = 0.2
    elif going_out_player_id == player.player_id and type(
            going_out_action) is GinAction:
        payoff = 1
    else:
        hand = player.hand
        best_meld_clusters = melding.get_best_meld_clusters(hand=hand)
        best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[
            0]
        deadwood_count = utils.get_deadwood_count(hand, best_meld_cluster)
        payoff = -deadwood_count / 100
    return payoff
Exemplo n.º 3
0
 def _get_best_discards(discard_action_events, state) -> List[Card]:
     best_discards = []  # type: List[Card]
     final_deadwood_count = 999
     env_hand = state['obs'][0]
     hand = utils.decode_cards(env_cards=env_hand)
     for discard_action_event in discard_action_events:
         discard_card = discard_action_event.card
         next_hand = [card for card in hand if card != discard_card]
         meld_clusters = melding.get_meld_clusters(hand=next_hand)
         deadwood_counts = []
         for meld_cluster in meld_clusters:
             deadwood_count = utils.get_deadwood_count(hand=next_hand, meld_cluster=meld_cluster)
             deadwood_counts.append(deadwood_count)
         best_deadwood_count = min(deadwood_counts,
                                   default=utils.get_deadwood_count(hand=next_hand, meld_cluster=[]))
         if best_deadwood_count < final_deadwood_count:
             final_deadwood_count = best_deadwood_count
             best_discards = [discard_card]
         elif best_deadwood_count == final_deadwood_count:
             best_discards.append(discard_card)
     return best_discards
Exemplo n.º 4
0
def get_best_meld_clusters(hand: List[Card]) -> List[List[List[Card]]]:
    assert len(hand) == 10
    result = []  # type: List[List[List[Card]]]
    meld_clusters = get_meld_clusters(hand=hand)  # type: List[List[List[Card]]]
    meld_clusters_count = len(meld_clusters)
    if meld_clusters_count > 0:
        deadwood_counts = [utils.get_deadwood_count(hand=hand, meld_cluster=meld_cluster)
                           for meld_cluster in meld_clusters]
        best_deadwood_count = min(deadwood_counts)
        for i in range(meld_clusters_count):
            if deadwood_counts[i] == best_deadwood_count:
                result.append(meld_clusters[i])
    return result
Exemplo n.º 5
0
 def score_player_0(self, action: ScoreNorthPlayerAction):
     # when current_player takes ScoreNorthPlayerAction step, the move is recorded and executed
     # south becomes current player
     if not self.current_player_id == 0:
         raise GinRummyProgramError("current_player_id is {}: should be 0.".format(self.current_player_id))
     current_player = self.get_current_player()
     best_meld_clusters = melding.get_best_meld_clusters(hand=current_player.hand)
     best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[0]
     deadwood_count = utils.get_deadwood_count(hand=current_player.hand, meld_cluster=best_meld_cluster)
     self.move_sheet.append(ScoreNorthMove(player=current_player,
                                           action=action,
                                           best_meld_cluster=best_meld_cluster,
                                           deadwood_count=deadwood_count))
     self.current_player_id = 1
Exemplo n.º 6
0
 def _get_payoff(self, player: GinRummyPlayer, game) -> float:
     going_out_action = game.round.going_out_action
     going_out_player_id = game.round.going_out_player_id
     if going_out_player_id == player.player_id and type(going_out_action) is KnockAction:
         payoff = self._knock_reward
     elif going_out_player_id == player.player_id and type(going_out_action) is GinAction:
         payoff = self._gin_reward
     else:
         hand = player.hand
         best_meld_clusters = melding.get_best_meld_clusters(hand=hand)
         best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[0]
         deadwood_count = utils.get_deadwood_count(hand, best_meld_cluster)
         payoff = -deadwood_count / 100
     return payoff
Exemplo n.º 7
0
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
Exemplo n.º 8
0
 def score_player_1(self, action: ScoreSouthPlayerAction):
     assert self.current_player_id == 1
     current_player = self.get_current_player()
     best_meld_clusters = melding.get_best_meld_clusters(
         hand=current_player.hand)
     best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[
         0]
     deadwood_count = utils.get_deadwood_count(
         hand=current_player.hand, meld_cluster=best_meld_cluster)
     self.move_sheet.append(
         ScoreSouthMove(player=current_player,
                        action=action,
                        best_meld_cluster=best_meld_cluster,
                        deadwood_count=deadwood_count))
     self.is_over = True
Exemplo n.º 9
0
def get_best_meld_clusters(hand: List[Card]) -> List[List[Set[Card]]]:
    result = []
    meld_clusters = get_meld_clusters(hand=hand,
                                      going_out_deadwood_count=100,
                                      is_going_out=False)
    meld_clusters_count = len(meld_clusters)
    if meld_clusters_count > 0:
        deadwood_counts = [
            utils.get_deadwood_count(hand=hand, meld_cluster=meld_cluster)
            for meld_cluster in meld_clusters
        ]
        best_deadwood_count = min(deadwood_counts)
        for i in range(meld_clusters_count):
            if deadwood_counts[i] == best_deadwood_count:
                result.append(meld_clusters[i])
    return result
Exemplo n.º 10
0
 def score_player_0(self, action: ScoreNorthPlayerAction):
     # when current_player takes ScoreNorthPlayerAction step, the move is recorded and executed
     # south becomes current player
     assert self.current_player_id == 0
     current_player = self.get_current_player()
     best_meld_clusters = melding.get_best_meld_clusters(
         hand=current_player.hand)
     best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[
         0]
     deadwood_count = utils.get_deadwood_count(
         hand=current_player.hand, meld_cluster=best_meld_cluster)
     self.move_sheet.append(
         ScoreNorthMove(player=current_player,
                        action=action,
                        best_meld_cluster=best_meld_cluster,
                        deadwood_count=deadwood_count))
     self.current_player_id = 1
Exemplo n.º 11
0
def get_best_meld_clusters(hand: List[Card]) -> List[List[List[Card]]]:
    if len(hand) != 10:
        raise GinRummyProgramError(
            "Hand contain {} cards: should be 10 cards.".format(len(hand)))
    result = []  # type: List[List[List[Card]]]
    meld_clusters = get_meld_clusters(
        hand=hand)  # type: List[List[List[Card]]]
    meld_clusters_count = len(meld_clusters)
    if meld_clusters_count > 0:
        deadwood_counts = [
            utils.get_deadwood_count(hand=hand, meld_cluster=meld_cluster)
            for meld_cluster in meld_clusters
        ]
        best_deadwood_count = min(deadwood_counts)
        for i in range(meld_clusters_count):
            if deadwood_counts[i] == best_deadwood_count:
                result.append(meld_clusters[i])
    return result
Exemplo n.º 12
0
    def get_payoffs(self, game: GinRummyGame):
        ''' Get the payoffs of players:
                a) 1 if gin
                b) 0.2 if knock
                c) -deadwood_count / 100 otherwise

        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
        going_out_player_id = game_round.going_out_player_id
        for i in range(2):  # FIXME: 200213 simplified calculation
            player = game.round.players[i]
            hand = player.hand
            if self.get_payoff:
                payoff = self.get_payoff(player, game)
            else:
                best_meld_clusters = melding.get_best_meld_clusters(hand=hand)
                best_meld_cluster = [] if not best_meld_clusters else best_meld_clusters[
                    0]
                deadwood_count = utils.get_deadwood_count(
                    hand, best_meld_cluster)
                payoff = -deadwood_count / 100
                if going_out_player_id == player.player_id and type(
                        going_out_action) is KnockAction:
                    payoff = 0.2  # FIXME: 200213 simplified calculation
                elif going_out_player_id == player.player_id and type(
                        going_out_action) is GinAction:
                    payoff = 1  # FIXME: 200213 simplified calculation
                elif type(going_out_action) is DeclareDeadHandAction:
                    pass  # FIXME: 200213 payoffs should be zeros
                else:
                    raise Exception("get_payoffs: ???")
            payoffs[i] = payoff
        return payoffs