当前位置: 首页 > news >正文

别再死记硬背MDP公式了!用Python手搓一个强化学习‘贪吃蛇’来理解马尔科夫决策过程

用Python构建贪吃蛇游戏:从零理解马尔科夫决策过程

在咖啡厅里,我经常看到学生对着厚厚的强化学习教材皱眉——那些抽象的数学符号和理论推导确实容易让人望而生畏。直到有一天,我让学生用Python写了个简单的贪吃蛇游戏,他们突然恍然大悟:"原来MDP就是游戏规则!"这种通过具体项目理解抽象概念的方式,往往比死记硬背公式有效十倍。

1. 项目准备:搭建游戏骨架

我们先从最基础的贪吃蛇实现开始。这个版本不需要复杂的图形界面,用字符矩阵就能清晰展示游戏状态:

import numpy as np import random class SnakeGame: def __init__(self, width=10, height=10): self.width = width self.height = height self.snake = [(width//2, height//2)] # 蛇初始位置在中心 self.direction = (1, 0) # 初始向右移动 self.food = self._generate_food() self.score = 0 self.game_over = False def _generate_food(self): while True: food = (random.randint(0, self.width-1), random.randint(0, self.height-1)) if food not in self.snake: return food

这个基础框架已经包含了MDP的几个关键要素:

  • 状态空间(𝒮):由蛇身位置、食物位置和移动方向组成
  • 动作集(𝒜):{上, 下, 左, 右}四个基本动作
  • 奖励函数(ℛ):吃到食物+1分,撞墙或自身-10分

2. MDP五元组的代码映射

让我们把理论概念与代码实现一一对应起来:

2.1 状态空间(𝒮)的实现

在贪吃蛇游戏中,完整状态应该包含:

  1. 蛇头坐标(x,y)
  2. 蛇身各段坐标列表
  3. 食物坐标
  4. 当前移动方向
def get_state(self): head_x, head_y = self.snake[0] food_x, food_y = self.food direction_x, direction_y = self.direction # 计算相对食物位置 food_left = food_x < head_x food_right = food_x > head_x food_up = food_y < head_y food_down = food_y > head_y # 危险检测:四个方向是否安全 danger_straight = self._check_collision( (head_x + direction_x, head_y + direction_y)) danger_left = self._check_collision( (head_x + direction_y, head_y - direction_x)) danger_right = self._check_collision( (head_x - direction_y, head_y + direction_x)) return np.array([ food_left, food_right, food_up, food_down, direction_x == 1, direction_x == -1, direction_y == 1, direction_y == -1, danger_straight, danger_left, danger_right ], dtype=int)

2.2 动作集(𝒜)与状态转移(𝒫)

贪吃蛇的动作空间是离散的四个方向。状态转移在基础版本中是确定性的:

def step(self, action): # 动作映射:0=直行, 1=右转, 2=左转 directions = [(1,0), (0,1), (-1,0), (0,-1)] # 右,下,左,上 if action == 1: # 右转 self.direction = (self.direction[1], -self.direction[0]) elif action == 2: # 左转 self.direction = (-self.direction[1], self.direction[0]) # 计算新头部位置 new_head = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1]) # 检查碰撞 if self._check_collision(new_head): self.game_over = True return self.get_state(), -10, True # 移动蛇身 self.snake.insert(0, new_head) # 检查是否吃到食物 if new_head == self.food: self.score += 1 self.food = self._generate_food() return self.get_state(), 1, False else: self.snake.pop() return self.get_state(), -0.1, False # 小惩罚鼓励尽快吃食物

2.3 奖励函数(ℛ)的设计技巧

设计良好的奖励函数是强化学习成功的关键。在贪吃蛇中,我们可以考虑:

事件奖励值设计意图
吃到食物+1主要目标
撞墙/撞自己-10避免死亡
每步移动-0.1鼓励高效
靠近食物+0.2引导行为
def _calculate_reward(self, new_head): if self._check_collision(new_head): return -10, True reward = -0.1 # 基础移动惩罚 # 计算与食物的距离变化 old_dist = abs(self.snake[0][0]-self.food[0]) + abs(self.snake[0][1]-self.food[1]) new_dist = abs(new_head[0]-self.food[0]) + abs(new_head[1]-self.food[1]) if new_head == self.food: return 1, False elif new_dist < old_dist: reward += 0.2 return reward, False

3. 引入Q-learning算法

有了MDP框架,我们现在可以引入最简单的强化学习算法:

class QLearningAgent: def __init__(self, state_size, action_size): self.state_size = state_size self.action_size = action_size self.q_table = np.zeros((2**state_size, action_size)) # 简化状态编码 self.learning_rate = 0.1 self.discount_factor = 0.95 self.epsilon = 0.1 def get_action(self, state): if random.random() < self.epsilon: return random.randint(0, self.action_size-1) # 将状态转换为二进制索引 state_idx = int("".join(map(str, state)), 2) % len(self.q_table) return np.argmax(self.q_table[state_idx]) def learn(self, state, action, reward, next_state, done): state_idx = int("".join(map(str, state)), 2) % len(self.q_table) next_idx = int("".join(map(str, next_state)), 2) % len(self.q_table) # Q-learning更新公式 current_q = self.q_table[state_idx, action] max_next_q = np.max(self.q_table[next_idx]) new_q = current_q + self.learning_rate * ( reward + self.discount_factor * max_next_q * (1-done) - current_q) self.q_table[state_idx, action] = new_q

4. 训练与可视化

训练循环将游戏与学习过程结合起来:

def train_agent(episodes=1000): env = SnakeGame(8, 8) agent = QLearningAgent(state_size=11, action_size=3) # 3动作:直行/左转/右转 for episode in range(episodes): state = env.get_state() total_reward = 0 while not env.game_over: # 选择并执行动作 action = agent.get_action(state) next_state, reward, done = env.step(action) # 学习 agent.learn(state, action, reward, next_state, done) state = next_state total_reward += reward # 每100轮显示一次进度 if episode % 100 == 0: print(f"Episode {episode}, Score: {env.score}, Reward: {total_reward}") env.reset() return agent

通过这个项目,MDP的抽象概念变得触手可及:

  • 状态就是游戏画面
  • 动作是控制输入
  • 奖励是游戏得分
  • 策略是玩家的操作习惯

当看到AI从随机移动逐渐学会主动寻找食物、避开障碍时,那些数学符号突然有了生命。这种通过实践获得的理解,往往比纯理论学习更加深刻和持久。

http://www.rkmt.cn/news/1409088.html

相关文章:

  • git发版上线的时候,打tag标签方便jenkins部署
  • Windows Terminal 1.18终极指南:五大生产力功能深度解析与实战应用
  • 小米大模型官宣大幅降价!MiMo V2.5顶级能力全面爆发,新用户注册直送10元API体验金,普通人也能玩转最强AI
  • 别急着用cor()!用Python和R做皮尔逊相关分析前,这5个坑你绕开了吗?
  • 饲料颗粒机工厂哪家可靠
  • 用Python和NumPy手把手实现一个马尔可夫链预测模型(附股市预测代码)
  • 【ChatGPT投资分析权威报告】:2024年全球AI大模型资本流向、估值陷阱与超额回报三大预警信号
  • ThreadPoolExecutor 源码深度解析:从变量设计到生产级避坑指南
  • 基于STM32H745实现惯性级闭环光纤陀螺:MCU替代FPGA的硬实时架构设计
  • 用Python和螺旋理论手把手教你计算UR5机械臂的末端位置(附完整代码)
  • 三相模块级联型固态变压器SST(级联H桥+ISOP-DAB双有源变换器)Matlab仿真+文献
  • 2026采购风向标:Nitronic 60(S21800)供应链突围指南与核心供应商深度解析 - 品牌2025
  • 陌陌app 响应体解密
  • eNSP AR设备启动失败?可能是Win10更新惹的祸!手把手教你版本兼容性检查与降级/锁定VirtualBox 5.2.26
  • 2026年 高温滤袋/常温滤袋/PTFE/PPS/芳纶滤袋厂家推荐榜:除尘器过滤袋源头工厂实力与口碑深度解析 - 品牌企业推荐师(官方)
  • 2026年5月靠谱的大连防蓝光眼镜商场哪家靠谱厂家推荐榜,防蓝光镜片/渐进多焦点/青少年防控镜片厂家选择指南 - 海棠依旧大
  • 面霸AI · Multi-Agent 群面模拟,让面试官闭嘴惊艳
  • 保姆级教程:在ROS Melodic下用PX4Ctrl实现无人机自动起飞(附状态机源码解析)
  • “信寄一生”词条释义及用法详解
  • 基于本体的LLM推理全解析:输入、过程、输出与参数内化,助你抢占AI前沿!
  • 2026年 断桥窗厂家推荐排行榜:断桥铝门窗/断桥铝窗户/断桥门窗,隔音保温与高端品质之选 - 品牌企业推荐师(官方)
  • 医疗AI模型评估实战:用Python的DeLong检验判断新诊断算法是否真的比老方法好
  • C#中PDF操作-QuestPDF介绍和使用教程
  • Windows桌面壁纸开发避坑指南:从DWM API到跨进程注入,这些‘坑’我帮你踩过了
  • 2026年 东莞遮光膜厂家推荐排行榜:mini遮光膜/PET遮光膜/点阵遮光膜/黑色遮光膜/LED遮光膜/防漏光遮光膜优质品牌深度解析 - 品牌企业推荐师(官方)
  • 企业级集成怎么选:n8n、Zapier还是RestCloud iPaaS?
  • Arm编译器v5到v6预定义宏迁移实战指南
  • 一站式搞定Invar 36现货:多规格棒材带材的优质供应网络汇总 - 品牌2025
  • 单细胞数据分析前传:我在华为云上为RStudio Server配置Shiny Server的踩坑实录
  • 告别穿戴束缚!黎阳之光无感定位赋能矿山矿洞精细化管控