45 lines
2.6 KiB
ReStructuredText
45 lines
2.6 KiB
ReStructuredText
.. SPDX-License-Identifier: GFDL-1.3-or-later
|
||
|
||
FreeKill 的 AI 系统
|
||
===================
|
||
|
||
概述
|
||
----
|
||
|
||
备选算法:
|
||
|
||
- MCTS
|
||
- 神杀算法
|
||
|
||
--------------
|
||
|
||
MCTS实现
|
||
--------
|
||
|
||
实现该算法的最大难点在于如何模拟。
|
||
|
||
首先是树中各个节点的保存,我们自然无法给某个节点都分配一个Room对象。由于节点是通过根节点进行相应的决策拓展而来的,所以其实节点内部的数据可以保存为各个决策的数组。
|
||
|
||
然后节点首先要能知道自己的双亲节点和孩子节点,这个分别用一个值和一个数组表示就行了。
|
||
|
||
想要实现模拟的话,重点是如何创造一个一模一样的Room出来。指望lua提供完全clone一个coroutine所有内容或许不是很现实。以下是一种备选方案:
|
||
|
||
1. 首先Room初始化的时候也初始化一个AI用的Room
|
||
2. Room内要能够录像,记录所有的request结果和random生成的值。为此可能要自定义一个random函数对自带的math.random进行封装。
|
||
3. 在录像的时候,AI Room也跟着录像的内容进行更新。AI
|
||
Room本质上也就是一个Room而已,或者可以是Room的子类,反正他的内容就是用这个方式和真Room即时同步的。
|
||
4. 在AI即将处理问题的时候,首先获得所有可行选项。根据算法,需要对某个节点进行randomplay。
|
||
5. randomplay的话如果直接用AI Room,那么回溯的时候如何回到先前的状态呢?
|
||
|
||
1. 考虑新建一个新的AI
|
||
Room,然后重放录像以达到开始状态。这样每次randomplay之前都要先回复一下状态,而随着录像的加长这个过程也可能变长,导致AI越来越慢
|
||
2. 考虑真Room的所有字段全部复制给AI
|
||
Room一份。但有个问题在于如何把程序控制流和栈也跳转到一样的地方。所以这个是很难实现的。
|
||
3. 所以考虑用方案1。为了缓解太慢的情况,可以把1和2结合起来。约定好在某个时间点(比如GameLogic:action中的那个死循环执行)就与Room交换数据,然后这时候复盘录像的起始时间点修改。这样的话为了从randomplay恢复状态,就有必要将此时交换的数据额外保存一份。为了能让Logic平安跑到那个时间点,从人凑齐直到那个时间点的录像也要保存一份。
|
||
|
||
6. 解决了模拟和回溯的问题的话,就可以考虑实现该算法了。
|
||
|
||
那么为了模拟,首先得实现一个RandomAI才行。
|
||
|
||
然后还有一项前置工作是服务器端的录像功能。得先做好这个才能进行AI编写啊。所以AI暂且推迟一下好了。
|