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 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
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]