【强化学习】手把手教你实现游戏通关AI(2)——Q-Learning

2023-10-29

系列文章目录

在本系列文章中笔者将手把手带领大家实现基于强化学习的通关类小游戏,笔者将考虑多种方案,让角色顺利通关。本文将讲述如何使用Q-Learning算法实现AI通关。

完整代码已上传至github:https://github.com/TommyGong08/RL_shoot_game

【强化学习】手把手教你实现游戏通关AI(1)——游戏界面实现

【强化学习】手把手教你实现游戏通关AI(2)——Q-Learning



Q-Learning算法

QL的思想是:为每个状态-动作对学习动作函数Q(s,a)
Q(s,a)的值是在状态s中执行动作a之后获得的累计返回值。agent直接从历史经验中学习,不需要完全了解环境模型。当agent做出决策时,只需要比较s状态下每个动作对应的Q(s,a)值,就可以确定s状态下的最优策略,而不考虑状态s的后续状态
Q_learning算法流程如图所示:
在这里插入图片描述
在主函数中我们按照如下步骤进行:

  • 随机初始化Q表
  • 对于每一个游戏情节:
    • 从Q表中选择当前状态对应的action
    • 实施这个action(这时候物体已经移动到下一个状态s_了)
    • 对于状态s_,观察奖励reward
    • 更新Q表

即如下流程图所示:
在这里插入图片描述

主程序

# main.py
# -*- coding: UTF-8 -*-

"""
游戏的主程序,调用q_learning和env
"""

from game import Mygame
from q_learning import QLearning
import pygame


def update():
    for episode in range(100):  # 100次游戏情节
        # 初始化 state(状态)
        state = env.reset()
        print(state)

        step_count = 0  # 记录走过的步数

        while True:
            # 更新可视化环境

            clock = pygame.time.Clock()  # 设置时钟
            clock.tick(10)  # 每秒执行100次
            # RL 大脑根据 state 挑选 action
            action = RL.choose_action(str(state))
            # 探索者在环境中实施这个 action, 并得到环境返回的下一个 state, reward 和 done (是否是踩到炸弹或者找到宝藏)
            state_, reward, done = env.step(action)
            # print(state_)
            step_count += 1  # 增加步数

            # 机器人大脑从这个过渡(transition) (state, action, reward, state_) 中学习
            RL.learn(str(state), action, reward, str(state_))

            # 机器人移动到下一个 state
            state = state_
            env.person = state

            env.draw_map()
            # 如果踩到炸弹或者找到宝藏, 这回合就结束了
            if done:
                print("回合 {} 结束. 总步数 : {}\n".format(episode + 1, step_count))
                break

    # 结束游戏并关闭窗口
    print('游戏结束')
    pygame.quit()


if __name__ == "__main__":
    # 创建环境 env 和 RL
    pygame.init()  # 初始化pygame
    env = Mygame()
    RL = QLearning(actions=list(range(env.n_actions)))

    # 执行update函数
    update()

    print('\nQ table:')
    print(RL.q_table)

Q-Learning代码

注:为了避免角色陷入局部解,我们在动作选择函数choose_action中采用Epsilon Greedy 贪婪方法。

# q_learning.py
# -*- coding: UTF-8 -*-
"""
Q Learning Algorithm
"""

import numpy as np
import pandas as pd


class QLearning:
    def __init__(self, actions, learning_rate=0.01, discount_factor=0.9, e_greedy=0.1):
        self.actions = actions  # action 列表
        self.lr = learning_rate  # 学习速率
        self.gamma = discount_factor  # 折扣因子
        self.epsilon = e_greedy  # 贪婪度
        self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float32)  # Q 表

    # 检测 q_table 中有没有这个 state
    # 如果还没有当前 state, 那我们就插入一组全 0 数据, 作为这个 state 的所有 action 的初始值
    def check_state_exist(self, state):
        if state not in self.q_table.index:
            # 插入一组全 0 数据
            self.q_table = self.q_table.append(
                pd.Series(
                    [0] * len(self.actions),
                    index=self.q_table.columns,
                    name=state,
                )
            )

    # 根据 state 来选择 action
    def choose_action(self, state):
        self.check_state_exist(state)  # 检测此 state 是否在 q_table 中存在
        # 选行为,用 Epsilon Greedy 贪婪方法
        if np.random.uniform() < self.epsilon:
            # 随机选择 action
            action = np.random.choice(self.actions)
        else:  # 选择 Q 值最高的 action
            state_action = self.q_table.loc[state, :]
            # 同一个 state, 可能会有多个相同的 Q action 值, 所以我们乱序一下
            state_action = state_action.reindex(np.random.permutation(state_action.index))
            action = state_action.idxmax()  # 获取最大值的索引位置
        return action

    # 学习。更新 Q 表中的值
    def learn(self, s, a, r, s_):
        self.check_state_exist(s_)  # 检测 q_table 中是否存在 s_

        q_predict = self.q_table.loc[s, a]  # 根据 Q 表得到的 估计(predict)值

        # q_target 是现实值
        if s_ != 'terminal':  # 下个 state 不是 终止符
            q_target = r + self.gamma * self.q_table.loc[s_, :].max()
        else:
            q_target = r  # 下个 state 是 终止符

        # 更新 Q 表中 state-action 的值
        self.q_table.loc[s, a] += self.lr * (q_target - q_predict)

效果展示

请添加图片描述

总结

结合上一篇游戏界面制作,我们就介绍完了Q_learning算法制作通关类游戏AI的基本过程。将上一篇中的game.py以及本文中的main.py和q_learning.py相结合,能完整实现整个项目。各位读者可以实操一下,完整代码我已上传至github:https://github.com/TommyGong08/RL_shoot_game

下文我将带领大家用DQN算法是继续完善我们的小游戏。

参考资料

强化学习学习总结(二)——QLearning算法更新和思维决策

强化学习——从Q-Learning到DQN到底发生了什么?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【强化学习】手把手教你实现游戏通关AI(2)——Q-Learning 的相关文章

随机推荐

  • Eclipse启动tomcat出现invalid ports的解决办法

    在Eclipse出现以上错误的 可以继续往下看 在server中 点击Tomcat 进入设置 把三个端口都填写了不留空 根据情况来填写相应的端口号 防止占用 保存即可
  • 交易流水指标统计——pandas

    1 根据交易流水 计算每个交易交易对象的如下指标 总收入笔数 总收入月数 最大月收入笔数 最大月收入笔数所在日期 年月日格式 import pandas as pd path r C Users xxx Desktop 科技数据 xlsx
  • Angular入门学习笔记

    Angualr入门扫盲必备 声明 这篇是我学习angualr的笔记 可以转载 但必须注明来源作者 kone 并附上本文链接 A 环境 工具 1 先确保安装了nodejs和npm Nodejs npm 包管理器 cnpm 淘宝的镜像 2 安裝
  • 低代码让开发变得不再复杂

    传统IT自研软件开发 通过编程去写代码 还有数据库 API 第三方基础架构等 从而造成开发周期长 难度大 技术人员不易于开发维护 因此价格及时间成本也是相对较高 后期出现了可以直接应用的成品软件 以及现在火热的低代码开发方式 针对这三种方式
  • 给Sqlite数据库设置密码

    免费版Sqlie是不提供设置密码功能的 经过查阅资料最终找到了解决方案 方案一 从sqlite源码入手 据说sqlite源码已经提供了加密的接口 只是免费版没有实现 可以参考这位仁兄的博客以了解详情 http www cnblogs com
  • 架构师是做什么的?

    哈佛大学有一个非常著名的关于目标对人生影响的跟踪调查 调查的对象是一群智力 学历 环境等条件都差不多的大学毕业生 结果是这样的 第一类人 27 的人 没有目标 第二类人 60 的人 目标模糊 第三类人 10 的人 有清晰但比较短期的目标 第
  • Mysql错误1452 - Cannot add or update a child row: a foreign key constraint fails 原因及解决方法

    报错的原因大概分为三种 原因一 添加的外键列与另一个表的唯一索引列 一般是主键 的数据类型不同 原因二 要添加外键的表类型与另一个表的存储引擎是不是都为innodb引擎 查看表引擎 法一 show create table 表名 法二 sh
  • ag-grid在Vue项目中的基本使用

    ag grid官网 1 安装 npm install ag grid community ag grid vue save dev 2 在main js中引入ag grid的样式文件 引入ag grid的样式文件 import node m
  • bing搜索引擎入口_资源搜索,除了百度,还有哪些好用的搜索引擎?

    作者 杨银洁 来源 ETPPT 遇到问题怎么办 百度一下 你out了 除了百度还有很多搜索引擎 而且还有很多国外网站可以检索哦 是否还在苦恼高清图找不到 PPT素材找不到 关注ETPPT这些就不是问题 今天我们就介绍一下有哪些可以轻松帮助你
  • 云原生之使用Docker部署BookBrowser电子书浏览器

    云原生之使用Docker部署BookBrowser电子书浏览器 一 BookBrowser简介 1 BookBrowser简介 2 BookBrowser特点 二 检查docker环境 1 检查docker状态 2 检查docker版本 3
  • Java线程和操作系统线程的关系

    传统进程的缺点 fork一个子进程的消耗是很大的 fork是一个昂贵的系统调用 即使使用现代的写时复制 copy on write 技术 各个进程拥有自己独立的地址空间 进程间的协作需要复杂的IPC技术 如消息传递和共享内存等 多线程的优缺
  • 【C++从入门到放弃】C++编译生成动态链接库*.so及如何调用*.so进阶篇2-编译jsoncpp

    C 从入门到放弃 C 编译生成动态链接库 so及如何调用 so进阶篇2 编译jsoncpp 附 当前项目cstudy7 本文可以收获什么 将其它项目生成的动态链接库拿到本项目中使用 CMakeLists txt中使用其它项目的动态链接库 M
  • 记录开发中使用的设计模式之发布订阅者模式(观察者模式)

    一 开发场景 当我们在开发中涉及到大量的调用跨应用API的时候 需要按照场景书写大量的重复性代码 常规的做法就是通过if else进行场景判断 进行调用 代码十分的冗余 重复性的调用方法 不利于后期的维护 而为了更好的针对某些场景 去调用对
  • 在umi+dva中使用useDispatch、useSelector替代dva中的connect

    文章目录 前言 一 View和Model的关系图解 二 model的使用 三 connect的替代 四 umi dva的CURD应用 总结 前言 最近实习的公司用到了umi框架开发 里面有一个umi dva的使用 因此特地先看了dva的官方
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • 链栈的基本操作C/C++代码实现

    链栈的结构 由于栈的主要操作是在栈顶插入和删除 显然以链表的头部作为栈顶是最方便的 且不需要附加一个头结点 初始化 栈顶指针S置空即可 入栈 链栈不需要判断栈是否满 出栈 栈顶指针S等于NULL表空栈 即链栈S NULL时为空栈 代码如下
  • C++非const引用问题:error: cannot bind non-const lvalue reference of type

    当一个函数的形参为非const类型 而一个参数以非const传入 编译器一般会认为程序员会在该函数里修改该参数 而且该参数返回后还会发挥作用 此时如果你把一个临时变量当成非const引用传进来 由于临时变量的特殊性 程序员无法对改临时变量进
  • 【壁纸小程序】搭建自己的壁纸小程序-微信抖音双端

    文章目录 前言 一 前端展示 二 实现原理简析 1 wordpress 后端 2 前端uni app 三 如何自动发布文章 安装 JWT Authentication for WP API 插件 准备好图片 使用python脚本自动发布 前
  • Netty的零拷贝(Zero-Copy)

    Netty的零拷贝 Zero Copy 主要体现在五个方面 Netty接收和发送ByteBuffer采用DirectBuffer 使用堆外直接内存进行Socket读写 不需要进行字节缓冲区的二次拷贝 如果使用传统的JVM的堆内存 Heap
  • 【强化学习】手把手教你实现游戏通关AI(2)——Q-Learning

    系列文章目录 在本系列文章中笔者将手把手带领大家实现基于强化学习的通关类小游戏 笔者将考虑多种方案 让角色顺利通关 本文将讲述如何使用Q Learning算法实现AI通关 完整代码已上传至github https github com To