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
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
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])
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)
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
def test3(self): pile_cards = ['9s', '10s', 'Js', 'Qs'] result = pile_top_accessible_cards(pile_cards) self.assertEqual(['9s', 'Qs'], result)
def test2(self): pile_cards = ['As', 'Ad', 'Ah'] result = pile_top_accessible_cards(pile_cards) self.assertEqual(pile_cards, result)
def test(self): pile_cards = ['As', '2s', '3s'] result = pile_top_accessible_cards(pile_cards) self.assertEqual(['As', '3s'], result)