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 __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 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 from_already_spliteds( cls, head, # 9 mentsus, # ((1,2,3), (4,5,6), (20,20,20), (32,32,32)) furos, # List[Furo] taken, # 20 oya, bakaze, jikaze, doras, uradoras, num_akadoras, ): # need before calclate dora pais_buffer = Pai.from_idlist([head, head]) for mentsu in mentsus: pais_buffer.extend(Pai.from_idlist(list(mentsu))) free_pais = copy.copy(pais_buffer) for furo in furos: pais_buffer.extend(furo.pais) all_pais = pais_buffer is_menzen = len([f for f in furos if f.type != 'ankan']) == 0 taken = Pai.from_id(taken) num_doras = Hora.count_doras(all_pais, doras) num_uradoras = Hora.count_doras(all_pais, uradoras) # num_akadora need calclate outside. num_same_as_taken = len([f for f in free_pais if taken.is_same_symbol(f)]) combination = [ ["toitsu", Pai.from_idlist([head,head])], ] for mentsu in mentsus: if mentsu[0] == mentsu[1]: combination.append(["kotsu", Pai.from_idlist(mentsu)]) else: combination.append(["shuntsu", Pai.from_idlist(mentsu)]) hora_yaku_information = HoraYakuInformation( taken=taken, all_pais=all_pais, hora_type="tsumo", oya=oya, first_turn=False, num_doras=num_doras, num_uradoras=num_uradoras, num_akadoras=num_akadoras, reach=is_menzen, ippatsu=False, rinshan=False, chankan=False, haitei=False, double_reach=False, furos=furos, jikaze=jikaze, bakaze=bakaze, ) candidates = [] for i in range(num_same_as_taken): candidates.append(Candidate(hora_yaku_information, combination, i)) if len(candidates) > 0: best_candidate = max(candidates, key=lambda x:(x.fan, x.points)) if best_candidate.valid: return HoraInfo( fu=best_candidate.fu, fan=best_candidate.fan, yakus=best_candidate.yakus, points=best_candidate.points, oya_payment=best_candidate.oya_payment, ko_payment=best_candidate.ko_payment, ) return HoraInfo( fu=0, fan=0, yakus=[], points=0, oya_payment=0, ko_payment=0 )