Example #1
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
                        )))
Example #2
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
Example #3
0
    def restnum_update(self, action):
        if action is None or "type" not in action:
            return

        if action["type"] == MjMove.start_kyoku.value:
            # initialize
            self.rest_pai_view = [[4] * 34 for _ in range(4)]

            dora_marker_id = Pai.str_to_id(action["dora_marker"])
            for i in range(4):
                self.rest_pai_view[i][dora_marker_id] -= 1
                for pai in action["tehais"][i]:
                    pai_id = Pai.str_to_id(pai)
                    self.rest_pai_view[i][pai_id] -= 1

        elif action["type"] == MjMove.tsumo.value:
            pai_id = Pai.from_str(action["pai"]).id
            actor = action["actor"]
            self.rest_pai_view[actor][pai_id] -= 1

        elif action["type"] == MjMove.dahai.value:
            pai_id = Pai.from_str(action["pai"]).id
            actor = action["actor"]
            for i in range(4):
                if actor != i:
                    self.rest_pai_view[i][pai_id] -= 1

        elif action["type"] == MjMove.dora.value:
            pai_id = Pai.from_str(action["dora_marker"]).id
            for i in range(4):
                self.rest_pai_view[i][pai_id] -= 1

        elif action["type"] == MjMove.chi.value:
            actor = action["actor"]
            for i in range(4):
                if actor != i:
                    for consume in action["consumed"]:
                        self.rest_pai_view[i][Pai.str_to_id(consume)] -= 1

        elif action["type"] == MjMove.pon.value:
            actor = action["actor"]
            for i in range(4):
                if actor != i:
                    for consume in action["consumed"]:
                        self.rest_pai_view[i][Pai.str_to_id(consume)] -= 1

        elif action["type"] == MjMove.daiminkan.value:
            actor = action["actor"]
            for i in range(4):
                if actor != i:
                    for consume in action["consumed"]:
                        self.rest_pai_view[i][Pai.str_to_id(consume)] -= 1

        elif action["type"] == MjMove.ankan.value:
            actor = action["actor"]
            for i in range(4):
                if actor != i:
                    for consume in action["consumed"]:
                        self.rest_pai_view[i][Pai.str_to_id(consume)] -= 1

        elif action["type"] == MjMove.kakan.value:
            actor = action["actor"]
            pai_id = Pai.str_to_id(action["pai"])
            for i in range(4):
                if actor != i:
                    self.rest_pai_view[i][pai_id] -= 1
Example #4
0
    def update_state(self, action):
        if self.board.previous_action is not None and \
                self.board.previous_action['type'] in [MjMove.dahai.value, MjMove.kakan.value] and \
                'actor' in self.board.previous_action and \
                self.board.previous_action['actor'] != self.id and \
                action['type'] != MjMove.hora.value:
            
            self.extra_anpais.append(Pai.from_str(self.board.previous_action['pai']))





        action_type = action['type']

        if action_type == MjMove.start_game.value:
            if not self.id and 'id' in action:
                self.id = action['id']
                self.name = f"player{self.id}"
            if 'names' in action:
                self.name = action['names'][self.id]
            self.score = 25000
            self.tehais = []
            self.furos = []
            self.ho = []
            self.sutehais = []
            self.extra_anpais = []
            self.reach_state = None
            self.reach_ho_index = None
            self.reach_sutehais_index = None
            self.double_reach = False
            self.ippatsu_chance = False
            self.pao_for_id = None
            self.rinshan = False

        elif action_type == MjMove.start_kyoku.value:
            self.tehais = sorted(Pai.from_list(action['tehais'][self.id]))
            
            self.furos = []
            self.ho = []
            self.sutehais = []
            self.extra_anpais = []
            self.reach_state = "none"
            self.reach_ho_index  = None
            self.reach_sutehais_index = None
            self.double_reach = False
            self.ippatsu_chance = False
            self.pao_for_id = None
            self.rinshan = False

        elif action_type in [
            MjMove.chi.value,
            MjMove.pon.value, 
            MjMove.daiminkan.value, 
            MjMove.ankan.value
            ]:
            self.ippatsu_chance = False
        elif action_type == MjMove.tsumo.value:
            if self.board.previous_action['type'] == MjMove.kakan.value:
                self.ippatsu_chance = False


        if 'actor' in action and action['actor'] == self.id:
            if action_type == MjMove.tsumo.value:
                pai = Pai.from_str(action['pai'])
                self.tehais = sorted(self.tehais)
                self.tehais.append(pai)
            elif action_type == MjMove.dahai.value:
                pai = Pai.from_str(action['pai'])
                self.delete_tehai(pai)
                self.tehais = sorted(self.tehais)
                self.ho.append(pai)
                self.sutehais.append(pai)
                self.ippatsu_chance = False
                self.rinshan = False
                if self.reach == False:
                    self.extra_anpais.clear()
            elif action_type in [
                MjMove.chi.value, 
                MjMove.pon.value, 
                MjMove.daiminkan.value, 
                MjMove.ankan.value
                ]:

                consumed_pais = Pai.from_list(action['consumed'])
                for c in consumed_pais:
                    self.delete_tehai(c)

                furo = {
                        'type':action['type'],
                        'consumed':consumed_pais,   
                    }
                if action_type != MjMove.ankan.value:
                    pai = Pai.from_str(action['pai'])
                    furo['taken'] = pai

                if action_type == MjMove.chi.value:                    
                    furo['pai_id'] = min(
                        Pai.str_to_id(action['pai']),
                        min(
                            Pai.str_to_id(action['consumed'][0]), 
                            Pai.str_to_id(action['consumed'][1]))
                    )
                else:
                    furo['pai_id'] = Pai.str_to_id(action['consumed'][0])

                if action_type == MjMove.ankan.value:
                    furo['target'] = self.id
                else:
                    furo['target'] = action['target']

                self.furos.append(Furo(furo))
                if action_type in [MjMove.daiminkan.value, MjMove.ankan.value]:
                    self.rinshan = True

                # pao
                if action_type in [MjMove.daiminkan.value, MjMove.pon.value]:
                    pai = Pai.from_str(action['pai'])
                    if pai.is_sangenpai():
                        if self.is_daisangen_pao():
                            self.pao_for_id = action['target']
                    elif pai.is_wind():
                        if self.is_daisushi_pao():
                            self.pao_for_id = action['target']
            
            elif action_type == MjMove.kakan.value:
                pai = Pai.from_str(action['pai'])
                self.delete_tehai(pai)
                pon_index = -1
                for i,f in enumerate(self.furos):
                    if f.type == MjMove.pon.value and pai.is_same_symbol(f.taken):
                        pon_index = i
                if pon_index == -1:
                    raise Exception('not have same symbole pon')
                self.furos[pon_index] = Furo({
                    'type':MjMove.kakan.value,
                    'taken':self.furos[pon_index].taken,
                    'consumed':self.furos[pon_index].consumed + [pai],
                    'target':self.furos[pon_index].target,
                    'pai_id':self.furos[pon_index].pai_id,
                })
                self.rinshan = True
            
            elif action_type == MjMove.reach.value:
                self.reach_state = 'declared'
                self.double_reach = self.board.first_turn
            
            elif action_type == MjMove.reach_accepted.value:
                self.reach_state = 'accepted'
                self.reach_ho_index = len(self.ho)-1
                self.reach_sutehais_index = len(self.sutehais)-1
                self.ippatsu_chance = True
                
        
        if 'target' in action and action['target'] == self.id:
            pai = Pai.from_str(action['pai'])
            if action_type in [
                MjMove.pon.value,
                MjMove.chi.value, 
                MjMove.daiminkan.value
                ]:
                taken = self.ho.pop()
                # assert taken == pai
        
        if 'scores' in action:
            self.score = action['scores'][self.id]