def update_transaction(self, ID_ask, ID_target, card, success): """ Given a transaction, updates the player's info, public info, and half suit info :param ID_ask: ID of player asking for the card :param ID_target: player being asked :param card: card being asked :param success: true if card was taken from ID_target """ if success: self.num_cards[ID_ask] += 1 self.num_cards[ID_target] -= 1 self.info[ID_ask][card] = YES self.info[ID_target][card] = NO self.public_info[ID_ask][card] = YES self.public_info[ID_target][card] = NO if self.hs_info[ID_ask][card_utils.find_half_suit(card)] == 0: self.hs_info[ID_ask][card_utils.find_half_suit(card)] = 1 self.hs_info[ID_ask][card_utils.find_half_suit(card)] += 1 if self.public_hs_info[ID_ask][card_utils.find_half_suit( card)] == 0: self.public_hs_info[ID_ask][card_utils.find_half_suit( card)] = 1 self.public_hs_info[ID_ask][card_utils.find_half_suit(card)] += 1 if self.hs_info[ID_target][card_utils.find_half_suit(card)] > 0: self.hs_info[ID_target][card_utils.find_half_suit(card)] -= 1 if self.public_hs_info[ID_target][card_utils.find_half_suit( card)] > 0: self.public_hs_info[ID_target][card_utils.find_half_suit( card)] -= 1 else: self.info[ID_ask][card] = NO self.info[ID_target][card] = NO self.public_info[ID_ask][card] = NO self.public_info[ID_target][card] = NO if self.hs_info[ID_ask][card_utils.find_half_suit(card)] == 0: self.hs_info[ID_ask][card_utils.find_half_suit(card)] = 1 if self.public_hs_info[ID_ask][card_utils.find_half_suit( card)] == 0: self.public_hs_info[ID_ask][card_utils.find_half_suit( card)] = 1 self._update_info( card_utils.find_cards(card_utils.find_half_suit(card))) self._update_public_info( card_utils.find_cards(card_utils.find_half_suit(card)))
def test_check_call(self): own_hand = ["2h", "3h", "4h", "5h", "6h", "7h", "8h", "9h", "Th"] p1 = Player.player_start_of_game(0, own_hand) res = p1.check_call() expected = [(0, x) for x in card_utils.find_cards("Lh")] self.assertTrue(res, "Did not call") self.assertEqual( res, expected, "Did not attribute the cards with the correct player")
def _check_card_guarenteed(self): """ Checks if an opponent player has a card that you know you are guarenteed to guess correctly If so, return a tuple (player_id, card) If not, return False """ for hs in card_utils.gen_all_halfsuits(): if self.hs_info[self.ID][hs] > 0: for card in card_utils.find_cards(hs): for ID in self._get_opponents(): if self.info[ID][card] == YES: return ID, card return False
def report_call(self, hs): """ Updates the player_cards dict Makes each player update their info in response to a call :param hs: half suit being called """ hs_info_dict = {ID: 0 for ID in range(NUM_PLAYERS)} for card in card_utils.find_cards(hs): for ID in range(NUM_PLAYERS): if card in self.player_cards[ID]: self.player_cards[ID].remove(card) hs_info_dict[ID] += 1 for player in self.players: player.update_call(hs, hs_info_dict)
def test_update_info_endgame(self): own_hand = ["2h", "3h"] p1 = Player.player_start_of_game(0, own_hand) p1.num_cards = {0: 2, 1: 0, 2: 2, 3: 0, 4: 2, 5: 0} for c in card_utils.gen_all_cards(): for ID in range(constants.NUM_PLAYERS): if c not in card_utils.find_cards( "Lh") or ID in p1._get_opponents(): p1.info[ID][c] = constants.NO p1.info[2]["4h"] = constants.NO p1.info[2]["5h"] = constants.NO p1._update_info() self.assertEqual(p1.info[4]["4h"], constants.YES, "Did not conclude player 4 had 4h") self.assertEqual(p1.info[2]["6h"], constants.YES, "Did not conclude player 2 had 2h")
def check_call(self): """ Check if you can call a half suit Returns a list of tuples like this: [(player, card), (player, card) ...] If no call can be made, return False """ for hs in card_utils.gen_all_halfsuits(): call = [] for card in card_utils.find_cards(hs): for ID in self._get_teammates(): if self.info[ID][card] == YES: call.append((ID, card)) if len(call) == HS_SIZE: return call return False
def _check_legal_ask(self, ID_target, card): """ Given a target player and a card to ask, check if the ask is legal Conditions for legality: 1. You must have a card in the same half suit 2. You must not have that card 3. The person you ask must be on the opposite team ID_target: The ID of the person the self wants to ask card: the card that we are checking the legality of """ if ID_target % 2 != self.ID % 2: if self.info[self.ID][card] == NO: for c in card_utils.find_cards( card_utils.find_half_suit(card)): if self.info[self.ID][c] == YES: return True return False
def test_update_call(self): own_hand = ["2h", "3h", "4h", "5h", "6h", "7h", "8h", "9h", "Th"] p1 = Player.player_start_of_game(0, own_hand) p1.update_call("8J", {0: 1, 1: 0, 2: 2, 3: 0, 4: 3, 5: 0}) self.assertEqual(p1.num_cards, { 0: 8, 1: 9, 2: 7, 3: 9, 4: 6, 5: 9 }, "Number of cards is incorrect") for ID in range(constants.NUM_PLAYERS): for card in card_utils.find_cards("8J"): self.assertEqual( p1.info[ID][card], constants.NO, "A player still has a card in the called half suit") self.assertEqual( p1.hs_info[ID]["8J"], 0, "A player is still marked as having at least 1 card in the half suit" )
def force_call(self, hs): """ Forces the player to call the half suit hs. Typically this happens at the end of the game :param hs: half suit that is being forced :return: A "call" list of tuples [(player, card), (player, card) ...] """ call = [] teammates = self._get_teammates() for card in card_utils.find_cards(hs): found = False for ID in range(NUM_PLAYERS): if self.info[ID][card] == YES and ID in teammates: call.append((ID, teammates)) found = True if not found: call.append(teammates[random.randint(0, len(teammates) - 1)], call) return call
def update_call(self, hs, card_count_hs): """ Given a half suit being called, update the player's info and half suit info This essentially sets the info on all players to knowing that they don't have cards in that half suit hs: the half suit being called card_count_hs: the number of cards that each player had in the half suit This is a dictionary of {Player ID: num_cards} Note that there's no difference whether the call succeeds or fails! """ self.remaining_hs.remove(hs) for ID in range(NUM_PLAYERS): for card in card_utils.find_cards(hs): self.info[ID][card] = NO self.public_info[ID][card] = NO self.hs_info[ID][hs] = 0 self.public_hs_info[ID][hs] = 0 self.num_cards[ID] -= card_count_hs[ID] self._update_info() self._update_public_info()
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