石头剪刀布人工智能代码详解
石头剪刀布人工智能代码详解
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <time.h>
#define MAXN 3
using namespace std;
struct memPoint{
int _list[4];
int _all;
};
这里就没什么好说的了,stdlib与time都是随机数需要的库
memPoint _mem[4][4];
int _turn=1;
int _win=0;
int _draw=0;
int _lose=0;
_mem是记忆数组,剩下四个整形分别是回合,胜场,平场,负场
_mem[i][m]表示对手出i, 我们出j的状态
_mem[i][m]._all表示这个状态一共经历了几次
_mem[i][m]._list[k]表示这个状态下对手出k出了几次
void GenRand(){
srand(time(0) );
}
void GenMem(){
for(int i=0; i<=MAXN; i++){
for(int m=0; m<=MAXN; m++){
for(int k=1; k<=MAXN; k++){
_mem[i][m]._list[k]=1;
}
_mem[i][m]._all=3;
}
}
}
以上是初始化部分,GenRand是随机数撒种,GenMem在上一篇博客也说过
因为模数不能为零,而又要对后面影响不大,所以选择n=3, a1=a2=a3=1
void Debug(int one, int two){
cout<<"debug"<<endl;/////////////////////
for(int i=1; i<=MAXN; i++){
cout<<_mem[one][two]._list[i]<<" ";
}
cout<<endl;
}
这个没啥用,是我调试的时候用的
void Explain(){
cout<<"welcome to challenge my ai. now, you and my ai will choose a number(1~3), and 2>1, 3>2, 1>3. good luck!"<<endl;
}
这个实际上也没啥用,解释一下玩法
void CurParse(int &res){
cout<<"please input your decision here"<<endl;
int in;
cin>>in;
res=in;
}
输入对手的决策,因为后续可以改输入,还可以汉化
所以我单拎了一个函数,或者说方法
void Decision(int one, int two, int &res){
//cout<<"AI decision"<<endl;///////////
int maxNum=_mem[one][two]._all;
int choose=rand() % maxNum + 1;
//cout<<"rand="<<choose<<endl;/////////////////
//Debug(one, two);//////////////////
int add=0;
if(choose<=_mem[one][two]._list[1]+add){
res=2;
//cout<<"so choose foe may choose 1, us choose 2"<<endl;///////////////
return;
}
add+=_mem[one][two]._list[1];
if(choose<=_mem[one][two]._list[2]+add){
res=3;
//cout<<"so choose foe may choose 2, us choose 3"<<endl;///////////////
return;
}
res=1;
//cout<<"so choose foe may choose 3, us choose 1"<<endl;///////////////
return;
}
这里就是重点了,通过(rand mod k) +1来模拟对手的选择
k在1-a1间,我们认为对手会出1,我们就出2
其他类推
因为我们的区间是
1——a1,a1——a1+a2,a1+a2——n
而不是
1——a1,1——a2,1——a3
(这样的话1到底算在哪里?)
所以需要一个add来记录上次排到哪里了
然后因为每个判断后面都有return,所以不用重复判断
即从第一个判断出来后,我们就认为k>a1
同样,从第二个判断出来后,我们就认为k>a1+a2
所以肯定在第三个区间
void WriteOut(int foe, int us){
cout<<"ai:"<<us<<endl;
if(foe==1&&us==3){
cout<<"you win!!!"<<endl;
_win++;
return;
}
if(foe==3&&us==1){
cout<<"you lose!!!"<<endl;
_lose++;
return;
}
if(foe>us){
cout<<"you win!!!"<<endl;
_win++;
return;
}
if(foe<us){
cout<<"you lose!!!"<<endl;
_lose++;
return;
}
cout<<"draw..."<<endl;
_draw++;
}
这就没啥好说的了,输出赢还是输还是平
void Game(){
int lastFoe=0;
int lastUs=0;
int curFoe;
int curUs;
while(true){
cout<<"turn:"<<_turn<<" win:"<<_win<<" draw:"<<_draw<<" lose:"<<_lose<<endl;
Decision(lastFoe, lastUs, curUs);
CurParse(curFoe);
WriteOut(curFoe, curUs);
_mem[lastFoe][lastUs]._list[curFoe]++;
_mem[lastFoe][lastUs]._all++;
lastFoe=curFoe;
lastUs=curUs;
_turn++;
}
}
有了上面的决策函数,这里主要就是纪律上次的决策,从记忆数组里取(Decision)
然后刷新后再放回去
int main(){
cout<<"generating rand decision"<<endl;
GenRand();
cout<<"generating first memory"<<endl;
GenMem();
cout<<"start!"<<endl;
Explain();
Game();
return 0;
}
主程序就一个一个调就行了
好了,差不多讲完了
如果有 错误/优化/疑问 欢迎提出
WeChat:wxid_ffe28hxx677f32(其实是我想认识大佬)
——by 于斯为盛
本文地址:https://blog.csdn.net/maxChang_algha/article/details/107297403