Beispiel #1
0
    def _list_best_options(self):
        """
        Returns a list of the highest probability asks you can make, according to self.info
        Ties are broken in this method by the following criteria:
        1. Number of guarenteed cards in half suit
        If player A is guarenteed to have more cards in the half suit than player B, ask them

        This method does not account for the "danger" of asking certain players yet
        """
        best_asks = []
        highest_prob = 0
        most_hs_cards = 0
        for card in card_utils.gen_all_cards():
            for ID in self._get_opponents():
                if self._check_legal_ask(ID, card):
                    if self.info[ID][card] != NO:
                        best_asks = [(ID, card)]
                        highest_prob = self.info[ID][card]
                        most_hs_cards = self.hs_info[ID][
                            card_utils.find_half_suit(card)]
                    elif self.info[ID][card] == highest_prob:
                        if self.hs_info[ID][card_utils.find_half_suit(
                                card)] > most_hs_cards:
                            best_asks = [(ID, card)]
                            most_hs_cards = self.hs_info[ID][
                                card_utils.find_half_suit(card)]
                        elif self.hs_info[ID][card_utils.find_half_suit(
                                card)] == most_hs_cards:
                            best_asks.append((ID, card))
        return best_asks
Beispiel #2
0
 def _update_public_info(self,
                         check_cards=tuple(card_utils.gen_all_cards())):
     self.public_info = self._update_recurse(copy.deepcopy(
         self.public_info),
                                             self.remaining_hs,
                                             self.public_hs_info,
                                             self.num_cards,
                                             check_cards=check_cards)
Beispiel #3
0
    def generate_state_vector(info, hs_info, num_cards, public_info, ID_player):
        """
        Generates a state vector from the player's information

        The structure of the state vector is as follows:
        Length: 708 (SIZE_STATES)
        The order of players in each section starts with the ID of the player
        and counts up mod 6 (example: 3, 4, 5, 0, 1, 2)
        The order of cards is defined in card_utils.gen_all_cards
        The first 54 * 6 = 324 entries are for the info dict, with the values
        being the same as in the info dict
        The next 54 * 6 = 324 entries are for the public_info dict, with the values
        being the same as in the public_info dict
        The next 9 * 6 = 54 entries are for the hs_info, with the values
        being the same as in the hs_info dict
        The last 6 entries are the number of cards each player has

        :param info: defined in Player class
        :param hs_info: defined in Player class
        :param num_cards: defined in Player class
        :param public_info: defined in Player class
        :param ID_player: ID of the player
        :return: a state vector
        """
        player_order = list(range(6))[ID_player:] + list(range(6))[:ID_player]
        state = []
        # Info dict
        for ID in player_order:
            for card in card_utils.gen_all_cards():
                state.append(info[ID][card])
        # Public Info dict
        for ID in player_order:
            for card in card_utils.gen_all_cards():
                state.append(public_info[ID][card])
        # Half suit info dict
        for ID in player_order:
            for hs in card_utils.gen_all_halfsuits():
                state.append(hs_info[ID][hs])
        # Num cards
        for ID in player_order:
            state.append(num_cards[ID])
        return state
Beispiel #4
0
 def _init_info_start_game(ID, own_cards):
     """
     Returns the info dictionary assuming its the start of a new game
     Given your own cards and ID
     """
     info = {}
     for player_id in range(NUM_PLAYERS):
         if player_id == ID:
             player_cards = {
                 card: NO
                 for card in card_utils.gen_all_cards()
             }
             for card in own_cards:
                 player_cards[card] = YES
         else:
             player_cards = {
                 card: UNSURE
                 for card in card_utils.gen_all_cards()
             }
         info[player_id] = player_cards.copy()
     return info
Beispiel #5
0
 def _init_public_info_start_game():
     """
     Returns an "empty" public info dictionary
     :return: a dictionary that represents the public information at the start of the game
     """
     public_info_dict = {}
     for ID in range(NUM_PLAYERS):
         player_info = {}
         for card in card_utils.gen_all_cards():
             player_info[card] = UNSURE
         public_info_dict[ID] = player_info
     return public_info_dict
Beispiel #6
0
 def generate_action_number(ID_ask, ID_target, card):
     """
     Generates an action vector from the player's action
     This vector is universal to all players, meaning it is independent of player ID
     For example, player 0 asking player 3 for a Jc will return the ]
     same vector as player 1 asking player 4 for a Jc
     This is to ensure that the model can be used universally among all players
     :param ID_ask: ID of player asking
     :param ID_target: ID of target
     :param card: Card being asked
     :return: Action number (0-161)
     """
     player_num = (((ID_target - ID_ask) % 6) - 1)//2
     card_num = list(card_utils.gen_all_cards()).index(card)
     return player_num * constants.DECK_SIZE + card_num
Beispiel #7
0
 def make_optimal_ask(self):
     """
     Returns the optimal person and card to ask
     Format: (target_player_id, card)
     """
     ask_guarenteed = self._check_card_guarenteed()
     if ask_guarenteed:
         return ask_guarenteed
     # For now, just ask randomly if no obvious card
     target = self._get_opponents()[random.randint(0, 2)]
     valid = []
     for c in card_utils.gen_all_cards():
         if self._check_legal_ask(target, c):
             valid.append(c)
     return target, valid[random.randint(0, len(valid) - 1)]
Beispiel #8
0
 def print_info(self):
     for ID in range(NUM_PLAYERS):
         if self.ID == ID:
             print("Player {} (You)".format(ID))
         else:
             print("Player {}".format(ID))
         known_yes = []
         known_no = []
         for card in card_utils.gen_all_cards():
             if self.info[ID][card] == YES:
                 known_yes.append(card)
             elif self.info[ID][card] == NO:
                 known_no.append(card)
         print("Guarenteed to have: ")
         print(" ".join(known_yes))
         print("Guarenteed to not have: ")
         print(" ".join(known_no))
         print()
Beispiel #9
0
 def test_is_consistent_all_nos_3(self):
     info = {
         ID:
         {card: constants.UNSURE
          for card in card_utils.gen_all_cards()}
         for ID in range(constants.NUM_PLAYERS)
     }
     hs_info = {
         ID: {hs: 0
              for hs in card_utils.gen_all_halfsuits()}
         for ID in range(constants.NUM_PLAYERS)
     }
     for ID in range(constants.NUM_PLAYERS):
         info[ID]["2h"] = constants.NO
     self.assertTrue(
         Player._is_consistent(
             info, ["8J"], hs_info,
             {ID: 1
              for ID in range(constants.NUM_PLAYERS)}),
         "Incorrectly claimed inconsistency")
Beispiel #10
0
 def test_is_consistent_all_nos(self):
     info = {
         ID:
         {card: constants.UNSURE
          for card in card_utils.gen_all_cards()}
         for ID in range(constants.NUM_PLAYERS)
     }
     hs_info = {
         ID: {hs: 0
              for hs in card_utils.gen_all_halfsuits()}
         for ID in range(constants.NUM_PLAYERS)
     }
     for ID in range(constants.NUM_PLAYERS):
         info[ID]["2h"] = constants.NO
     self.assertFalse(
         Player._is_consistent(
             info, ["Lh"], hs_info,
             {ID: 1
              for ID in range(constants.NUM_PLAYERS)}),
         "Failed to catch duplicate cards in _is_consistent")
Beispiel #11
0
 def test_is_consistent_duplicate_cards(self):
     info = {
         ID:
         {card: constants.UNSURE
          for card in card_utils.gen_all_cards()}
         for ID in range(constants.NUM_PLAYERS)
     }
     hs_info = {
         ID: {hs: 1
              for hs in card_utils.gen_all_halfsuits()}
         for ID in range(constants.NUM_PLAYERS)
     }
     info[0]["2h"] = constants.YES
     info[1]["2h"] = constants.YES
     self.assertFalse(
         Player._is_consistent(
             info, list(card_utils.gen_all_halfsuits()), hs_info,
             {ID: 9
              for ID in range(constants.NUM_PLAYERS)}),
         "Failed to catch duplicate cards in _is_consistent")
Beispiel #12
0
 def test_is_consistent_hs(self):
     info = {
         ID:
         {card: constants.UNSURE
          for card in card_utils.gen_all_cards()}
         for ID in range(constants.NUM_PLAYERS)
     }
     hs_info = {
         ID: {hs: 0
              for hs in card_utils.gen_all_halfsuits()}
         for ID in range(constants.NUM_PLAYERS)
     }
     hs_info[1]["Hc"] = 4
     info[1]["9c"] = constants.NO
     info[1]["Tc"] = constants.NO
     self.assertTrue(
         Player._is_consistent(
             info, list(card_utils.gen_all_halfsuits()), hs_info,
             {ID: 9
              for ID in range(constants.NUM_PLAYERS)}),
         "Incorrectly claimed inconsistency")
Beispiel #13
0
    def _is_consistent(info_dict,
                       remaining_hs,
                       hs_info,
                       num_cards,
                       check_cards=tuple(card_utils.gen_all_cards())):
        """
        Checks if an info dictionary is consistent. If the info dictionary
        has a contradiction, returns false. Otherwise returns true.

        Info dictionaries must follow these rules:
        1. No two players can have YES for the same card
        2. If the half suit has not been called yet, at least 1 player
        must have at least the possibility of having any card
        in that half suit
        3. If a player has at least X cards in a half suit, they cannot have
        more than HS_SIZE-X cards being NO in that half suit
        4. If a player has X cards in their hand, they cannot have more than
        DECK_SIZE-X cards being NO
        :param info_dict: either a public info dict or player info dict
        :param remaining_hs: the remaining half suits in the game
        :param hs_info: the half suit info
        :param num_cards: number of each players cards
        :param check_cards: cards to check for consistency
        :return: True if consistent, false otherwise
        """
        # Calculate check_hs based on check_cards
        check_hs = set([])
        for c in check_cards:
            hs = card_utils.find_half_suit(c)
            if hs not in check_hs and hs in remaining_hs:
                check_hs.add(hs)
        # Rule 1
        for card in check_cards:
            players_yes = 0
            for ID in range(NUM_PLAYERS):
                if info_dict[ID][card] == YES:
                    players_yes += 1
            if players_yes > 1:
                return False
        # Rule 2
        for hs in check_hs:
            for card in card_utils.find_cards(hs):
                players_no = 0
                for ID in range(NUM_PLAYERS):
                    if info_dict[ID][card] == NO:
                        players_no += 1
                if players_no == NUM_PLAYERS:
                    return False
        # Rule 3
        for hs in check_hs:
            for ID in range(NUM_PLAYERS):
                hs_no_count = 0
                for card in card_utils.find_cards(hs):
                    if info_dict[ID][card] == NO:
                        hs_no_count += 1
                if hs_info[ID][hs] + hs_no_count > HS_SIZE:
                    return False
        # Rule 4
        for ID in range(NUM_PLAYERS):
            no_count = 0
            for card in card_utils.gen_all_cards():
                if info_dict[ID][card] == NO:
                    no_count += 1
            if num_cards[ID] + no_count > DECK_SIZE:
                return False
        return True