def get_combination_to_play(self, trick, wish=None): combination_to_play = None if Mahjong() in self.hand.cards: return Combination(cards_list=[Mahjong()]) # if there is a trick being played last_play = trick.get_last_play() if last_play: last_combination = last_play.combination combination_to_play = self.hand.find_lowest_combination( last_combination.level, last_combination.type) # If we are leading else: for combination_type in self.lead_preference: # -1 otherwise the dog is never played combination_to_play = self.hand.find_lowest_combination( -1, combination_type) # as soon as a combination is found, play it if combination_to_play: break return combination_to_play
def run_game(self): # Until 3 players are out # Game self.exchange_cards() for player in self.players: if Mahjong() in player.hand.cards: self.lead_player = player break #TODO How to decide lead player else: self.lead_player = self.players[0] while not self.is_game_over(): print('', '### new trick with players %s' % (', '.join(['%s (%spts)' % (player.name, player.points) for player in self.get_player_still_game()])), '### leading player is %s' % self.lead_player, '### trick - %s' % self.present_trick, '', sep='\n') # Take action from the lead player self.get_player_action(self.lead_player) # Check if game is over if self.is_game_over(): continue self.check_for_bomb() # Initialize the rolling cycle of player player_iterator = self.next_active_player() if self.lead_player.is_out(): self.lead_player = next(player_iterator) continue active_player = next(player_iterator) # Until somebody wins the hand while not self.present_trick.is_over() and not self.is_game_over(): player_action = self.get_player_action(active_player) if not player_action.has_passed(): # Check if game is over if self.is_game_over(): break self.check_for_bomb() if self.lead_player.is_out(): self.lead_player = next(player_iterator) self.check_for_bomb() active_player = next(player_iterator) self.end_of_trick()
def assert_valid(self): if self.action_type == ActionsType.play: if self.combination is None: raise IllegalAction('a play must come with cards') if self.action_type == ActionsType.passes: if self.combination is not None: raise IllegalAction('No cards can be played while passing') if self.wish is not None: if self.combination is None and Mahjong() not in self.combination: raise IllegalAction('Must play the Mahjong to wish for a card')
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 play(self, trick: Trick, wish=None): combination_to_play = self.get_combination_to_play(trick, wish) if combination_to_play is not None: self.hand -= combination_to_play self.hand_size -= combination_to_play.size if Mahjong() in combination_to_play.cards: return Action.play(player=self, combination=combination_to_play, wish=self.wish) else: return Action.play(player=self, combination=combination_to_play) else: # Empty action means passing return Action.passes(player=self)
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 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