def pb2struct(self, frame_state, last_action):
        obs, _ = frame_state
        self.step_no = obs["frame_state"]["step_no"]

        hero = obs["frame_state"]["heroes"][0]
        self.cur_pos = (hero["pos"]["x"], hero["pos"]["z"])

        # History position
        # 历史位置
        self.history_pos.append(self.cur_pos)
        if len(self.history_pos) > 10:
            self.history_pos.pop(0)

        # End position
        # 终点位置
        for organ in obs["frame_state"]["organs"]:
            if organ["sub_type"] == 4:
                end_pos_dis = RelativeDistance[organ["relative_pos"]["l2_distance"]]
                end_pos_dir = RelativeDirection[organ["relative_pos"]["direction"]]
                self.end_status = organ["status"]  # 保存終點狀態
                
                if organ["status"] != -1:
                    self.end_pos = (organ["pos"]["x"], organ["pos"]["z"])
                    self.is_end_pos_found = True
                # if end_pos is not found, use relative position to predict end_pos
                # 如果终点位置未找到，使用相对位置预测终点位置
                elif (not self.is_end_pos_found) and (
                    self.end_pos is None
                    or self.step_no % 100 == 0
                    or self.end_pos_dir != end_pos_dir
                    or self.end_pos_dis != end_pos_dis
                ):
                    distance = end_pos_dis * 20
                    theta = DirectionAngles[end_pos_dir]
                    delta_x = distance * math.cos(math.radians(theta))
                    delta_z = distance * math.sin(math.radians(theta))

                    self.end_pos = (
                        max(0, min(128, round(self.cur_pos[0] + delta_x))),
                        max(0, min(128, round(self.cur_pos[1] + delta_z))),
                    )

                    self.end_pos_dir = end_pos_dir
                    self.end_pos_dis = end_pos_dis

        self.last_pos_norm = self.cur_pos_norm
        self.cur_pos_norm = norm(self.cur_pos, 128, -128)
        self.feature_end_pos = self._get_pos_feature(self.is_end_pos_found, self.cur_pos, self.end_pos)

        # History position feature
        # 历史位置特征
        self.feature_history_pos = self._get_pos_feature(1, self.cur_pos, self.history_pos[0])

        # 更新狀態信息用於reward計算
        current_end_dist = self.feature_end_pos[-1] if self.end_pos else float('inf')
        
        # 記錄距離變化
        if self.last_end_dist is not None:
            distance_change = self.last_end_dist - current_end_dist
            self.progress_history.append(distance_change)
            if len(self.progress_history) > 10:
                self.progress_history.pop(0)
        
        self.last_end_dist = current_end_dist
        
        # 追蹤已訪問位置
        pos_key = (round(self.cur_pos[0]), round(self.cur_pos[1]))
        self.visited_positions.add(pos_key)
        
        # 檢測是否卡住
        if len(self.history_pos) >= 3:
            recent_pos = self.history_pos[-3:]
            if all(np.linalg.norm(np.array(pos) - np.array(self.cur_pos)) < 2 for pos in recent_pos):
                self.stuck_counter += 1
            else:
                self.stuck_counter = 0

        self.move_usable = True
        
        # 更新閃現冷卻狀態
        if self.flash_cooldown > 0:
            self.flash_cooldown -= 1
            self.flash_usable = False
        else:
            self.flash_usable = True
            
        # 如果上一個動作是閃現動作（8-15），啟動冷卻
        if last_action >= 8 and last_action <= 15:
            self.flash_cooldown = 100  # 根據環境配置設置冷卻時間
            self.flash_usable = False
            
        self.last_action = last_action

詳細代碼解釋