def find_multiple(cards: Cards, level_to_beat: int, cards_to_find: int): """ :param cards: :param level_to_beat: :param cards_to_find: :rtype: Combination """ if cards_to_find <= 0 or cards_to_find > 4: raise ValueError('Illegal combination_type %s' % cards_to_find) if cards_to_find == 1: for card in (cards - Phoenix()).cards: if card.power > level_to_beat: return Combination(cards_list=[card]) # if no card could have been player, try to take the lead with your Phoenix # Phoenix can not be played on a Dragon if cards.phoenix_flag and level_to_beat < Dragon().power: return Combination(cards_list=[Phoenix()]) # TODO - TO REFACTOR WITH LOGIC if cards_to_find == 2: for i in range(len(cards.cards) - 1): card = cards.cards[i] if card.power > level_to_beat and card.power == cards.cards[ i + 1].power: return Cards(cards_list=[card, cards.cards[i + 1]]) if cards_to_find == 3: for i in range(len(cards.cards) - 2): card = cards.cards[i] if card.power > level_to_beat and card.power == cards.cards[ i + 2].power: return Cards(cards_list=[ card, cards.cards[i + 1], cards.cards[i + 2] ]) if cards_to_find == 4: for i in range(len(cards.cards) - 3): card = cards.cards[i] if card.power > level_to_beat and card.power == cards.cards[ i + 3].power: return Cards(cards_list=[ card, cards.cards[i + 1], cards.cards[i + 2], cards.cards[i + 3] ]) # If no combination found, try to use Phoenix to play if cards.phoenix_flag and 1 <= cards_to_find < 4 and cards.size > 1: return Hand.find_multiple(cards - Phoenix(), level_to_beat, cards_to_find - 1) + Phoenix()
def find_straight(cards, level_to_beat, length=None, bomb=False): """ 1/ Start at level_to_beat - length +2: if level_to_beat is 10, length 6, their straight starts at 5, your straight has to start at 6 2/ see if you can find a straight that beats that 3/ see if you can find a length-1 straight at level_to_beat -1 """ # Get all possible start points for the straight if length is None: length = 5 elif length <= 0: return None start_point = max(1, level_to_beat - length + 2) max_strength_power = Dragon().power - 1 max_start_point = max_strength_power - length + 2 start_points = range(start_point, max_start_point + 1) for card in cards.cards: for start in start_points: if card.power == start: if length == 1: return Cards(cards_list=[card]) else: # TODO - jump in straights # Issue constantly increasing threshold rest = Hand.find_straight(cards - card, card.power + length - 2, length - 1, bomb=bomb) # TODO BOMB if rest: if not rest.phoenix_flag: if min(rest.cards).power == card.power + 1: return rest + card elif (len(rest.cards) == 1 and Phoenix() in rest.cards) or min( (rest - Phoenix() ).cards).power <= card.power + 2: return rest + card if cards.phoenix_flag: if length == 1: return Cards(cards_list=[Phoenix()]) rest = Hand.find_straight(cards - Phoenix(), level_to_beat, length - 1, bomb=bomb) if rest: return rest + Phoenix()
def find_all_multiples(cards: Cards, multiple: int): cards = cards - Dog() - Dragon() buckets = Cards.bucketize_hands(cards.cards) multiples = [] for level in range(Mahjong().power + 1, Dragon().power): cards_this_level = buckets[level] if (Phoenix().power in buckets.keys()) and (multiple != 4): cards_this_level.append(Phoenix()) if len(cards_this_level) > 1: for pair in itertools.combinations(cards_this_level, multiple): multiples.append(Combination(cards_list=list(pair))) return multiples
def __init__(self, cards_list: list = None, cards_dict_list: list = None, cards_string: str = None): # Get phoenix, get type, get level new_cards_list = None if cards_string is not None: new_cards_list = self.parse_string(cards_string) if cards_dict_list is not None: new_cards_list = [ Card(card_dict=card_dict) for card_dict in cards_dict_list ] if new_cards_list is not None: Cards.__init__(self, cards_list=new_cards_list) return # TODO - Should we break on empty cards list # if cards_list is None or len(cards_list) == 0: # raise ValueError('Empty cards list') # Check that we do not have duplicates if len(set(cards_list)) != len(cards_list): raise ValueError('duplicated cards') cards_list.sort() self.cards = cards_list self.size = len(cards_list) self.phoenix_flag = Phoenix() in self.cards
def get_type(self): phoenixless_combination = [card for card in self.cards if card != Phoenix()] combination = [card for card in self.cards] phoenixless_combination_size = len(phoenixless_combination) if phoenixless_combination_size == 0: self.type = 'SINGLE' return if Dog() in phoenixless_combination and len(combination) > 1: raise ValueError('Dog is played alone') if Dragon() in phoenixless_combination and len(combination) > 1: raise ValueError('Dragon is played alone') if Mahjong() in phoenixless_combination and len(combination) == 2 and self.phoenix_flag: raise ValueError('No pairs with Mahjong') distinct_values = list(set([card.power for card in phoenixless_combination])) number_of_values_except_ph = len(distinct_values) distinct_suits = list(set([card.suit for card in phoenixless_combination])) number_of_suits = len(distinct_suits) value_span = max(distinct_values) - min(distinct_values) + 1 if number_of_values_except_ph == 1: if phoenixless_combination_size == 1: if not self.phoenix_flag: self.type = 'SINGLE' else: self.type = 'PAIR' self.get_phoenix().set_power(max(distinct_values)) return if phoenixless_combination_size == 2: if not self.phoenix_flag: self.type = 'PAIR' else: self.type = 'TRIO' self.get_phoenix().set_power(max(distinct_values)) return if phoenixless_combination_size == 3: self.type = 'TRIO' return if phoenixless_combination_size == 4 and not self.phoenix_flag: self.type = 'SQUAREBOMB' return elif phoenixless_combination_size == number_of_values_except_ph and len(combination) >= 5: if self.phoenix_flag: if value_span == phoenixless_combination_size: self.type = 'STRAIGHT' self.get_phoenix().set_power(max(distinct_values) + 1) return elif value_span == phoenixless_combination_size + 1: # it is a straight with the phoenix in the middle self.type = 'STRAIGHT' # Not assigning level because of no interest return else: raise ValueError('Incoherent Straight') if not self.phoenix_flag: if value_span != phoenixless_combination_size: raise ValueError('Incoherent Straight') if number_of_suits == 1: self.type = 'STRAIGHTBOMB' return else: self.type = 'STRAIGHT' return # STEPS AND FULLHOUSE elif phoenixless_combination_size / 2 == number_of_values_except_ph: if self.phoenix_flag and phoenixless_combination_size == 4: self.type = 'FULLHOUSE' # Not assigning level because of no interest return elif value_span == phoenixless_combination_size / 2: self.type = 'STEPS' return # TODO [Phoenix, 2_Pa, 3_Pa, 4_Pa, 5_Pa, 5_Sw, 5_Ja, 5_St] not working elif value_span == phoenixless_combination_size // 2 + 1 and phoenixless_combination_size % 2 == 1 and self.phoenix_flag: self.type = 'STEPS' # Not assigning level because of no interest return elif number_of_values_except_ph == 2 and phoenixless_combination_size == 5 and not self.phoenix_flag: self.type = 'FULLHOUSE' return raise ValueError('Unknown Combination %s' % self)
def test_pairs_with_phoenix(self): cards = [Card(name='2', suit='Pagoda'), Phoenix()] combination = Combination(cards_list=cards) self.assertEqual(combination.type, 'PAIR') self.assertEqual(combination.level, 2)
Card(name='5', suit='Jade'), Card(name='5', suit='Star'), # Card(name='4', suit='Pagoda'), # Card(name='4', suit='Star'), # Card(name='5', suit='Star'), # Card(name='5', suit='Jade'), # Card(name='5', suit='Pagoda'), # Card(name='5', suit='Sword'), # Card(name='7', suit='Star'), # Card(name='8', suit='Star'), # Card(name='6', suit='Star'), # Card(name='9', suit='Star'), # Card(name='4', suit='Star'), # Card(name='4', suit='Pagoda'), # Card(name='4', suit='Pagoda'), Phoenix(), # Dog(), # Mahjong(), # Mahjong(), # Dragon(), ] test = [1, 2, 3, 4] d = Dragon() hand1 = Hand(cards_string='K_Pa, K_Sw') hand2 = Hand(cards_string='Phoenix, A_Pa, Q_Pa') hand3 = Hand(cards_string='K_Pa, Mahjong, 2_Pa, 3_Pa, 4_Pa, 5_Pa, 6_Pa') hand4 = Hand(cards_string='J_Pa') # players = [DumbAI(hand1, 'AI1'), DumbAI(hand2, 'AI2'), DumbAI(hand3, 'AI3'), DumbAI(hand4, 'AI4')] # players = [DumbAI(Hand(), 'AI1'), DumbAI(Hand(), 'AI2'), DumbAI(Hand(), 'AI3'), DumbAI(Hand(), 'AI4')]
def find_all_straights(cards: Cards): #TODO fix levels #TODO, put the level in there to differentiate phoenix at start and end #TODO Sort the combinations # remove Dog and Dragon from any straights cards = cards - Dog() - Dragon() buckets = Cards.bucketize_hands(cards.cards) power_values = buckets.keys() possible_straights_power_values = [] # Get all possible power combinations for start in range(Mahjong().power, Dragon().power): length = 0 current_straight_values = [] for next_value in range(start, Dragon().power): found = False new_value = None if next_value in power_values: found = True new_value = next_value elif Phoenix().power in power_values and Phoenix( ).power not in current_straight_values: if next_value != 1: found = True new_value = Phoenix().power if found and new_value not in current_straight_values: current_straight_values.append(new_value) length += 1 if length >= 5: possible_straights_power_values.append( current_straight_values.copy()) elif not found: break # Now that we have the powers, we get all possible straights straights = [] for straight in possible_straights_power_values: straight_cards = [buckets[power] for power in straight] for combinations in itertools.product(*straight_cards): # straights.append(Cards(cards_list=list(combinations))) straights.append(Combination(cards_list=list(combinations))) # We replace the phoenix in all the straights where we can new_straights = [] for straight in straights: if Phoenix() not in straight.cards: for card in straight.cards: if not card == Mahjong(): new_cards = straight - card + Phoenix() new_combo = Combination(cards_list=new_cards.cards) new_straights.append(new_combo) # new_straights.append(straight - card + Phoenix()) straights.extend(new_straights) straights.sort() return straights