庙算兵棋推演AI开发初探(支线-AI平台注意及tips)

总是停留在stage阶段一的问题

输出回放数据,在显示中发现一动不动,发现stage字段一直是1部署阶段……

解决方法:

  • 代码层面需要有type=333的行为告诉引擎部署完毕。
  • pip卸载重装兵棋引擎

这个我每次关机后都得重新来一遍,很讨厌(经过试验,此举会重新复制一个.engine_config到python包的目录

  • 删除某文件

确定发出了部署命令还没效果,看看你的用户根目录(root或者用户名)下有没有.engine_config这个隐藏文件,你现在是什么用户就在什么下。

可以用这个命令行在自己的用户目录找……但是找到的删了就跑不起来了

find . -type f -name ".engine_config"

如何操纵算子进行行动

把每个算子看成独立的对象,在执行的时候就是遍历(还有筛选出有效行为的”行为掩码“),所以在进行强化学习的时候也可以进行分别的训练

这就是demo中常用的模式:遍历有效行为空间->过滤出可控算子的可控动作->定制化输出

(说实话我一开始很不习惯这样,我熟悉的是魔兽编辑器的trigger触发器那一套)


def step(self, observation: dict):
    # 智能体本轮要输出的所有行为
    total_actions = []

    # 获取可控算子列表
    self.controllable_ops = observation["role_and_grouping_info"][self.seat]["operators"]
    # 生成动作
    for obj_id, valid_actions in observation["valid_actions"].items(): # valid_actions is also a dict
        # 过滤是自己可控的算子
        if obj_id not in self.controllable_ops:
            continue
        # 遍历所有可用行为(这一帧的有效行为空间)
        for (action_type) in self.priority:
            if action_type not in valid_actions:
                continue
            # 开始安排 兵力obj_id 的 行为类型action_type 的 行为action
            action = .......


            if action:
                total_actions.append(action)
                # 一个单位每轮只能有一个行为
                break
    return total_actions

还有一点就是作为指令的json常常不是简单的值,比如移动还需要给出路径经过点的列表,这个就需要自己写函数进行适配了。

放出my_gen_move()函数的实现涉及的函数,移动的算是自由度最大的一个行为了,一个"move_path": route就需要前面几个函数的参与。


def get_move_type(self, bop):
    """Get appropriate move type for a bop."""
    bop_type = bop["type"]
    if bop_type == BopType.Vehicle:
        if bop["move_state"] == MoveType.March:
            move_type = MoveType.March
        else:
            move_type = MoveType.Maneuver
    elif bop_type == BopType.Infantry:
        move_type = MoveType.Walk
    else:
        move_type = MoveType.Fly
    return move_type

def gen_move_route(self, begin, end, mode):
    if (
        not self.is_valid(begin)
        or not self.is_valid(end)
        or not 0 <= mode < len(self.cost)
        or begin == end
    ):
        return []
    frontier = [(0, random.random(), begin)]
    cost_so_far = {begin: 0}
    came_from = {begin: None}

    def a_star_search():
        while frontier:
            _, _, cur = heapq.heappop(frontier)
            if cur == end:
                break
            row, col = divmod(cur, 100)
            for neigh, edge_cost in self.cost[mode][row][col].items():
                neigh_cost = cost_so_far[cur] + edge_cost
                if neigh not in cost_so_far or neigh_cost < cost_so_far[neigh]:
                    cost_so_far[neigh] = neigh_cost
                    came_from[neigh] = cur
                    heuristic = self.get_distance(neigh, end)
                    heapq.heappush(frontier, (neigh_cost + heuristic, random.random(), neigh))

    def reconstruct_path():
        path = []
        if end in came_from:
            cur = end
            while cur != begin:
                path.append(cur)
                cur = came_from[cur]
            path.reverse()
        return path

    a_star_search()
    return reconstruct_path()


def my_gen_move(self, obj_id, destination):
    bop = self.get_bop(obj_id)
    if bop and bop["cur_hex"] != destination:
        move_type = self.get_move_type(bop)
        route = self.map.gen_move_route(bop["cur_hex"], destination, move_type)
        return {
            "actor": self.seat,
            "obj_id": obj_id,
            "type": ActionType.Move,
            "move_path": route,
        }

解释demo的意思

行为类型-“函数指针(一种比喻)”-随机选择可用行为类型直接执行到函数上面


def my_gen_move(self, obj_id, destination):
    ...
    return action

def setup(self, setup_info):
        self.priority = {
        ...
        ActionType.Move: self.gen_move,
        ...
    }  # 通过优先级来决定执行顺序的类型,这是demo的安排

def step(self, observation: dict):
    ...
    # 从有效动作类型中,直接priority获取"函数指针",也就是某个函数
    gen_action = self.priority[action_type] 
    # 通过"函数指针self.priority"获取函数接口,传入形参
    action = gen_action(obj_id, valid_actions[action_type]) 
    ...

环境要求

这里列举上传AI的基于的环境,按照这个来应该没问题

平台安装需求

python==3.10

numpy==1.26.2

pandas==1.5.3

ray==2.9.0

scikit-learn==1.0.2

scipy==1.10.1

tensorflow==2.11.0

torch==2.0.1 

其他的一些tips

功能函数:获取某位置的某方向邻格

def get_move_destination(cur_pos, move_dir):
    """
    按方向取邻接格子,正右是1,顺时针旋转
    """
    move_destination = 0
    cur_row, cur_col = cur_pos // 100, cur_pos % 100
    next_row = cur_row
    next_col = cur_col

    # 判断当前行是奇数行还是偶数行
    if cur_row % 2 == 1: # odd
        flag_Odd_Even = 1
    else: # even
        flag_Odd_Even = 0

    # 六边形格子
    if move_dir == 1:  # 正右
        next_col += 1
    elif move_dir == 2:  # 右下(奇数双加)
        if flag_Odd_Even == 1:
            next_col += 1
        next_row += 1
    elif move_dir == 3:  # 左下(偶数行加行减列)
        if flag_Odd_Even == 0:
            next_col -= 1
        next_row += 1
    elif move_dir == 4:  # 正左
        next_col -= 1
    elif move_dir == 5:  # 左上(偶数行双减)
        if flag_Odd_Even == 0:
            next_col -= 1
        next_row -= 1
    elif move_dir == 6:  # 右上(奇数行加列)
        if flag_Odd_Even == 1:
            next_col += 1
        next_row -= 1

    move_destination = 100 * next_row + next_col
    return move_destination

for i in range(1, 7):
    print(f"Direction {i}: {get_move_destination(203, i)}")

……

你可能感兴趣的:(智能决策,人工智能)