一直想给这个游戏加一个RL的大脑。
我为了确定要用到哪些状态,和动作,以及奖励,回合的定义。
我设想了一个最简单逻辑,此处存活的敌机群它们的x坐标的平均值avg_x,以及我方飞机的x坐标m_hero.m_X,让我方飞机向敌机群靠近打击,avg_x比m_hero.m_X小则向右移动,avg_x比m_hero.m_X大则向左移动。
动作:action:一维,0表示不动,1表示向左移,2表示向右移。
奖励:子弹碰到一架敌机则记1分
回合结束:我方飞机的机身与敌方飞机的机身发生碰撞。
状态的设置可以是很多情况:
Atari游戏是直接把游戏界面的像素点组成的数组作为状态,数据量太大了。必须要用带神经网络的RL算法。
我想的状态是:敌机群的平均x坐标,我那个游戏界面有多宽就有多少种状态,外加我方飞机的x坐标。
还可以进一步简化状态:0:敌机群在我方飞机左边;1:敌机群在我方飞机右边;
目前的问题:我还没有交互呢,只是把Q-learning的python脚本嵌入进去了,让他不报错,它就卡的不要不要的。
我在C++里面实例化python的Q-table类,死活不行。卡在这里好几天了。蚌埠住了。T_T.
谁来救救我啊......
重新去看了python的迷宫Q-table代码,研究了传给Q-table的action必须是一个列表,改正传递的参数后,总算能实例化了。
接下来的问题是:调用choose_action()和learn()函数不成功,我估计是由于我传的参数类型不对。
还有就是python代码区分了s和s_,我的游戏环境没有区分当前时刻和下一时刻的状态。准确的说我做的这个环境不太规范,没有像gym环境那样标准的接口。还是需要静下心来看看,人家怎么搭建的环境。
好家伙!改来改去,直接程序中断运行:
E:\Program_Files\SogouInput\Components\
20:21:56: 程序异常结束。
参数传入不对会直接影响python函数是否获得成功
重新用一个小demo来实现我想要的功能,看是否能成功,能成功再放到大的工程里面。
C++传入到python的所有元素都是元祖类型,不能进行加操作
发现必须把python释放掉(用Py_Finalize()),才会显示c中内容;
int add=1;
//char* s="";
PyObject* pGet_age=PyObject_CallMethod(pInstance,"getage",NULL);
if(!pGet_age){
qDebug()<<"get getage() failed"<<endl;
}
PyObject* pSet_age=PyObject_CallMethod(pInstance,"setage","i",add);
if(!pSet_age){
qDebug()<<"get setage() failed"<<endl;
}
//age = PyTuple_GetItem(pArgs,0);
//PyObject_CallMethod(pInstance,"getage",NULL,NULL);
PyArg_Parse(pSet_age,"i",&age);
//结束,释放python
Py_Finalize();
qDebug()<<"age:"<<age<<endl;
经过了一段时间的挣扎,最终我放弃了这种嵌入python脚本的方式。在demo下能正常运行的代码,到了大工程就运行不了,感觉是C++与python的交互太快,而这个交互需要进行的类型转换太复杂,cpu根本忙不过来,所以一运行就中断。
我用C++写了一个Q-learning,建立了一个2行3列的Q数组,只有敌机群在飞机左边或右边两种状态和不动,左移,右移三个动作,走错方向,奖励值为-1;原地不动奖励0;走对方向打下敌机,奖励值加1.最终Q数组会收敛到类似于这样的状态。
需要注意:
1.Q-table的初始值的设置会影响智能程度,实际上就是就是奖励值的设置。
2.如果走错方向,或者原地不动没有惩罚的话,它可能会选择原地不动。
3.Q-table的更新需要有探索。
4.初始存在sparse reward,可以考虑模仿学习。
总结:让RL玩游戏其实有两种途径:①把游戏做成一个RL的环境给python算法;②把python算法作为大脑给游戏。本次实践选的②的方案,但仍然在嵌入方面出现了问题。用C++可以写一些简单RL算法,但当状态,动作维数增大,就需要引入神经网络了,但涉及神经网络的算法大部分都是用python写的,所以个人感觉用C++写RL算法可扩展性差。之后都会选择①了。