1. Gym CartPole环境封装与随机策略基线
任务目标
实现一个4×4网格世界环境,智能体从左上角出发,目标是到达右下角终点。每一步移动获得-1奖励,到达终点获得+10奖励并终止回合。环境需继承gym.Env,实现reset、step、render方法,并正确设置observation_space与action_space,使其可通过标准Gym API调用。
环境依赖
- Python 3.8+
- gymnasium(推荐)或gym 0.26+
- numpy
完整实现
import gymnasium as gym
import numpy as np
from gymnasium import spaces
class GridworldEnv(gym.Env):
"""
4x4 Gridworld:
- 状态: 0~15 (row*4+col)
- 动作: 0=上, 1=右, 2=下, 3=左
- 奖励: 每步-1, 到达终点+10
- 终止: 到达状态15
"""
metadata = {"render_modes": ["human", "ansi"]}
def __init__(self, render_mode=None):
super().__init__()
self.grid_size = 4
self.n_states = self.grid_size * self.grid_size
self.start_state = 0
self.goal_state = self.n_states - 1
# 动作空间: 0上, 1右, 2下, 3左
self.action_space = spaces.Discrete(4)
# 状态空间: 0~15
self.observation_space = spaces.Discrete(self.n_states)
assert render_mode is None or render_mode in self.metadata["render_modes"]
self.render_mode = render_mode
self.state = None
def _get_coords(self, state):
return state // self.grid_size, state % self.grid_size
def _get_state(self, row, col):
# 边界约束: 不允许移出网格
row = max(0, min(row, self.grid_size - 1))
col = max(0, min(col, self.grid_size - 1))
return row * self.grid_size + col
def reset(self, seed=None, options=None):
super().reset(seed=seed)
self.state = self.start_state
if self.render_mode == "human":
self.render()
return self.state, {}
def step(self, action):
row, col = self._get_coords(self.state)
if action == 0: # 上
row -= 1
elif action == 1: # 右
col += 1
elif action == 2: # 下
row += 1
elif action == 3: # 左
col -= 1
else:
raise ValueError(f"Invalid action: {action}")
# 边界约束(撞墙则停留在原地)
new_state = self._get_state(row, col)
self.state = new_state
terminated = (self.state == self.goal_state)
reward = 10.0 if terminated else -1.0
if self.render_mode == "human":
self.render()
return self.state, reward, terminated, False, {}
def render(self):
if self.render_mode == "ansi":
return self._render_ansi()
elif self.render_mode == "human":
print(self._render_ansi())
def _render_ansi(self):
output = ""
for r in range(self.grid_size):
row_str = ""
for c in range(self.grid_size):
s = r * self.grid_size + c
if s == self.state:
row_str += " A "
elif s == self.goal_state:
row_str += " G "
else:
row_str += " . "
output += row_str + "\n"
return output
def close(self):
pass
运行与验证
将上述代码保存为gridworld_env.py,然后运行以下验证脚本:
from gridworld_env import GridworldEnv
import gymnasium as gym
# 注册环境(可选,用于gym.make)
gym.register(
id="Gridworld-v0",
entry_point="gridworld_env:GridworldEnv",
)
# 方式1: 直接实例化
env = GridworldEnv(render_mode="ansi")
obs, _ = env.reset()
print("初始状态:", obs)
# 执行一步向右移动
obs, reward, terminated, truncated, info = env.step(1)
print(f"状态={obs}, 奖励={reward}, 终止={terminated}")
print(env.render())
# 方式2: 通过gym.make创建
env2 = gym.make("Gridworld-v0", render_mode="ansi")
obs2, _ = env2.reset()
print("gym.make创建成功,初始状态:", obs2)
# 手动走一条路径到终点验证终止逻辑
env3 = GridworldEnv()
obs3, _ = env3.reset()
# 路径: 右(1), 右(1), 下(2), 下(2) -> 到达(2,2)即状态10
# 继续: 右(1), 下(2) -> 到达(3,3)即状态15
for action in [1, 1, 2, 2, 1, 2]:
obs3, reward3, terminated3, _, _ = env3.step(action)
print(f"动作={action} -> 状态={obs3}, 奖励={reward3}, 终止={terminated3}")
if terminated3:
print("到达终点,回合终止")
break
通过条件
- 环境可正常实例化,
reset()返回状态0和空字典。 step()返回5元组,动作0~3分别对应上、右、下、左移动。- 在边界执行移出动作时,状态保持不变(撞墙效果)。
- 到达状态15时
terminated=True且奖励为+10;其他步骤奖励为-1。 - 通过
gym.make("Gridworld-v0")可成功创建环境实例。 - 运行验证脚本,最后一步动作2后输出
终止=True,说明终止逻辑正确。
常见问题
- 版本兼容:若使用gym(非gymnasium),需将
terminated, truncated合并为done,即return self.state, reward, terminated, {},并移除truncated返回值。 - 注册失败:确保
gridworld_env.py在当前工作目录,或已安装为Python模块。 - 渲染输出:
render_mode="ansi"返回字符串,"human"打印到控制台;不设置渲染模式则render()不执行任何操作。