我这个程序在QQ五子棋上实验了一下,结果是黑棋先手全胜,白棋后手的胜率却惨不忍睹,原因有下:
1、五子棋的先手是有优势的,所以职业比赛里都会有禁手来实现公平
2、水平有限,对局面的评估只有一小部分

主要思路就是博弈树,程序向前看一步,对对手可能的走法进行评估,评估的策略主要有两条:

1、扫描整个棋盘,判断出现了多少个三子成线并且两端未堵的情况,对方每出现一种该情况,评估大幅下降,因为这几乎是必堵的,反之评估大幅上升,程序追求的就是这种情况;
2、判断出现了多少个两子成线的情况,这种情况的评估值比上一种要少
此外还有一个几乎是没用的判断,是我从九宫格的评估方案上“拿”过来的,用两种颜色的棋子分别填满棋盘,判断出现了多少个五子成龙的情况,不过很鸡肋
#include <iostream> #include <cstring> #include <string> #include <vector>
#include <queue> #include <cstdio> #include <set> #include <math.h> #include
<algorithm> #include <queue> #define INF 0x3f3f3f3f using namespace std; int
changex=8,changey=8; struct Node { int A[16][16]; int f; }; void mcopy(int
des[16][16],int src[16][16]) { for(int i=1; i<=15; ++i) for(int j=1; j<=15;
++j) des[i][j]=src[i][j]; } bool check(int flag,int tmp[16][16]) { int fflag;
if(flag==0) fflag=1; else fflag=0; //棋谱1:四子连线,端点都在 for(int i=1; i<=15; ++i)
//水平方向 for(int j=1; j<=10; ++j) {
if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag&&tmp[i][j+5]!=fflag)
return true; } for(int i=1; i<=10; ++i) //垂直方向 for(int j=1; j<=15; ++j) {
if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag&&tmp[i+5][j]!=fflag)
return true; } for(int i=1; i<=10; ++i) //正斜方向 for(int j=1; j<=10; ++j) {
if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag&&tmp[i+5][j+5]!=fflag)
return true; } for(int i=1; i<=10; ++i) //反斜方向 for(int j=15; j>=6; --j) {
if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag&&tmp[i+5][j-5]!=fflag)
return true; } //棋谱2:最简单的五子成型 for(int i=1; i<=15; ++i) //水平方向 for(int j=1;
j<=11; ++j) {
if(tmp[i][j]==flag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag)
return true; } for(int i=1; i<=11; ++i) //垂直方向 for(int j=1; j<=15; ++j) {
if(tmp[i][j]==flag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag)
return true; } for(int i=1; i<=11; ++i) //正斜方向 for(int j=1; j<=11; ++j) {
if(tmp[i][j]==flag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag)
return true; } for(int i=1; i<=11; ++i) //反斜方向 for(int j=15; j>=5; --j) {
if(tmp[i][j]==flag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag)
return true; } return false; } int h(int flag,int A[16][16]) { int tmp[16][16];
mcopy(tmp,A); int fflag; if(flag==1) fflag=0; else fflag=1; int val=0;
//出现没有堵住的三子,对己方不利的评价要很高 for(int i=1; i<=15; ++i) //水平方向 for(int j=1; j<=11;
++j) {
if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]==fflag&&tmp[i][j+4]!=flag)
val+= -1000;
if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]!=fflag)
val+= 1000;
/*if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]!=flag&&tmp[i][j+3]==fflag&&tmp[i][j+4]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]!=fflag&&tmp[i][j+3]==flag&&tmp[i][j+4]!=fflag)
val+= 100;*/ } for(int i=1; i<=11; ++i) //垂直方向 for(int j=1; j<=15; ++j) {
if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]==fflag&&tmp[i+4][j]!=flag)
val+= -1000;
if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]!=fflag)
val+= 1000;
/*if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]!=flag&&tmp[i+3][j]==fflag&&tmp[i+4][j]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]!=fflag&&tmp[i+3][j]==flag&&tmp[i+4][j]!=fflag)
val+= 100;*/ } for(int i=1; i<=11; ++i) //正斜方向 for(int j=1; j<=11; ++j) {
if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]!=flag)
val+= -1000;
if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]!=fflag)
val+= 1000;
/*if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]!=flag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]!=fflag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]!=fflag)
val+= 100;*/ } for(int i=1; i<=11; ++i) //反斜方向 for(int j=15; j>=5; --j) {
if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]!=flag)
val+= -1000;
if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]!=fflag)
val+= 1000;
/*if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]!=flag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]!=fflag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]!=fflag)
val+= 100;*/ } //出现未堵住的两子,评价次之 for(int i=1; i<=15; ++i) //水平方向 for(int j=1;
j<=12; ++j) {
if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]!=fflag)
val+= 100; } for(int i=1; i<=12; ++i) //垂直方向 for(int j=1; j<=15; ++j) {
if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]!=fflag)
val+= 100; } for(int i=1; i<=12; ++i) //正斜方向 for(int j=1; j<=12; ++j) {
if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]!=fflag)
val+= 100; } for(int i=1; i<=12; ++i) //反斜方向 for(int j=15; j>=4; --j) {
if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]!=flag)
val+= -100;
if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]!=fflag)
val+= 100; } /*if(val!=0) { return val; }*/ for(int i=1; i<=15; ++i) for(int
j=1; j<=15; ++j) if(tmp[i][j]==8) tmp[i][j]=flag; int sum1=0; for(int i=1;
i<=15; ++i) //水平方向 for(int j=1; j<=11; ++j)
if(tmp[i][j]==flag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag)
sum1++; for(int i=1; i<=11; ++i) //垂直方向 for(int j=1; j<=15; ++j)
if(tmp[i][j]==flag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag)
sum1++; for(int i=1; i<=11; ++i) //正斜方向 for(int j=1; j<=11; ++j)
if(tmp[i][j]==flag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag)
sum1++; for(int i=1; i<=11; ++i) //反斜方向 for(int j=15; j>=5; --j)
if(tmp[i][j]==flag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag)
sum1++; mcopy(tmp,A); for(int i=1; i<=15; ++i) for(int j=1; j<=15; ++j)
if(tmp[i][j]==8) tmp[i][j]=fflag; int sum0=0; for(int i=1; i<=15; ++i) //水平方向
for(int j=1; j<=11; ++j)
if(tmp[i][j]==fflag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]==fflag&&tmp[i][j+4]==fflag)
sum0++; for(int i=1; i<=11; ++i) //垂直方向 for(int j=1; j<=15; ++j)
if(tmp[i][j]==fflag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]==fflag&&tmp[i+4][j]==fflag)
sum0++; for(int i=1; i<=11; ++i) //正斜方向 for(int j=1; j<=11; ++j)
if(tmp[i][j]==fflag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]==fflag)
sum0++; for(int i=1; i<=11; ++i) //反斜方向 for(int j=15; j>=5; --j)
if(tmp[i][j]==fflag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]==fflag)
sum0++; return val+sum1-sum0; } int move1(int A[16][16]) { int
tmp[16][16],num,ans=INF; for(int i=1; i<=15; ++i) for(int j=1; j<=15; ++j)
if(A[i][j]==8) { mcopy(tmp,A); tmp[i][j]=0; //对手下 if(check(0,tmp)) num=-INF;
else num=h(1,tmp); //cout<<num<<endl; ans=min(ans,num); } return ans; } int
move0(int A[16][16]) { int tmp[16][16],num,ans=INF; for(int i=1; i<=15; ++i)
for(int j=1; j<=15; ++j) if(A[i][j]==8) { mcopy(tmp,A); tmp[i][j]=1; //对手下
if(check(1,tmp)) num=-INF; else num=h(0,tmp); //cout<<num<<endl;
ans=min(ans,num); } return ans; } void solve1(Node &node) { int
tmp[16][16],f,ans=-INF,anst[16][16]= {}; for(int i=1; i<=15; ++i) for(int j=1;
j<=15; ++j) if(node.A[i][j]==8) { mcopy(tmp,node.A); tmp[i][j]=1; //自己下
if(check(1,tmp)) { f=move1(tmp); if(f!=-INF) f=INF; } else f=move1(tmp);
//cout<<f<<endl; if(f>ans) { //cout<<f<<endl; ans=f; mcopy(anst,tmp); } }
for(int i=1; i<=15; ++i) for(int j=1; j<=15; ++j) if(node.A[i][j]!=anst[i][j])
{ changex=i; changey=j; break; } mcopy(node.A,anst); node.f=ans;
cout<<ans<<endl; } void solve0(Node &node) { int
tmp[16][16],f,ans=-INF,anst[16][16]= {}; for(int i=1; i<=15; ++i) for(int j=1;
j<=15; ++j) if(node.A[i][j]==8) { mcopy(tmp,node.A); tmp[i][j]=0; //自己下
if(check(0,tmp)) { f=move0(tmp); if(f!=-INF) f=INF; } else f=move0(tmp);
if(f>ans) { //cout<<f<<endl; ans=f; mcopy(anst,tmp); } } for(int i=1; i<=15;
++i) for(int j=1; j<=15; ++j) if(node.A[i][j]!=anst[i][j]) { changex=i;
changey=j; break; } mcopy(node.A,anst); node.f=ans; cout<<ans<<endl; } void
show(int A[16][16]) { int sum=0; for(int i=1; i<=15; ++i) for(int j=1; j<=15;
++j) sum+=A[i][j]; if(sum==0) cout<<"无法继续!"<<endl; else { for(int i=0; i<=15;
++i) { for(int j=0; j<=15; ++j) { if(i==0) { cout<<j<<" "; if(j==0) cout<<" ";
} else if(j==0) { cout<<i<<" "; if(i<10) cout<<" "; } else
if((i==4&&j==4)||(i==4&&j==12)||(i==12&&j==4)||(i==12&&j==12)||(i==changex&&j==changey))
{ if(A[i][j]==8) cout<<".<"; else cout<<A[i][j]<<"<"; } else { if(A[i][j]==8)
cout<<". "; else cout<<A[i][j]<<" "; } if(j>9&&i!=0) cout<<" "; } cout<<endl; }
cout<<endl; } } int main() { int flag=1,myturn,first=1; int i,j; Node node;
for(int i=1; i<=15; ++i) for(int j=1; j<=15; ++j) node.A[i][j]=8;
cout<<"程序执黑棋(1)or白棋(0)?"; cin>>myturn; while(1) { if(flag) { if(flag==myturn) {
if(first)//人工智能第一次不会走中间,因为中间范围的评价相同,所以第一步要强制下在中间 { node.A[8][8]=1; first=0; }
else solve1(node); } else { cout<<"对方的选择是?"; cin>>i>>j; node.A[i][j]=1; }
show(node.A); flag=0; } else { if(flag==myturn) { if(first) {
node.A[i-1][j-1]=0; first=0; } else solve0(node); } else { cout<<"对方的选择是?";
cin>>i>>j; node.A[i][j]=0; } show(node.A); flag=1; } } return 0; }

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信