예제 #1
0
    def pull_card_from_pile_top(self):
        self.turn_output['pull_source'] = 'pile'
        n_cards = len(self.pile_top_cards)

        accessible_cards = self.pile_top_cards
        if 1 == n_cards:
            self.chosen_from_pile_top = self.pile_top_cards[0]
            return self.pile_top_cards[0]
        elif 2 == n_cards:
            # both card are accessible
            pass
        else:
            accessible_cards = pile_top_accessible_cards(self.pile_top_cards)
        # ======== here we will need to introduce strategy of best card to choose ============
        player_cards = self.turn_player.cards_in_hand
        cards_plus_player_collective_points_ = pile_cards_plus_player_collective_hypothetical_points(accessible_cards, player_cards)

        if bool(cards_plus_player_collective_points_):
            this_card = next(iter(cards_plus_player_collective_points_))
        else:
            if len(accessible_cards) == 1:
                this_card = accessible_cards[0]
            else:
                this_card = sorted(accessible_cards, key=lambda card: card_to_value(card), reverse=False)[0]

        # print(self.number, self.turn_number, self.pile_top_cards, accessible_cards, player_cards, cards_plus_player_collective_points_, this_card)


        # =====================================
        self.pile_top_cards = list(set(self.pile_top_cards) - set([this_card]))
        self.chosen_from_pile_top = this_card

        return this_card
예제 #2
0
def step(env, name, action):
    info = {'yaniv_declare_correct': None}

    declare_yaniv = action[0]
    cards_to_throw = action[1]
    pick_from_deck = action[2]

    cards_in_hand_before = env.players[name].cards_in_hand
    n_cards_in_hand_before = len(cards_in_hand_before)
    hand_sum_before = cards_to_value_sum(cards_in_hand_before)

    reward_yaniv, reward_throw_pick = 0, 0
    done = False
    if declare_yaniv:
        done = True
        if hand_sum_before <= YANIV_LIMIT:
            env.round_.round_summary(name)
            info['yaniv_declare_correct'] = True
        else:
            reward_yaniv = REWARD_FACTOR_YANIV_INCORRECT_PENALTY
            info['yaniv_declare_correct'] = False

        n_cards_in_hand_after = None
    else:
        env.round_.throw_cards_to_pile(name, cards_to_throw=cards_to_throw)
        env.round_.pull_card(name, pick_from_deck=pick_from_deck)
        env.round_.pile_top_cards = env.round_.pile_top_cards_this_turn
        env.round_.update_players_knowledge(name)

        cards_in_hand_after = env.players[name].cards_in_hand
        n_cards_in_hand_after = len(cards_in_hand_after)

        reward_throw_pick_points = cards_to_value_sum(
            cards_in_hand_before) - cards_to_value_sum(cards_in_hand_after)
        reward_throw_pick_points *= REWARD_FACTOR_TURN_POINT_DIFFERENCE

        reward_throw_pick_n_cards = n_cards_in_hand_before - n_cards_in_hand_after
        reward_throw_pick_n_cards *= REWARD_FACTOR_TURN_N_CARDS
        reward_throw_pick = reward_throw_pick_points + reward_throw_pick_n_cards

    reward = reward_yaniv + reward_throw_pick

    # --- setting up opponent ---
    opponent_name = _name_to_opponent_name_two_players(name, env.players)

    n_deck = len(env.round_.round_deck)
    top_accessible_cards = pile_top_accessible_cards(env.round_.pile_top_cards)
    cards_in_hand = env.players[opponent_name].cards_in_hand

    observables = n_deck, top_accessible_cards, cards_in_hand, n_cards_in_hand_after

    return opponent_name, observables, reward, done, info
예제 #3
0
    def pull_card(self, name, pick_from_deck=None):
        player = self.players[name]
        self.turn_player = player

        self.chosen_from_pile_top = None

        if 'human' == player.agent:
            options = {'1': 'deck'} #, '2': 'pile': }
            accessible_cards = pile_top_accessible_cards(self.pile_top_cards)
            for option_id, card in enumerate(accessible_cards, 2):
                options[f'{option_id}'] = card
            option_id = self.io_options(options, player, option_type='pull')

            if '1' == option_id:
                this_card = self.pull_card_from_deck()
                source = 'deck'
            else:
                this_card = options[option_id]
                source = 'pile'
            print(f'You chose {this_card} from the {source}')

        else:

            if pick_from_deck is not None:
                if pick_from_deck == True:
                    pull_card_function = self.pull_card_from_deck
                else:
                    pull_card_function = self.pull_card_from_pile_top
            else:
                # ======== need to devise better strategy ===========
                #pull_card_function = np.random.choice([self.pull_card_from_deck, self.pull_card_from_pile_top])

                card_values = [card_to_value(card) for card in self.pile_top_cards]
                idx_lowest = np.array(card_values).argmin()

                if player.strategy["pile_pull"]["highest_card_value_to_pull"]  >= card_values[idx_lowest]:
                    pull_card_function = self.pull_card_from_pile_top
                else:
                    pull_card_function = self.pull_card_from_deck

            # overriding previous decision, because the deck is empty ...
            if len(self.round_deck) == 0:
                pull_card_function = self.pull_card_from_pile_top

            this_card = pull_card_function()
            # ==================================================

        self.turn_output['pulls'] = this_card
        player.cards_in_hand.append(this_card)
        player.sum_hand_points()
        player.remove_cards_from_unknown([this_card])
예제 #4
0
    def play_round(self, players_ordered=None, turn=0):
        # flag to finish round. True: keep playing, False: end of round.
        yaniv_declared = False

        if not players_ordered:
            players_ordered = self.get_player_order()

            # each player accounts for other players hands. In beginning no knowledge
            for name_i, player_i in players_ordered.items():
                player_i.other_players_known_cards = {}
                for name_j, player_j in players_ordered.items():
                    if name_i != name_j:
                        player_i.other_players_known_cards[name_j] = []

        #print('playing order: ', ', '.join(list(players_ordered.keys())))

        for name, player in players_ordered.items():
            turn += 1
            self.turn_number = turn
            self.round_output[turn] = {}
            self.turn_output = self.round_output[turn]

            player.strategy = pile_conservative_constant()

            self.turn_output['name'] = name
            self.turn_output['pile_top_accessible'] = list(pile_top_accessible_cards(self.pile_top_cards))
            #self.turn_output[name] = list(player.cards_in_hand) # this might be redundant information
            for name_j, player_j in players_ordered.items():
                self.turn_output[f'{name_j}_ncards'] = len(list(player_j.cards_in_hand))
                self.turn_output[f'{name_j}_cards'] = list(player_j.cards_in_hand)
            # self._log_meta_data(player)

            # ================
            # player.action(yaniv_declared)
            # ================

            if not yaniv_declared:
                if player.hand_points <= YANIV_LIMIT:
                    # name considers declearing yaniv based on their Player.yaniv_strategy probability of success

                    # ------ return to this ------
                    yaniv_declared = self.decide_declare_yaniv(name)
                # ----------temporary ---------
                ## yaniv_declared = np.random.choice([True, False], size=1, p=[0.4, 0.6])[0]
                # -----------------------------
                if yaniv_declared:
                    self.turn_output['yaniv_call'] = 1
                    # round ends
                    self.round_summary(name)
                    return None

                else:
                    self.throw_cards_to_pile(name)
                    self.pull_card(name)
                    self.pile_top_cards = self.pile_top_cards_this_turn

                    self.update_players_knowledge(name)

        if not yaniv_declared:
            if turn >= MAX_TURNS:
                print(f'Reached {MAX_TURNS} turns, terminating round')
                self.turn_output['max_turns'] = 1
                return None
            # at this stage we did a full "circle around the table",
            # but did not conclude with a Yaniv declaration. We will go for another round
            # perhaps there is a better way of doing this loop.
            self.play_round(players_ordered=players_ordered, turn=turn)
예제 #5
0
def visualise_cards(cards, ax=None, cards_type='hand', show_spines=False):
    """

    :param cards:
    :param ax:
    :param cards_type:
    :param show_spines:
    :return:

    Example usage
    cards_hand = ['As', '7d', 'Kc', 'Wa', 'Wb']
    cards_pile = ['2s', '3s', '4s']

    ax = visualise_cards(cards_hand, ax=None, cards_type='hand', show_spines=False)
    visualise_cards(cards_pile, ax=ax, cards_type='pile', show_spines=False)
    visualise_cards(4, ax=ax, cards_type='opponent', show_spines=False)
    """
    assert cards_type in ['hand', 'pile', 'deck', 'opponent']

    show_card_values = True
    if 'hand' == cards_type:
        bottom = 0.1
    elif 'pile' == cards_type:
        bottom = YLIM / 2 - CARD_HEIGHT / 2
        cards_accessible = pile_top_accessible_cards(cards)
    elif 'opponent' == cards_type:
        bottom = YLIM / 2 + CARD_HEIGHT / 2 + 0.1
        assert isinstance(cards, int)
        cards = [None] * cards
        show_card_values = False

    hatch = None
    if not show_card_values:
        hatch = '/'

    if ax is None:
        fig, ax = plt.subplots(1, figsize=FIGSIZE)

    ncards = len(cards)
    left_most = CARD_WIDTH / 2 + (MAX_CARDS - ncards) * CARD_WIDTH / 2

    left = left_most
    dx, dy = 0.2, -0.1
    card_margin = 0.02
    for card in cards:
        alpha = 1
        if 'pile' == cards_type:
            if card not in cards_accessible:
                alpha = 0.3

        ax.add_patch(
            Rectangle((left, bottom),
                      CARD_WIDTH,
                      CARD_HEIGHT,
                      fill=False,
                      alpha=alpha,
                      hatch=hatch))

        if show_card_values:
            card_pretty = card_to_pretty(card)
            if 'W' in card_pretty:
                card_pretty = card_pretty[-1]

            ax.annotate(card_pretty, ((left + (left + CARD_WIDTH)) / 2 - dx,
                                      (bottom + CARD_HEIGHT / 2.2)),
                        rotation=0,
                        fontsize=30,
                        alpha=alpha,
                        color=card_to_color(card))

        left += CARD_WIDTH + card_margin

    plt.xlim(0., XLIM)
    plt.ylim(0., YLIM)

    if not show_spines:
        spines = ['right', 'top', 'left', 'bottom']
        [ax.spines[spine].set_visible(False) for spine in spines]
        ax.tick_params(bottom=False, left=False)
        ax.yaxis.set_major_locator(plt.NullLocator())
        ax.xaxis.set_major_formatter(plt.NullFormatter())

    return ax
예제 #6
0
    def test3(self):
        pile_cards = ['9s', '10s', 'Js', 'Qs']
        result = pile_top_accessible_cards(pile_cards)

        self.assertEqual(['9s', 'Qs'], result)
예제 #7
0
    def test2(self):
        pile_cards = ['As', 'Ad', 'Ah']
        result = pile_top_accessible_cards(pile_cards)

        self.assertEqual(pile_cards, result)
예제 #8
0
    def test(self):
        pile_cards = ['As', '2s', '3s']
        result = pile_top_accessible_cards(pile_cards)

        self.assertEqual(['As', '3s'], result)