def play_trick(self, leading_index, trick_nr): """ Simulate a single trick. leading_index contains the index of the player that must begin. """ player_index = leading_index trick = [] are_hearts_broken = self.are_hearts_broken() for _ in range(4): player = self.players[player_index] player_hand = self._player_hands[player_index] played_card = player.play_card(player_hand, trick, trick_nr, are_hearts_broken) if not is_card_valid(player_hand, trick, played_card, trick_nr, are_hearts_broken): raise ValueError( 'Player {} ({}) played an invalid card {} to the trick {}.' .format(player_index, type(player).__name__, played_card, trick)) trick.append(played_card) self._player_hands[player_index].remove(played_card) player_index = (player_index + 1) % 4 for player in self.players: player.see_played_trick(trick, trick_nr) winning_index = self.winning_index(trick) winning_player_index = (leading_index + winning_index) % 4 self.say('Player {} won the trick {}.', winning_player_index, trick) self._cards_taken[winning_player_index].extend(trick) return winning_player_index
def step(self, played_card=None): player_hand = self._player_hands[self.current_player_idx] if played_card is None: played_card = self.players[self.current_player_idx].play_card(self) if not is_card_valid(player_hand, self.trick, played_card, self.trick_nr, self.is_heart_broken): raise ValueError('Player {} ({}) played an invalid card {} to the trick {}.'.format(\ self.current_player_idx, type(self.players[self.current_player_idx]).__name__, played_card, self.trick)) if played_card not in self._player_hands[self.current_player_idx]: raise ValueError("Not found {} card in this Player-{} hand cards({})".format(\ played_card, self.current_player_idx, self._player_hands[self.current_player_idx])) self._player_hands[self.current_player_idx].remove(played_card) self.trick.append(played_card) for i in range(4): self.players[i].see_played_trick(played_card, self) for idx, card in zip(range(4, 0, -1), self.trick[::-1]): player_idx = (self.current_player_idx + idx) % 4 self.trick_cards[self.trick_nr][player_idx] = card self.current_player_idx = (self.current_player_idx + 1) % 4 if len(self.trick) == 4: self.round_over()
def play_card(self, hand, trick, trick_nr, are_hearts_broken): # Lead with a low card if not trick: hand.sort(key=lambda card: 100 if not are_hearts_broken and card.suit == Suit.hearts else card.rank.value) return hand[0] hand.sort(key=self.undesirability, reverse=True) self.say('Hand: {}', hand) self.say('Trick so far: {}', trick) # Safe cards are cards which will not result in winning the trick leading_suit = trick[0].suit max_rank_in_leading_suit = max([card.rank for card in trick if card.suit == leading_suit]) valid_cards = [card for card in hand if is_card_valid(hand, trick, card, trick_nr, are_hearts_broken)] safe_cards = [card for card in valid_cards if card.suit != leading_suit or card.rank <= max_rank_in_leading_suit] self.say('Valid cards: {}', valid_cards) self.say('Safe cards: {}', safe_cards) try: return safe_cards[0] except IndexError: queen_of_spades = Card(Suit.spades, Rank.queen) # Don't try to take a trick by laying the queen of spades if valid_cards[0] == queen_of_spades and len(valid_cards) > 1: return valid_cards[1] else: return valid_cards[0]
def play_trick(self, leading_index, trick_nr): """ Simulate a single trick. leading_index contains the index of the player that must begin. """ player_index = leading_index trick = [] are_hearts_broken = self.are_hearts_broken() for _ in range(4): player = self.players[player_index] player_hand = self._player_hands[player_index] played_card = player.play_card(player_hand, trick, trick_nr, are_hearts_broken) if not is_card_valid(player_hand, trick, played_card, trick_nr, are_hearts_broken): raise ValueError('Player {} ({}) played an invalid card {} to the trick {}.' .format(player_index, type(player).__name__, played_card, trick)) trick.append(played_card) self._player_hands[player_index].remove(played_card) player_index = (player_index + 1) % 4 for player in self.players: player.see_played_trick(trick, trick_nr) winning_index = self.winning_index(trick) winning_player_index = (leading_index + winning_index) % 4 self.say('Player {} won the trick {}.', winning_player_index, trick) self._cards_taken[winning_player_index].extend(trick) return winning_player_index
def play_card(self, hand, trick, trick_nr, are_hearts_broken): # Play first card that is valid for card in hand: if is_card_valid(hand, trick, card, trick_nr, are_hearts_broken): return card raise AssertionError( 'Apparently there is no valid card that can be played. This should not happen.' )
def get_valid_cards(self, hand, game): cards = [ card for card in hand if is_card_valid( hand, game.trick, card, game.trick_nr, game.is_heart_broken) ] cards.sort(key=lambda x: self.undesirability(x, game.take_pig_card), reverse=(True if game.trick else False)) return cards
def play_card(self, game): hand = game._player_hands[game.current_player_idx] # Play first card that is valid shuffle(hand) for card in hand: if is_card_valid(hand, game.trick, card, game.trick_nr, game.is_heart_broken): return card game.verbose = True game.print_game_status() raise AssertionError( 'Apparently there is no valid card that can be played. This should not happen.' )
def step(self, played_card=None): hand_cards = self._player_hands[self.current_player_idx] if played_card is None: played_card, results = self.players[ self.current_player_idx].play_card( self, simulation_time_limit=self.simulation_time_limit) if not is_card_valid(hand_cards, self.trick, played_card, self.trick_nr, self.is_heart_broken): raise ValueError('{} round - Player {} ({}) played an invalid card {}({}) to the trick {}.'.format(\ self.trick_nr, self.current_player_idx, type(self.players[self.current_player_idx]).__name__, played_card, hand_cards, self.trick)) if played_card not in self._player_hands[self.current_player_idx]: raise ValueError("{} round - Not found {} card in this Player-{} hand cards({})".format(\ self.trick_nr, played_card, self.current_player_idx, self._player_hands[self.current_player_idx])) possible_cards = [[], [], [], []] possible_cards[self.current_player_idx] = hand_cards for player_idx, info in self.players[ self.current_player_idx].void_info.items(): if player_idx != self.current_player_idx: possible_cards[player_idx] = self.players[ self.current_player_idx].get_remaining_cards(hand_cards)[:] for suit, is_void in sorted(info.items(), key=lambda x: x[0]): if is_void: for card in possible_cards[player_idx][:]: if card.suit == suit: possible_cards[player_idx].remove(card) #print("try to remove {} card from player-{}, current_suit is {}, {}".format(\ # card, player_idx, suit, info)) for player_idx, cards in self.players[ self.current_player_idx].transfer_cards.items(): for idx in range(len(possible_cards)): if idx != player_idx: for card in cards: if card in possible_cards[idx]: possible_cards[idx].remove(card) trick_cards = self.trick valid_cards, probs = [], [0] * 52 for card, prob in results: valid_cards.append(card) probs[card2v(card)] = prob probs = log_softmax(probs) leading_cards = len(self.trick) == 0 expose_cards = self.expose_info self._short_memory.append([ self.current_player_idx, self.trick_cards, self.score_cards, possible_cards, trick_cards, valid_cards, leading_cards, expose_cards, probs, None ]) if IS_DEBUG: print_a_memory(self._short_memory[-1]) self._player_hands[self.current_player_idx].remove(played_card) self.trick.append(played_card) if len(self.trick) == 4: for idx, card in zip(range(4, 0, -1), self.trick[::-1]): player_idx = (self.current_player_idx + idx) % 4 self.trick_cards[self.trick_nr][player_idx] = card for i in range(4): self.players[i].see_played_trick(played_card, self) self.current_player_idx = (self.current_player_idx + 1) % 4 if len(self.trick) == 4: self.round_over()