1. 本文将强化学习方法(MC、Sarsa、Q learning)应用于“S21点的简单纸牌游戏”。
类似于Sutton和Barto的21点游戏示例,但请注意,纸牌游戏的规则是不同且非标准的。
2. 为方便描述,过程使用代码截图,文末附链接。(如果耐心读完的话)
一. S21环境实现
游戏的规则我们设置如下:
- 游戏是用无限副牌进行的(即用替换牌进行采样)
- 从牌组中抽取的每一张牌的值都在1到10之间(均匀分布),颜色为红色(概率0.4)或黑色(概率0.6)。
- 此游戏中没有王牌或图片牌。
- 在游戏开始时,玩家和发牌人都抽到一张黑卡(双方都可以完全观察)
- 每轮玩家可以选择停止拿牌stick或继续拿牌hit
- 如果玩家hit,则从牌组中抽取另一张牌
- 如果玩家stick,她将不会收到更多的牌
- 黑色牌会增加玩家的牌值,红色牌不改牌值(等于无效)
- 如果玩家的总和超过21,或小于1,则她将输掉游戏(奖励-1)
- 如果玩家stick,则发牌人开始它的回合。对于大于等于20的总和,庄家总是保持stick,否则就会继续拿牌hit。如果经销商爆牌,则玩家获胜;否则总和最大的玩家获胜。
- 获胜(奖励+1)、失败(奖励-1)或平局(奖励0)
相比复杂的21点游戏,本游戏主要简化如下:
1. 可以无视前面已发的牌的牌面,不需要根据开始拿到的牌来推断后续发牌的概率。
2. 庄家和玩家分开游戏,并非轮流决定拿牌还是弃牌。
3. 牌值从1-10,且1的值不会变化。
4. 庄家策略固定,总和<20时持续拿牌。
根据任务1,我们针对上述规则定义相关类如下:

环境类Envi功能如下:
- 主要记录当前玩家和庄家的卡牌,游戏是否结束。
- 在玩家每步step之后 ,返回新的状态、奖励、是否结束标志。
- 当玩家选择stick之后,将后续的所有庄家操作纳入环境中计算。(任务1要求)

游戏的每步操作step逻辑如下:(其中在玩家决策内更新当前的奖励和状态,存储在环境类对象上)

玩家的取牌、弃牌实现如下:
- 当玩家取牌时,增加一张牌到player_cards中,并且更新状态和奖励
- 当玩家弃牌时,转为庄家操作(取牌直到20以上),结束后判定胜负。

实现发牌的操作如下图所示,在1-10之间选择卡牌,并且依照概率赋予颜色。开局必发黑牌。

最后,我们根据双方牌值,计算是否发生爆牌的情况或者胜负情况。若玩家仍可继续选择,则继续游戏,更新状态和奖励。

二. 游戏代理实现
2.1 通用代理(玩家类)
我们定义通用代理具有选择动作和训练的基本方法。后续通过不同的策略代理进行继承并实现。(蒙特卡洛代理、Sarsa代理、Q-learning代理)

2.2 蒙特卡洛代理
2.2.1 算法过程
蒙特卡洛方法是一种模型无关(Model Free)的方法,这意味着我们需要通过模拟多次环境交互来估计出策略价值函数。
评估基本步骤如下:
- 生成轨迹: 在每一轮蒙特卡洛模拟中,从环境的初始状态开始,根据当前的策略生成一个完整的轨迹(也称为episode)。轨迹包括状态、动作和即时奖励的序列,直到达到终止状态。
- 计算回报: 对于轨迹中的每个状态,计算从该状态开始的累积回报。回报是从当前状态开始,经过一系列动作和环境反馈后获得的奖励的总和 。在这一环节,我们采用First-Visit MC这种方法,只考虑在一个episode中首次访问某个状态时计算的回报。如果同一个状态在同一个episode中被多次访问,只有第一次访问的回报会被计算在内。这样的话,一个状态在一个episode中只有一个相关的回报值。
- 更新价值函数: 使用得到的