Пример #1
0
    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()]
Пример #2
0
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
Пример #3
0
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)
Пример #4
0
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
Пример #6
0
    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]
Пример #7
0
    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)
Пример #8
0
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
Пример #9
0
    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]
                ]
Пример #10
0
    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)
Пример #11
0
    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))
Пример #12
0
 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
Пример #13
0
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
Пример #14
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),
        )
Пример #15
0
    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))
Пример #16
0
 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
Пример #17
0
 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]
Пример #18
0
    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
Пример #19
0
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
Пример #20
0
    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
                        )))
Пример #21
0
    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
Пример #23
0
    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
Пример #24
0
    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
Пример #25
0
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
Пример #26
0
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
Пример #27
0
            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)
Пример #28
0
    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
Пример #29
0
    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
Пример #30
0
    def tsumo(self, pai: str):
        self._consumed_num += 1
        if pai == UNKNOWN_PAI_STR:
            return

        self.rest.remove(Pai.from_str(pai))