def get_chi_dahai(self, chi_action): dahai_dic = {} chi_pai = Pai.from_str(chi_action['pai']) chi_consumed = Pai.from_list(chi_action['consumed']) upper_kuikae_exists = False lower_kuikae_exists = False if chi_consumed[0].number + 1 == chi_consumed[1].number: if chi_pai.number + 1 == chi_consumed[0].number and chi_pai.number != 7: upper_kuikae_exists = True elif chi_pai.number - 2 == chi_consumed[0].number and chi_pai.number != 3: lower_kuikae_exists = True for tehai in self.tehais: if tehai.str in dahai_dic: continue if chi_pai.is_same_symbol(tehai): continue if upper_kuikae_exists and \ tehai.type == chi_pai.type and \ tehai.number - 3 == chi_pai.number: continue if lower_kuikae_exists and \ tehai.type == chi_pai.type and \ tehai.number + 3 == chi_pai.number: continue dahai_dic[tehai.str] = '' return [d for d in dahai_dic.keys()]
def get_score(tehais_num, furos, taken): tehais = [] for i in range(len(tehais_num)): for _ in range(tehais_num[i]): tehais.append(Pai.from_id(i)) taken_index = tehais.index(Pai.from_id(taken)) taken = tehais.pop(taken_index) hora = HoraRs( tehais=tehais, furos=furos, taken=taken, hora_type='tsumo', oya=False, bakaze='E', jikaze='S', doras=[], uradoras=[], reach=len(furos) == 0, double_reach=False, ippatsu=False, rinshan=False, haitei=False, first_turn=False, chankan=False, ) return hora
def main(): import datetime manzu = [1,0,0,1,0,0,0,0,0] pinzu = [0,0,0,0,0,2,2,0,0] souzu = [0,0,0,2,0,0,2,0,0] ji = [0,3,0,0,0,0,0] """ manzu = [1,0,0,0,0,0,0,0,1] pinzu = [1,0,0,0,0,0,0,0,1] souzu = [1,0,3,0,0,0,0,0,1] ji = [1,1,1,1,0,0,1] """ tehai = manzu + pinzu + souzu + ji tehai = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] depth = 3 furo_num = (14-sum(tehai))//3 from mjaigym.board.function.furo import Furo w_pai = Pai.from_str("W") pai_3m =Pai.from_str("3m") furos = [ Furo({"type":"pon", "actor":0, "target":2, "taken":pai_3m, "consumed":[pai_3m,pai_3m]}), # Furo({"type":"pon", "actor":0, "target":2, "taken":w_pai, "consumed":[w_pai,w_pai]}), # Furo({"type":"pon", "actor":0, "target":2, "taken":pai_3m, "consumed":[pai_3m,pai_3m]}), ] assert 13 <= sum(tehai) + 3 * len(furos) <= 14 dfs = Dfs() shanten_normal, shanten_kokushi, shanten_chitoitsu = shanten.get_shanten_all(tehai, len(furos)) start = datetime.datetime.now() for i in range(40): tehai = get_random_tehai() # if 0 <= shanten_normal < depth-1: result = dfs.dfs_with_score_normal(tehai, furos, depth, oya=True, shanten_normal=shanten_normal) # result = dfs.dfs_with_score_chitoitsu(tehai, furos, depth, doras=Pai.from_list(["1m","3m"]), shanten_chitoitsu=shanten_chitoitsu) # result = dfs.dfs_with_score_kokushi(tehai, furos, depth, oya=True, shanten_kokushi=shanten_kokushi) # result = dfs.dfs(tehai, furo_num, depth) end = datetime.datetime.now() print(tehai) for r in result: print(r) pass print(len(result)) print(end - start)
def compare(): import datetime depth = 3 dfs = Dfs() print("start dfs a") start = datetime.datetime.now() manzu = [0,0,0,0,0,0,0,0,0] pinzu = [0,0,0,0,0,0,0,0,0] souzu = [0,0,0,0,0,0,0,0,0] ji = [1,0,0,0,0,3,1] tehai_a = manzu + pinzu + souzu + ji depth = 3 furo_num = (14-sum(tehai_a))//3 from mjaigym.board.function.furo import Furo w_pai = Pai.from_str("W") pai_3m =Pai.from_str("3m") furos = [ Furo({"type":"pon", "actor":0, "target":2, "taken":w_pai, "consumed":[w_pai,w_pai]}), Furo({"type":"pon", "actor":0, "target":2, "taken":w_pai, "consumed":[w_pai,w_pai]}), Furo({"type":"pon", "actor":0, "target":2, "taken":pai_3m, "consumed":[pai_3m,pai_3m]}), ] assert 13 <= sum(tehai_a) + 3 * len(furos) <= 14 shanten_normal, shanten_kokushi, shanten_chitoitsu = shanten.get_shanten_all(tehai_a, len(furos)) result_a = dfs.dfs_with_score_normal(tehai_a, furos, depth, shanten_normal=shanten_normal) # a_changes = set() # for ra in result_a: # a_changes.add(tuple(ra[0])) print("start dfs b") dfs = Dfs() manzu = [0,0,0,0,0,0,0,0,0] pinzu = [0,0,0,0,0,0,0,0,0] souzu = [0,0,0,0,0,0,0,0,0] ji = [1,0,0,0,0,1,3] tehai_b = manzu + pinzu + souzu + ji shanten_normal, shanten_kokushi, shanten_chitoitsu = shanten.get_shanten_all(tehai_b, len(furos)) result_b = dfs.dfs_with_score_normal(tehai_b, furos, depth, shanten_normal=shanten_normal) result_a = sorted(result_a, key=lambda x:x[0]) result_b = sorted(result_b, key=lambda x:x[0]) print(len(result_a)) print(len(result_b)) for i in range(max(len(result_a),len(result_b))): if i >= len(result_b): print(result_a[i][0]) else: print(result_a[i][0], result_b[i][0])
def calc(cls, result:np.array, board_state:BoardState, player_id:int, candidate_furo:Dict, oracle_enable_flag:bool=False): target_index = None if candidate_furo["type"] == MjMove.chi.value: target_index = 0 elif candidate_furo["type"] == MjMove.pon.value: target_index = 1 elif candidate_furo["type"] in [MjMove.kakan.value, MjMove.daiminkan.value, MjMove.ankan.value]: target_index = 2 else: raise Exception("not intended path") result[target_index,:] = 1 pais = [] if candidate_furo["type"] == MjMove.ankan.value: pais += candidate_furo["consumed"] else: pais += ([candidate_furo["pai"]] + candidate_furo["consumed"]) pais = Pai.from_list(pais) min_pai_id = min([pai.id for pai in pais]) result[3,min_pai_id] = 1 contains_red = any([pai.is_red for pai in pais]) if contains_red: result[4,:] = 1
def can_kakan(self, pai:str=None): if self.reach_state == "accepted": return False, [] if pai is None: pons = {} for f in self.furos: if f.type == 'pon': pons[f.pais[0].id] = [p.str for p in f.pais] can_kakan_ids = [p.id for p in self.tehais if p.id in pons] if len(can_kakan_ids) == 0: return False, [] candidates = [] for can_kakan_id in can_kakan_ids: candidate = [p.str for p in self.tehais if p.id == can_kakan_id] # assert len(candidate) == 1 candidates.append([candidate[0], pons[can_kakan_id]]) return True, candidates else: target_pai = Pai.from_str(pai) in_tehai = [p for p in self.tehais if p.is_same_symbol(target_pai)] in_pon = [[p.str for p in f.pais] for f in self.furos if f.type == 'pon' and f.pais[0].is_same_symbol(target_pai)] return len(in_tehai)==1 & len(in_pon)==1, [in_tehai[0], in_pon]
def can_hora(self): previous_action = self.board.previous_action if not previous_action: return False if previous_action['type'] == MjMove.tsumo.value and self.id == previous_action['actor']: hora_type = 'tsumo' pais = self.tehais shanten = self.shanten elif previous_action['type'] in [MjMove.dahai.value, MjMove.kakan.value] and self.id != previous_action['actor']: hora_type = 'ron' pais = self.tehais + [Pai.from_str(previous_action['pai'])] shanten = self.calc_added_shanten(previous_action['pai']) else: return False if shanten != -1: return False action = { 'type':MjMove.hora.value, 'pai':previous_action['pai'], 'actor':self.id, 'target':previous_action['actor'], } hora = self.board.get_hora(action, **{'previous_action':previous_action}) return hora.valid and (hora_type == 'tsumo' or self.furiten == False)
def test_dfs_pattern_chitoitsu(): dfs = Dfs() # chitoitsu pattern nums = [ 0, 2, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, ] dora_ids = [1, 5, 33] doras = [p for p in Pai.from_idlist(dora_ids)] depth = 3 _, _, chitoitsu_shanten = shanten.get_shanten_all(nums, 0) results = dfs.dfs_with_score_chitoitsu( nums, furos=[], depth=depth, shanten_chitoitsu=chitoitsu_shanten, doras=doras, ) result = sorted(results, key=lambda x: x.point_info.points)[-1] print(f"{nums} \n-> {result}, depth:{depth}, {[d.id for d in doras]}") dora_id_contains = False for toitsu in result.combination: dora_id_contains |= toitsu[0] in dora_ids assert dora_id_contains
def can_pon(self, pai:str): if self.reach_state == "accepted": return False, [] target_pai = Pai.from_str(pai) candidates_pai = [t for t in self.tehais if target_pai.is_same_symbol(t)] if len(candidates_pai) < 2: return False, [] red_consumed = ([c for c in candidates_pai if c.is_red]) not_red_consumed = ([c for c in candidates_pai if c.is_red == False]) if len(red_consumed) > 0: if len(candidates_pai) == 2: return True, [ [red_consumed[0].str, not_red_consumed[0].str], ] else: return True, [ [red_consumed[0].str, not_red_consumed[0].str], [not_red_consumed[0].str, not_red_consumed[0].str], ] else: return True, [ [not_red_consumed[0].str, not_red_consumed[1].str] ]
def update_oya(self, renchan, ryukyoku_reason): if renchan == False: self.oya = (self.oya + 1) % self.PLAYER_NUM if self.oya == self.chicha: self.bakaze = Pai.from_str(self.bakaze).succ.str if renchan or ryukyoku_reason: self.honba += 1 else: self.honba = 0 if self.game_type == 'tonpu': self.last = self.decide_last(Pai.from_str('E'), renchan, ryukyoku_reason) elif self.game_type == 'tonnan': self.last = self.decide_last(Pai.from_str('S'), renchan, ryukyoku_reason)
def calc_added_shanten(self, pai:str): pai = Pai.from_str(pai) dahaied_tehai = self.tehais.copy() dahaied_tehai.append(pai) tehai = [0] * 34 for t in dahaied_tehai: tehai[t.id] += 1 return self.shanten_analysis.calc_shanten(tehai, len(self.furos))
def can_daiminkan(self, pai:str): if self.reach_state == "accepted": return False, [] target_pai = Pai.from_str(pai) candidates = [t.str for t in self.tehais if target_pai.is_same_symbol(t)] if len(candidates) < 3: return False, [] else: return True, candidates
def test_dfs_score(): dfs = Dfs() # can add new dora and dora tanki test nums = [ 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, ] dora_ids = [1, 5, 27, 33] doras = [p for p in Pai.from_idlist(dora_ids)] depth = 9 _, _, chitoitsu_shanten = shanten.get_shanten_all(nums, 0) result = dfs.dfs_with_score_chitoitsu( nums, furos=[], depth=3, shanten_chitoitsu=chitoitsu_shanten, doras=doras, ) print(f"{nums} \n-> {result}, depth:{depth}, {[d.id for d in doras]}") assert len(result) > 0
def get_hora(self, action, **params): if action['type'] != MjMove.hora.value: raise Exception('shoud not happen') hora_type = 'tsumo' if action['actor'] == action['target'] else 'ron' if hora_type == 'tsumo': tehais = self.players[action['actor']].tehais[:-1] # remove tsumo else: tehais = self.players[action['actor']].tehais doras = [Pai.from_str(p).succ for p in self.dora_markers] if 'uradora_markers' in params: uradoras = [ Pai.from_str(p).succ for p in params['uradora_markers'] ] else: uradoras = [] hora_player = self.players[action['actor']] # return Hora( return HoraRs( tehais=tehais, furos=hora_player.furos, taken=Pai.from_str(action['pai']), hora_type=hora_type, oya=self.oya == action['actor'], bakaze=self.bakaze, jikaze=self.players[action['actor']].jikaze, doras=doras, uradoras=uradoras, reach=hora_player.reach_state == 'accepted', double_reach=hora_player.double_reach, ippatsu=hora_player.ippatsu_chance, rinshan=hora_player.rinshan, haitei=(self.yama.get_rest_num() == 0) and (hora_player.rinshan == False), first_turn=self.first_turn, chankan=('previous_action' in params) and (params['previous_action']['type'] == MjMove.kakan.value), )
def calc_dahaied_shanten(self, pai:str): pai = Pai.from_str(pai) if pai not in self.tehais: raise Exception(f'tehais not condains pai:{pai}') dahaied_tehai = self.tehais.copy() dahaied_tehai.remove(pai) tehai = [0] * 34 for t in dahaied_tehai: tehai[t.id] += 1 return self.shanten_analysis.calc_shanten(tehai, len(self.furos))
def calc(cls, result:np.array, board_state:BoardState, player_id:int, oracle_enable_flag:bool=False): dora_markers = board_state.dora_markers nums = {} for dora_maker in dora_markers: pai = Pai.from_str(dora_maker) dora_pai = pai.succ if dora_pai.id not in nums: nums[dora_pai.id] = 0 nums[dora_pai.id] += 1 for pai_id, n in nums.items(): if n > 0: result[0:n, pai_id] = 1
def shuntsu_piece(self, first_pai, relative_numbers): if first_pai.type == 'z': return None added = [first_pai.number + r for r in relative_numbers] if any([(1 <= a <= 9) == False for a in added]): return None else: return [Pai( type=first_pai.type, number=first_pai.number+n, is_red=False, pai_str=f"{first_pai.number+n}{first_pai.type}" # this can only for shuntsu ) for n in relative_numbers]
def calc(cls, result: np.array, board_state: BoardState, player_id: int, oracle_enable_flag: bool = False): if board_state.previous_action["type"] != MjMove.dahai.value: return if board_state.previous_action["actor"] != player_id: return last_dahai_pai = Pai.from_str(board_state.previous_action['pai']) result[0, last_dahai_pai.id] = 1 if last_dahai_pai.is_red: result[1, :] = 1
class TenpaiAnalysis: ALL_YAOCHUS = Pai.from_list([ "1m","9m","1p","9p","1s","9s","E","S","W","N","P","F","C", ]) def __init__(self, pais): self.pais = pais self.shanten_analysis = RsShantenAnalysis() self.tehai = [0]*34 for p in pais: self.tehai[p.id] += 1 self.furo_num = (14 - len(pais)) // 3 self.shanten = self.shanten_analysis.calc_shanten(self.tehai, self.furo_num) self.waiting = [] if self.shanten != 0: return for waiting_id in range(34): if self.tehai[waiting_id] == 4: # already use all pais continue self.tehai[waiting_id] += 1 if self.shanten_analysis.calc_shanten(self.tehai, self.furo_num) == -1: self.waiting.append(Pai.from_id(waiting_id)) self.tehai[waiting_id] -= 1 @property def tenpai(self): if self.shanten != 0: return False # assert self.shanten.shanten == 0 return (len(self.pais) % 3 != 1) or (len(self.waited_pais) > 0) @property def waited_pais(self): # assert len(self.pais) % 3 == 1, "invalid number of pais" # assert self.shanten.shanten == 0, "not tenpai" return self.waiting
def register_experience_to_sars(self, experiences: deque): for experience in experiences: # create dahai if experience.action["type"] == MjMove.dahai.value: dahai_actor = experience.action["actor"] player_state = experience.state[dahai_actor] # create dahai s_a_r if player_state.dahai_observation is not None\ and not experience.board_state.reach[dahai_actor]: label = Pai.str_to_id(experience.action["pai"]) self.dahai_queue.append( tuple(( player_state.dahai_observation, label, experience. reward, # already set to actor oriented align reward )))
def think_on_tsumo(self, board_state: BoardState, candidates: List[Dict]): my_tehais = board_state.tehais[self.id] rest_in_view = board_state.restpai_in_view[self.id] # if can hora, always do hora hora_candidates = [ c for c in candidates if c['type'] == MjMove.hora.value ] if len(hora_candidates) == 1: return hora_candidates[0] # if can reach, always do reach reach_candiadtes = [ c for c in candidates if c['type'] == MjMove.reach.value ] if len(reach_candiadtes) == 1: return reach_candiadtes[0] # dahai think dahai_candiadtes = [ c for c in candidates if c['type'] == MjMove.dahai.value ] # calclate the number of shanten reducing tsumo with each dahai node = Node(my_tehais) valid_nums = node.calc_ukeire_num(rest_num=rest_in_view) max_valid_dahai_action = None max_valid_num = -1 for candidate in dahai_candiadtes: valid_dahai_id = Pai.str_to_id(candidate['pai']) valid_num = valid_nums[valid_dahai_id] if max_valid_num < valid_num: max_valid_dahai_action = candidate max_valid_num = valid_num return max_valid_dahai_action
def calc(cls, result:np.array, board_state:BoardState, player_id:int, candidate_furo:Dict, oracle_enable_flag:bool=False): player_tehai = board_state.tehais[player_id] tehais = [0] * 34 for pai in player_tehai: tehais[pai.id] += 1 furo_num = len(board_state.furos[player_id]) current_shanten = cls.shanten_analysis.calc_shanten(tehais, furo_num) # ignore kan if candidate_furo["type"] not in [MjMove.ankan.value, MjMove.daiminkan.value, MjMove.kakan.value]: add_pai = Pai.from_str(candidate_furo["pai"]) tehais[add_pai.id] += 1 added_shanten = cls.shanten_analysis.calc_shanten(tehais, furo_num) if current_shanten > added_shanten: result[0,:,0] = 1 offset = 1 target_channel = max(0,min(6,current_shanten)) + offset result[target_channel, :, 0] = 1
def can_ankan(self, pai:str=None): if pai is None: pai_count = {} for t in self.tehais: if t.id not in pai_count: pai_count[t.id] = 0 pai_count[t.id] += 1 can_ankan_ids = [p for p in pai_count if pai_count[p] == 4] if len(can_ankan_ids) == 0: return False, [] candidates = [] for can_ankan_id in can_ankan_ids: candidate = [p.str for p in self.tehais if p.id == can_ankan_id] candidates.append(candidate) return True, candidates else: in_tehai = [p for p in self.tehais if p.is_same_symbol(Pai.from_str(pai))] return len(in_tehai) == 4, in_tehai
def __init__(self, pais): self.pais = pais self.shanten_analysis = RsShantenAnalysis() self.tehai = [0]*34 for p in pais: self.tehai[p.id] += 1 self.furo_num = (14 - len(pais)) // 3 self.shanten = self.shanten_analysis.calc_shanten(self.tehai, self.furo_num) self.waiting = [] if self.shanten != 0: return for waiting_id in range(34): if self.tehai[waiting_id] == 4: # already use all pais continue self.tehai[waiting_id] += 1 if self.shanten_analysis.calc_shanten(self.tehai, self.furo_num) == -1: self.waiting.append(Pai.from_id(waiting_id)) self.tehai[waiting_id] -= 1
def test_dfs_pattern_chitoitsu_toitsu_tanki(): dfs = Dfs() # can add new dora and dora tanki test nums = [ 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, ] dora_ids = [1, 5, 20, 33] doras = [p for p in Pai.from_idlist(dora_ids)] depth = 3 _, _, chitoitsu_shanten = shanten.get_shanten_all(nums, 0) results = dfs.dfs_with_score_chitoitsu( nums, furos=[], depth=depth, shanten_chitoitsu=chitoitsu_shanten, doras=doras, ) result = sorted(results, key=lambda x: x.point_info.points)[-1] print(f"{nums} \n-> {result}, depth:{depth}, {[d.id for d in doras]}") contains_33 = False contains_1_5_20 = False for toitsu in result.combination: if toitsu[0] in [1, 5, 20]: contains_1_5_20 = True if toitsu[0] == 33: contains_33 = True assert contains_1_5_20 & contains_33
def test_dfs_pattern_kokushi(): dfs = Dfs() # can add new dora and dora tanki test nums = [ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, ] dora_ids = [1, 5, 27, 33] doras = [p for p in Pai.from_idlist(dora_ids)] depth = 3 oya = True _, shanten_kokushi, _ = shanten.get_shanten_all(nums, 0) results = dfs.dfs_with_score_kokushi( nums, furos=[], depth=3, oya=oya, shanten_kokushi=shanten_kokushi, ) print(f"{nums} \n-> {results}, depth:{depth}, {[d.id for d in doras]}") assert len(results) > 0 kokushi_exists = False for result in results: yakus = result.point_info.yakus if any([yaku[0] == "kokushimuso" for yaku in yakus]): kokushi_exists = True assert kokushi_exists
if self.shanten_analysis.calc_shanten(self.tehai, self.furo_num) == -1: self.waiting.append(Pai.from_id(waiting_id)) self.tehai[waiting_id] -= 1 @property def tenpai(self): if self.shanten != 0: return False # assert self.shanten.shanten == 0 return (len(self.pais) % 3 != 1) or (len(self.waited_pais) > 0) @property def waited_pais(self): # assert len(self.pais) % 3 == 1, "invalid number of pais" # assert self.shanten.shanten == 0, "not tenpai" return self.waiting if __name__ == "__main__": pais = Pai.from_list([ "1m","1m","1m","1p","5m","6m","7m","5p","6p","7p","9m","9m","9m", ]) ana = TenpaiAnalysis(pais) print(ana.tenpai) print(ana.waited_pais)
def dfs_with_score_normal( self, tehai:List[int], furos:List[Furo], depth:int, shanten_normal:int, oya:bool=False, bakaze:str="E", jikaze:str="S", doras:List[Pai]=None, uradoras:List[Pai]=None, num_akadoras:int=0, ): if doras is None: doras = [] if uradoras is None: uradoras = [] # print(tehai, len(furos), depth, shanten_normal) results = self.dfs_normal(tehai, len(furos), depth, shanten_normal) # union to min distance unioned_results = {} for result in results: result_tehai = result[0] distance = result[1] if result_tehai in unioned_results: unioned_results[result_tehai] = min(distance, unioned_results[result_tehai]) else: unioned_results[result_tehai] = distance horas = [] dahai_horas = {} for result_tehai, distance in unioned_results.items(): (head, mentsus) = result_tehai # try to use cache changed_tehai_num = [0] * 34 changed_tehai_num[head] += 2 for mentsu in mentsus: for pai in mentsu: changed_tehai_num[pai] += 1 diff = [changed_tehai_num[i] - num for i,num in enumerate(tehai)] # assert sum([d for d in diff if d>0]) <= depth, f"{tehai}, {result_tehai}, {diff}, {distance}" taken_candidate_ids = [i for (i,p) in enumerate(diff) if p > 0] hora_key = ( result_tehai, tuple(sorted(furos)), oya, bakaze, jikaze, tuple(sorted(doras)), tuple(sorted(uradoras)), num_akadoras, tuple(sorted(taken_candidate_ids)), ) if hora_key in self.hora_cash: (max_result, diff) = self.hora_cash[hora_key] horas.append(DfsResult(DfsResultType.Normal, result_tehai, max_result, diff)) continue if len(taken_candidate_ids) == 0: taken_candidate_ids = [i for (i,p) in enumerate(changed_tehai_num) if p > 0] changed_tehais = [] for i, value in enumerate(changed_tehai_num): for _ in range(value): changed_tehais.append(Pai.from_id(i)) taken_changed_results = [] for taken_id in taken_candidate_ids: horra_tehai = copy.copy(changed_tehais) taken_index = horra_tehai.index(Pai.from_id(taken_id)) taken = horra_tehai.pop(taken_index) """ # print(horra_tehai, taken, taken_id) hora = Candidate.from_already_spliteds( head=head, # 9 mentsus=mentsus, # ((1,2,3), (4,5,6), (20,20,20), (32,32,32)) furos=furos, # List[Furo] taken=taken_id, # 20 oya=oya, bakaze=bakaze, jikaze=jikaze, doras=doras, uradoras=uradoras, num_akadoras=num_akadoras, ) """ hora = HoraRs( tehais=horra_tehai, furos=furos, taken=taken, hora_type='tsumo', oya=oya, bakaze=bakaze, jikaze=jikaze, doras=doras, uradoras=uradoras, reach=len(furos)==0, double_reach=False, ippatsu=False, rinshan=False, haitei=False, first_turn=False, chankan=False, num_akadoras=num_akadoras ) # print(hora) taken_changed_results.append(hora) max_result = max(taken_changed_results, key= lambda x:{x.points*1000+x.fan*1000+x.fu}) self.hora_cash[hora_key] = (max_result, diff) horas.append(DfsResult(DfsResultType.Normal, result_tehai, max_result, diff)) return horas
def dfs_with_score_chitoitsu( self, tehai:List[int], furos:List[Furo], depth:int, shanten_chitoitsu:int, oya:bool=False, bakaze:str="E", jikaze:str="S", doras:List[Pai]=None, uradoras:List[Pai]=None, num_akadoras:int=0, ): if doras is None: doras = [] if uradoras is None: uradoras = [] horas = [] results = self.dfs_chitoitsu(tehai, depth, doras, shanten_chitoitsu) for result in results: tehais = [] toitsus = result for i, toitsu in enumerate(toitsus): tehais.append(Pai.from_id(toitsu[0])) tehais.append(Pai.from_id(toitsu[1])) if len(tehais) > 0: taken = tehais.pop() else: taken = None # print(horra_tehai, taken, taken_id) """ hora = Candidate.from_already_splited_chitoitsu( tehais=tehais, furos=furos, # List[Furo] taken=taken, oya=oya, bakaze=bakaze, jikaze=jikaze, doras=doras, uradoras=uradoras, num_akadoras=num_akadoras, ) """ hora = HoraRs( tehais=tehais, furos=furos, taken=taken, hora_type='tsumo', oya=oya, bakaze=bakaze, jikaze=jikaze, doras=doras, uradoras=uradoras, reach=len(furos)==0, double_reach=False, ippatsu=False, rinshan=False, haitei=False, first_turn=False, chankan=False, num_akadoras=num_akadoras ) nums = [0] * 34 nums[taken.id] += 1 for t in tehais: nums[t.id] += 1 diff = [nums[i] - tehai[i] for i in range(34)] horas.append(DfsResult(DfsResultType.Chitoitsu, toitsus, hora, diff)) return horas
def tsumo(self, pai: str): self._consumed_num += 1 if pai == UNKNOWN_PAI_STR: return self.rest.remove(Pai.from_str(pai))