def test_threatening_riichi_player_and_not_early_hand_bonus(): table = Table() enemy_seat = 2 discards = string_to_136_array(sou="1111222") for discard in discards: table.add_discarded_tile(enemy_seat, discard, False) table.add_called_riichi_step_one(enemy_seat) table.add_called_riichi_step_two(enemy_seat) table.get_player(enemy_seat).is_ippatsu = False # +1 scale for riichi on 6+ turn threatening_player = table.player.ai.defence.get_threatening_players()[0] assert threatening_player.enemy.seat == enemy_seat assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="2")) == 3900
def test_threatening_riichi_player_middle_tiles_bonus(): table = Table() enemy_seat = 2 table.add_called_riichi_step_one(enemy_seat) table.add_called_riichi_step_two(enemy_seat) table.get_player(enemy_seat).is_ippatsu = False # +1 scale 456 tiles threatening_player = table.player.ai.defence.get_threatening_players()[0] assert threatening_player.enemy.seat == enemy_seat # +1 scale 456 tiles assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="4"), can_be_used_for_ryanmen=True) == 3900 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="5"), can_be_used_for_ryanmen=True) == 3900 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="6"), can_be_used_for_ryanmen=True) == 3900 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="5"), can_be_used_for_ryanmen=False) == 3900 # +1 scare for 2378 tiles that could be used in ryanmen assert threatening_player.get_assumed_hand_cost( string_to_136_tile(pin="2"), can_be_used_for_ryanmen=True) == 3900 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(pin="2"), can_be_used_for_ryanmen=False) == 2000 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(sou="7"), can_be_used_for_ryanmen=True) == 3900 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(sou="7"), can_be_used_for_ryanmen=False) == 2000 # not middle tiles assert threatening_player.get_assumed_hand_cost( string_to_136_tile(man="1"), can_be_used_for_ryanmen=True) == 2000 assert threatening_player.get_assumed_hand_cost( string_to_136_tile(pin="9"), can_be_used_for_ryanmen=True) == 2000
def reproduce(self, player, wind, honba, needed_tile, action, tile_number_to_stop): player_position = self._find_player_position(player) round_content = self._find_needed_round(wind, honba) draw_tags = ["T", "U", "V", "W"] discard_tags = ["D", "E", "F", "G"] player_draw = draw_tags[player_position] player_draw_regex = re.compile(r"^<[{}]+\d*".format( "".join(player_draw))) discard_regex = re.compile(r"^<[{}]+\d*".format("".join(discard_tags))) draw_regex = re.compile(r"^<[{}]+\d*".format("".join(draw_tags))) last_draws = {0: None, 1: None, 2: None, 3: None} table = Table() # TODO get this info from log content table.has_aka_dora = True table.has_open_tanyao = True table.player.init_logger(self.logger) players = {} for round_item in self.rounds: for tag in round_item: if "<UN" in tag: players_temp = self.decoder.parse_names_and_ranks(tag) if players_temp: for x in players_temp: players[x["seat"]] = x draw_tile_seen_number = 0 enemy_discard_seen_number = 0 for tag in round_content: if player_draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) table.count_of_remaining_tiles -= 1 # is it time to stop reproducing? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile if action == "draw" and found_tile: draw_tile_seen_number += 1 if draw_tile_seen_number == tile_number_to_stop: self.logger.info("Stop on player draw") discard_result = None with_riichi = False table.player.draw_tile(tile) table.player.should_call_kan( tile, open_kan=False, from_riichi=table.player.in_riichi) if not table.player.in_riichi: discard_result = table.player.discard_tile() with_riichi = table.player.can_call_riichi() return discard_result, with_riichi table.player.draw_tile(tile) if "INIT" in tag: values = self.decoder.parse_initial_values(tag) shifted_scores = [] for x in range(0, 4): shifted_scores.append( values["scores"][self._normalize_position( player_position, x)]) table.init_round( values["round_wind_number"], values["count_of_honba_sticks"], values["count_of_riichi_sticks"], values["dora_indicator"], self._normalize_position(values["dealer"], player_position), shifted_scores, ) hands = [ [ int(x) for x in self.decoder.get_attribute_content( tag, "hai0").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai1").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai2").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai3").split(",") ], ] table.player.init_hand(hands[player_position]) table.player.name = players[player_position]["name"] self.logger.info("Init round info") self.logger.info(table.player.name) self.logger.info(f"Scores: {table.player.scores}") self.logger.info( f"Wind: {DISPLAY_WINDS[table.player.player_wind]}") if "DORA hai" in tag: table.add_dora_indicator( int(self._get_attribute_content(tag, "hai"))) if draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) player_sign = tag.upper()[1] player_seat = self._normalize_position( draw_tags.index(player_sign), player_position) last_draws[player_seat] = tile if discard_regex.match(tag) and "DORA" not in tag: tile = self.decoder.parse_tile(tag) player_sign = tag.upper()[1] player_seat = self._normalize_position( discard_tags.index(player_sign), player_position) if player_seat == 0: table.player.discard_tile(tile, force_tsumogiri=True) else: # is it time to stop? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile is_kamicha_discard = player_seat == 3 if action == "enemy_discard" and found_tile: enemy_discard_seen_number += 1 if enemy_discard_seen_number == tile_number_to_stop: self.logger.info("Stop on enemy discard") self._rebuild_bot_shanten_cache(table.player) table.player.should_call_kan(tile, open_kan=True, from_riichi=False) return table.player.try_to_call_meld( tile, is_kamicha_discard) is_tsumogiri = last_draws[player_seat] == tile table.add_discarded_tile(player_seat, tile, is_tsumogiri=is_tsumogiri) if "<N who=" in tag: meld = self.decoder.parse_meld(tag) player_seat = self._normalize_position(meld.who, player_position) table.add_called_meld(player_seat, meld) if player_seat == 0: if meld.type != MeldPrint.KAN and meld.type != MeldPrint.SHOUMINKAN: table.player.draw_tile(meld.called_tile) if "<REACH" in tag and 'step="1"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_one(who_called_riichi) if "<REACH" in tag and 'step="2"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_two(who_called_riichi)