欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

石头剪刀布人工智能代码详解

程序员文章站 2022-06-23 09:42:25
石头剪刀布人工智能代码详解#include #include #include #include #define MAXN 3using namespace std;struct memPoint{int _list[4];int _all;};这里就没什么好说的了,stdlib与time都是随机数需要的库memPoint _mem[4][4];in...

石头剪刀布人工智能代码详解

#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