AI捉迷藏代码如何实现智能寻路与隐藏?

99ANYc3cd6 人工智能 10

这个项目通常使用强化学习 来实现,特别是多智能体强化学习,因为捉迷藏是一个典型的多智能体交互环境,每个智能体的行为都会直接影响其他智能体的奖励。

AI捉迷藏代码如何实现智能寻路与隐藏?-第1张图片-广州国自机器人
(图片来源网络,侵删)

下面我将分步为你详细解释如何实现这个项目,包括核心思想、代码框架、关键代码片段以及未来可以改进的方向。


核心思想:多智能体强化学习

  1. 环境:一个由网格组成的地图,有墙壁、障碍物、开放空间。

  2. 智能体

    • :目标是在最短时间内找到藏家,它的动作是上下左右移动。
    • 藏家:目标是尽可能长时间不被找到,它的动作也是上下左右移动。
  3. 状态:对于每个智能体,状态可以包括:

    AI捉迷藏代码如何实现智能寻路与隐藏?-第2张图片-广州国自机器人
    (图片来源网络,侵删)
    • 自己的坐标。
    • 自己的视野范围内的地图信息(周围5x5的格子)。
    • (可选)对其他智能体位置的感知(藏家可以听到鬼的声音,知道大概方向)。
  4. 动作:每个智能体在每个时间步可以选择的动作,如:上、下、左、右、不动。

  5. 奖励:这是学习的核心。

    • 对于鬼
      • 如果找到藏家,给予一个大的正奖励 (e.g., +100)。
      • 每移动一步,给予一个小的负奖励 (e.g., -0.1),鼓励它尽快找到。
    • 对于藏家
      • 如果被找到,给予一个大的负奖励 (e.g., -100)。
      • 每存活一个时间步,给予一个小的正奖励 (e.g., +0.1),鼓励它尽可能躲藏。
      • (可选)如果找到一个更好的藏身处,给予一个小的正奖励。
  6. 算法

    • MAPPO (Multi-Agent Proximal Policy Optimization):这是目前最流行和效果最好的多智能体强化学习算法之一,它结合了PPO的稳定性和多智能体协作/对抗的思想。
    • MADDPG (Multi-Agent Deep Deterministic Policy Gradient):另一个经典算法,适用于连续动作空间,但也可以用于离散动作空间。

项目实现步骤

我们将使用一个流行的强化学习框架 Stable Baselines3,并结合其多智能体扩展 Stable Baselines3-ZooMADRL 库,这里我们以概念性的代码框架和伪代码为主,因为完整实现需要大量的计算资源和调试。

AI捉迷藏代码如何实现智能寻路与隐藏?-第3张图片-广州国自机器人
(图片来源网络,侵删)

第1步:环境搭建

我们需要创建一个自定义的 gym.Env 环境,这是整个项目的基础。

import numpy as np
import gym
from gym import spaces
class HideAndSeekEnv(gym.Env):
    metadata = {'render.modes': ['human']}
    def __init__(self, grid_size=10, num_seekers=1, num_hiders=1):
        super(HideAndSeekEnv, self).__init__()
        self.grid_size = grid_size
        self.num_seekers = num_seekers
        self.num_hiders = num_hiders
        self.max_steps = 200 # 最大步数,防止无限循环
        # 定义动作空间:每个智能体有5个动作 (上, 下, 左, 右, 不动)
        self.action_space = spaces.Discrete(5)
        # 定义观察空间和动作空间的元组,以容纳多个智能体
        # 观察空间可以是一个网格视图,(5, 5, 3) 表示5x5的视野,3个通道(墙壁/空地/其他智能体)
        obs_shape = (5, 5, 3) 
        self.observation_space = spaces.Tuple([spaces.Box(low=0, high=1, shape=obs_shape, dtype=np.float32)] * (num_seekers + num_hiders))
        self.reset()
    def reset(self):
        # 初始化地图 (0=空地, 1=墙)
        self.map = np.zeros((self.grid_size, self.grid_size), dtype=int)
        # 随机添加一些墙壁
        num_walls = int(self.grid_size * self.grid_size * 0.2)
        for _ in range(num_walls):
            x, y = np.random.randint(0, self.grid_size, 2)
            self.map[x, y] = 1
        # 初始化智能体位置
        self.seeker_pos = []
        self.hider_pos = []
        # 确保所有智能体初始位置不重叠且不在墙上
        all_positions = []
        for _ in range(self.num_seekers):
            while True:
                pos = (np.random.randint(0, self.grid_size), np.random.randint(0, self.grid_size))
                if self.map[pos] == 0 and pos not in all_positions:
                    self.seeker_pos.append(list(pos))
                    all_positions.append(pos)
                    break
        for _ in range(self.num_hiders):
            while True:
                pos = (np.random.randint(0, self.grid_size), np.random.randint(0, self.grid_size))
                if self.map[pos] == 0 and pos not in all_positions:
                    self.hider_pos.append(list(pos))
                    all_positions.append(pos)
                    break
        self.current_step = 0
        return self._get_obs()
    def _get_obs(self):
        # 为每个智能体生成观察
        observations = []
        # 藏家的观察
        for pos in self.hider_pos:
            obs = self._get_grid_view(pos, is_hider=True)
            observations.append(obs)
        # 鬼的观察
        for pos in self.seeker_pos:
            obs = self._get_grid_view(pos, is_hider=False)
            observations.append(obs)
        return tuple(observations)
    def _get_grid_view(self, pos, is_hider, view_size=5):
        # 为单个智能体生成一个以它为中心的网格视图
        # view_size x view_size x 3 的数组
        # 通道0: 墙壁
        # 通道1: 自己
        # 通道2: 对手 (如果可见)
        view = np.zeros((view_size, view_size, 3))
        half_view = view_size // 2
        x, y = pos
        for i in range(view_size):
            for j in range(view_size):
                map_x = x - half_view + i
                map_y = y - half_view + j
                # 检查是否在地图范围内
                if 0 <= map_x < self.grid_size and 0 <= map_y < self.grid_size:
                    # 墙壁通道
                    view[i, j, 0] = self.map[map_x, map_y]
                    # 自己通道
                    view[half_view, half_view, 1] = 1
                    # 对手通道 (简化版:如果对手在视野内)
                    # 这里可以加入更复杂的感知逻辑,比如声音、光线等
                    if is_hider: # 藏家看鬼
                        for seeker_p in self.seeker_pos:
                            if map_x == seeker_p[0] and map_y == seeker_p[1]:
                                view[i, j, 2] = 1
                    else: # 鬼看藏家
                        for hider_p in self.hider_pos:
                            if map_x == hider_p[0] and map_y == hider_p[1]:
                                view[i, j, 2] = 1
        return view
    def step(self, actions):
        # actions 是一个元组,包含所有智能体的动作
        #  (action_seeker_0, action_hider_0, action_seeker_1, ...)
        new_seeker_pos = []
        new_hider_pos = []
        # 1. 移动鬼
        for i, pos in enumerate(self.seeker_pos):
            action = actions[i]
            new_pos = self._move(pos, action)
            new_seeker_pos.append(new_pos)
        # 2. 移动藏家
        for i, pos in enumerate(self.hider_pos):
            action = actions[self.num_seekers + i]
            new_pos = self._move(pos, action)
            new_hider_pos.append(new_pos)
        self.seeker_pos = new_seeker_pos
        self.hider_pos = new_hider_pos
        # 3. 计算奖励和完成状态
        rewards = []
        dones = []
        # 为每个智能体计算奖励
        for i in range(self.num_seekers):
            reward = -0.1 # 每步小惩罚
            done = False
            # 检查是否找到所有藏家
            for seeker_p in self.seeker_pos:
                for hider_p in self.hider_pos:
                    if seeker_p == hider_p:
                        reward += 100 # 找到大奖赏
                        done = True
            rewards.append(reward)
            dones.append(done)
        for i in range(self.num_hiders):
            reward = 0.1 # 每步小奖励
            done = False
            # 检查是否被任何鬼找到
            for seeker_p in self.seeker_pos:
                for hider_p in self.hider_pos:
                    if seeker_p == hider_p:
                        reward -= 100 # 被找到大惩罚
                        done = True
            rewards.append(reward)
            dones.append(done)
        self.current_step += 1
        if self.current_step >= self.max_steps:
            # 超时,藏家获胜
            for i in range(self.num_seekers):
                rewards[i] -= 50 # 鬼的超时惩罚
            for i in range(self.num_hiders):
                rewards[self.num_seekers + i] += 50 # 藏家的超时奖励
            dones = [True] * (self.num_seekers + self.num_hiders)
        info = {} # 可以添加额外信息
        return self._get_obs(), rewards, dones, info
    def _move(self, pos, action):
        x, y = pos
        new_x, new_y = x, y
        if action == 0: # 上
            new_x = x - 1
        elif action == 1: # 下
            new_x = x + 1
        elif action == 2: # 左
            new_y = y - 1
        elif action == 3: # 右
            new_y = y + 1
        # action == 4: 不动
        # 检查新位置是否有效 (在地图内且不是墙)
        if 0 <= new_x < self.grid_size and 0 <= new_y < self.grid_size and self.map[new_x, new_y] == 0:
            return [new_x, new_y]
        else:
            return pos # 如果移动无效,留在原地
    def render(self, mode='human'):
        # 用简单的文本渲染游戏状态
        print(f"--- Step {self.current_step} ---")
        display_map = self.map.copy().astype(str)
        for pos in self.seeker_pos:
            display_map[pos[0], pos[1]] = 'S' # Seeker
        for pos in self.hider_pos:
            display_map[pos[0], pos[1]] = 'H' # Hider
        print(display_map)
        print("-" * 20)

第2步:训练AI模型

现在我们有了环境,接下来使用MAPPO或MADDPG等算法来训练智能体,这里以伪代码形式展示。

import torch
from stable_baselines3 import PPO
from sb3_contrib import MAPPo # 需要安装 sb3-contrib
# 1. 创建环境
env = HideAndSeekEnv(grid_size=15, num_seekers=1, num_hiders=1)
# 2. 定义策略网络
# 对于复杂的观察空间,可以使用CNN
policy_kwargs = dict(
    features_extractor_class=stable_baselines3.common.torch_layers.BaseFeaturesExtractor,
    features_extractor_kwargs=dict(features_dim=64),
    net_arch=[dict(pi=[64, 64], vf=[64, 64])],
    activation_fn=torch.nn.ReLU,
)
# 3. 初始化MAPPO算法
# 注意:MAPPO的实现可能略有不同,这里是一个概念性的示例
# 你可能需要使用专门的MARL库,如 `magent` 或 `pettingzoo` 中的环境
# 为了简化,我们假设有一个可以直接使用的MAPPo类
# 实际项目中,更推荐使用像 `PettingZoo` 这样的标准多智能体环境库
# 它已经内置了捉迷藏等环境,并与SB3兼容。
# from pettingzoo.butterfly import pursuit_v4
# env = pursuit_v4.env()
# model = MAPPo("MultiInputPolicy", 
#                env, 
#                policy_kwargs=policy_kwargs,
#                tensorboard_log="./hide_and_seek_tensorboard/",
#                verbose=1,
#                learning_rate=0.0003)
# 4. 开始训练
print("Starting training...")
# model.learn(total_timesteps=500000) # 训练50万步
# model.save("hide_and_seek_mappo")
print("Training finished and model saved.")
# 5. 测试训练好的模型
print("Starting testing...")
# model = MAPPo.load("hide_and_seek_mappo")
# obs = env.reset()
# for i in range(1000):
#     actions, _states = model.predict(obs, deterministic=True)
#     obs, rewards, dones, info = env.step(actions)
#     env.render()
#     if all(dones):
#         obs = env.reset()
# env.close()

关键挑战与改进方向

  1. 非平稳性问题:在多智能体学习中,每个智能体都在学习,导致环境不断变化,这被称为“非平稳性”,MAPPO通过使用集中式训练和去中心化执行的范式来缓解这个问题。
  2. 稀疏奖励:最初的很长一段时间,鬼都得不到正奖励,藏家也得不到负奖励,这会导致学习非常缓慢。
    • 解决方案:设计奖励塑形,鬼可以根据与藏家的距离获得奖励(越近奖励越高),藏家可以根据距离鬼的远近获得奖励(越远奖励越高)。
  3. 可扩展性:当智能体数量增多时,计算量和复杂度会急剧上升。
    • 解决方案:使用更高效的算法(如QMIX、VDN等值分解算法),或者设计通信机制,让智能体之间可以协作。
  4. 观察空间设计:简单的网格视图可能不够,可以加入更丰富的信息,如:
    • 声音:藏家可以听到鬼的大致方向,但不知道精确位置。
    • 视野遮挡:加入“阴影”或“迷雾”,让智能体只能看到一定范围。
    • 动态障碍物:比如会移动的门或巡逻的守卫。
  5. 更复杂的地图:可以设计具有不同房间的复杂地图,或者有“捷径”和“死胡同”的策略性地图。

更简单的起点:使用现有库

如果你想快速体验,可以直接使用 PettingZoo 库,它提供了标准化的多智能体环境,包括捉迷藏。

pip install pettingzoo

然后你可以直接用 Stable Baselines3 训练它:

from pettingzoo.butterfly import pursuit_v4
from stable_baselines3 import PPO
from stable_baselines3.common.env_util import make_vec_env
# 创建环境
env = pursuit_v4.env()
# 使用向量化的环境来加速训练
vec_env = make_vec_env(lambda: env, n_envs=4)
# 使用 PPO 训练 (注意:PPO是单智能体算法,在PettingZoo中通过循环控制每个智能体)
# 对于真正的多智能体协作,还是需要MAPPO等算法
model = PPO("MlpPolicy", vec_env, verbose=1, tensorboard_log="./pursuit_v4_tensorboard/")
model.learn(total_timesteps=100000)
# 测试
obs = vec_env.reset()
for i in range(1000):
    action, _states = model.predict(obs)
    obs, rewards, dones, info = vec_env.step(action)
    vec_env.render()
    if dones:
        break
vec_env.close()

实现一个AI捉迷藏游戏是一个激动人心的项目,它结合了强化学习、多智能体系统和环境设计等多个领域的知识。

核心流程

  1. 定义环境:创建 gym.Env,处理状态、动作、奖励和逻辑。
  2. 选择算法:对于对抗/协作场景,MAPPO是首选。
  3. 训练与评估:使用RL库进行长时间训练,并观察AI的行为。
  4. 迭代优化:通过调整奖励函数、观察空间和环境来提升AI的智能水平。

从简单的开始,逐步增加复杂性,是完成这类项目的最佳路径,祝你编码愉快!

标签: AI捉迷藏智能寻路算法 AI捉迷藏隐藏策略代码 AI捉迷藏路径优化实现

抱歉,评论功能暂时关闭!