石头剪刀布自学习人工智能
前言
先点关注,不迷路
前一段灵光一现,想出了这个算法
不知道以前有没有人写过(应该是有的)
不过我觉得我还是可以大概说一下我的想法
还是那句话,讲得不好勿喷~
思路
既然是自学习,那肯定是得学习的
石头剪刀布这个游戏本身可能是没什么可学的,随机数就可以获得不错的胜率
由于胜负是由两个人的决策决定的,只能通过随机+猜对手的决策来进行决策,不存在永远获胜的方案
因此可以通过学习对手通常的决策或是偏好来提高胜率
另外,石头剪刀布可以抽象成0, 1, 2或1, 2, 3
本人这里用的1, 2, 3(没错,很脏)
存储结构
存储单元:每个存储单元有三个数据组成a1, a2, a3, n分别表示对手出1, 2, 3, 总数的个数
//memory point
struct memPoint{
int _list[4];
int _all;
};
这里用all(n)而不用概率是因为要避免小数
每个的概率就是ai / all
整个存储结构就由很多个存储单元组成
至于多少个,各位可以按照自己的想法自己设计
我这里用了3*3的,表示上一轮我和对手的状态
//0~3->4
memPoint _memMap[4][4];//last turn status->foe decision
所以整个存储结构的意思就是说在上回合的情况下,对手出1,2,3的概率
因为大多数人都是根据上一轮的数据来决定这一轮的决策,这样就可以对一般人有很好的效果了
也可以根据对手的算法来设计自己的存储结构
但注意存储深度越大,学习时间越长
决策
前文说过,没有永远获胜的方案
进行了学习对手的偏好优化后,仍然需要随机数来决策
但由于知道对手当前出i的概率,我们可以针对对手的决策来进行决策
所以在这里,随机数是模拟对手的选择
随机数Mod all+1, 得出一个[1, all] 的数 k
1<=k<=a1 :这种情况下,我们认为对手会出1
a1<k<=a1+a2:这种情况下,我们认为对手会出2
a1+a2<k<=all:这种情况下,我们认为对手会出3
然后模拟出对手的决策,我们就可以出能赢他(她,它)的决策
void Decision(int one, int two, int &res){
int maxNum=_memMap[one][two]._all;
int choose=rand() % maxNum + 1;
int add=0;
if(choose<=_memMap[one][two]._list[1]+add){
res=2;
//cout<<"foe may choose 1, us choose 2"<<endl;
return;
}
add+=_memMap[one][two]._list[1];
if(choose<=_memMap[one][two]._list[2]+add){
res=3;
//cout<<"foe may choose 2, us choose 3"<<endl;
return;
}
res=1;
//cout<<"foe may choose 3, us choose 1"<<endl;
return;
}
这边注意一点初值问题,因为随机数要Mod all, 所以all!=0
但是开始第一局每种决策概率应该相等
又考虑到不能对以后的学习产生太大的影响
所以all=3, ai=1
void GenMem(){
for(int i=0; i<=MAXN; i++){
for(int m=0; m<=MAXN; m++){
for(int k=1; k<=MAXN; k++){
_memMap[i][m]._list[k]=1;
}
_memMap[i][m]._all=3;
}
}
}
顺便提一句,第一局的决策可以存在[0][0]里面,因为开局人也是有偏好的
另外,不要忘记在对手做出决策后存储在记忆数组里哦~
结尾
好了,差不多说完了
代码我到时候会发粉丝专栏
如果有 错误/优化/疑问 欢迎提出
WeChat:wxid_ffe28hxx677f32
(其实是我想认识大佬)
——by于斯为盛