目录
手敲800多行代码,搞了6个小时,终于写完了五子棋博弈问题,艰难!(以下纯属个人思路,仅供参考,创作不易,禁止搬运)
希望对大家有帮助。
1.课题要求
还记得我们在第一章 见过的“人机对弈”那个例子吗?现在就请你利用自己所学的知识,设计一一个“ 五子棋”对弈程序吧。注意:你所设计的‘对弈程序”的对手是人,因此你的“对弈程序”也要具有一定的智能:能赢就绝不平局,最差的结果也就是平局。要求:
(1)当用户执子时,需在界面上输入落棋的位置。
(2) 当用户落子后,“对弈程序”在两秒后给出落子位置。
(3) 每当一方落子后,要刷新棋盘状态。
(4)棋盘大小为15*15。
2.思路
又加了一个人-人PK。
(1)判断输赢,只可能在当前落子的位置判断输赢
(2)电脑所要执行的操作:
a.当用户已经构成3子的时候,此时电脑必须拦截用户所下的第4个棋子的
落子位置,如果拦截失败,用户在某种意义上面已经取得胜利,只需要走
接下来的操作即可,此时用户胜利;如果拦截成功,则继续游戏,但是还有
一种情况,当用户连成3子的话,此时电脑已经连成3子了,此时电脑下连成
3子的位置.
b.如果用户没有构成3子的话,电脑可以走自己的步数,一次搜索有没有构
成4个棋子的,如果有,则落下此棋子;如果没有4个棋子的,再搜索有没有
3个棋子,...,择优进行选择,能赢一定赢.
c.当落满整个棋盘上面的棋子的时候,和局.
3.源代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stdlib.h>
using namespace std;
const int N=1100;
string mp[N][N];//棋盘
int st[N][N];//标记
int n,m;//棋盘大小
bool vis[N][N];
void menu()//菜单
{
printf("**********欢迎来到五子棋小游戏**********\n");
printf("********** 1.人-机PK ***********\n");
printf("********** 2.人-人PK ***********\n");
printf("********** 3.退出 ***********\n");
printf("***************************************\n");
}
int search(int x,int y,int dx[],int dy[],int ans,int op)//搜索连成几个棋子
{
for(int i=1;i<=4;i++)
{
int l=x+dx[i],r=y+dy[i];
if(l>=1&&l<=n&&r>=1&&r<=m&&st[l][r]==op) ans++;
else break;
}
return ans;
}
bool check(int x,int y,int op)//判断输赢,只可能在当前落子的位置判断输赢
{
int ans;
int dx[5],dy[5];
//正对角线
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=-i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
//反对角线
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=-i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
//横向
ans=1;
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=-i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=i;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
//纵向
ans=1;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=0;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=0;
ans=search(x,y,dx,dy,ans,op);
if(ans>=5) return true;
return false;
}
bool check2()//判断是否和局
{
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(st[i][j]) ans++;
if(ans==n*m) return true;//已经落满所有的位置
return false;
}
void init()//初始化棋盘
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mp[i][j]="#";
}
void print()//打印棋盘
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(i==0&&j!=0)
{
cout<<j<<" ";
}
else if(i!=0&&j==0)
{
cout<<i<<" ";
}
else if(i==0&&j==0) cout<<" ";
else cout<<mp[i][j]<<" ";
}
puts("");
}
}
void print2(int f)//显示黑白棋子
{
if(f==1) cout<<"(黑子):";
else cout<<"(白子):";
}
void check3(int f,int &a,int &b)//电脑检测落子的位置
{
//寻找电脑是否连成3子
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(st[i][j]==3-f)//如果是电脑下的棋子
{
int ans;
int dx[5],dy[5];
//正对角
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r--;
if(l&&r&&!st[l][r]&&st[l-1][r-1]!=f&&l-1&&r-1)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r++;
if(l&&r&&!st[l][r]&&st[l+1][r+1]!=f&&l+1<=n&&r+1<=m)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//反对角线
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r++;
if(l&&r&&!st[l][r]&&st[l-1][r+1]!=f&&l-1>=1&&r+1<=m)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r--;
if(l&&r&&!st[l][r]&&st[l+1][r-1]!=f&&l+1<=n&&r-1)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//横向
ans=1;
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) r--;
if(l&&r&&!st[l][r]&&st[l][r-1]!=f&&r-1)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]&&l>=1&&l<=n&&r>=1&&r<=m&&!vis[l][r]) r++;
if(l&&r&&!st[l][r]&&st[l][r+1]!=f&&r+1<=m)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//纵向
ans=1;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=0;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]&&l>=1&&l<=n&&r>=1&&r<=m) l++;
if(l&&r&&!st[l][r]&&st[l+1][r]!=f&&l+1<=n)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=0;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]&&l>=1&&l<=n&&r>=1&&r<=m) l--;
if(l&&r&&!st[l][r]&&st[l-1][r]!=f&&l)
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
}
}
}
//拦截用户
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(st[i][j]==f)//如果是用户下的棋子
{
int ans;
int dx[5],dy[5];
//正对角
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r++;
if(l&&r&&!st[l][r]&&!vis[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//反对角线
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//横向
ans=1;
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=-i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=i;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) r++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//纵向
ans=1;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=0;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=0;
ans=search(i,j,dx,dy,ans,f);
if(ans>=3)
{
int l=i,r=j;
while(st[l][r]==f&&l>=1&&l<=n&&r>=1&&r<=m) l--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
}
}
}
//都没有拦截的话
for(int k=2;k>=1;k--)
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(st[i][j]==3-f)//如果是电脑下的棋子
{
int ans;
int dx[5],dy[5];
//正对角
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//反对角线
ans=1;
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l--,r++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l++,r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//横向
ans=1;
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=-i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) r--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=0,dy[i]=i;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) r++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
//纵向
ans=1;
for(int i=1;i<=4;i++) dx[i]=i,dy[i]=0;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l++;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
for(int i=1;i<=4;i++) dx[i]=-i,dy[i]=0;
ans=search(i,j,dx,dy,ans,3-f);
if(ans>=k)
{
int l=i,r=j;
while(st[l][r]==3-f&&l>=1&&l<=n&&r>=1&&r<=m) l--;
if(l&&r&&!st[l][r])
{
st[l][r]=3-f;
if(3-f==1) mp[l][r]="○";//黑子
else if(3-f==2) mp[l][r]="●";//白子
a=l,b=r;
return ;
}
}
}
}
}
//白子为空
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!st[i][j])
{
st[i][j]=3-f;
if(3-f==1) mp[i][j]="○";//黑子
else if(3-f==2) mp[i][j]="●";//白子
a=i,b=j;
return ;
}
}
void game1()//人-机PK
{
init();
int f;
cout<<"***1.黑子***"<<endl;
cout<<"***2.白子***"<<endl;
cout<<"请用户选择一个棋子的颜色:";
while(1)
{
cin>>f;
if(f==1||f==2) break;
else cout<<"序号错误!请重新选择:";
}
//此时用户选择的一定是1或者2,那么电脑的选择为3-f
memset(vis,false,sizeof vis);
while(1)
{
system("cls");
print();
int x,y;
cout<<"请用户选择一个坐标";
print2(f);
while(1)
{
cin>>x>>y;
if(st[x][y])
{
cout<<"该位置已落子,请用户重新输入:";
print2(f);
}
else
{
st[x][y]=f;
if(f==1) mp[x][y]="○";//黑子○
else mp[x][y]="●";//白子
if(check(x,y,f))
{
system("cls");
print();
cout<<"用户取得胜利!"<<endl;
return ;
}
break;
}
}
system("cls");
print();
_sleep(1000);//延时1s
/*电脑所要执行的操作:
1.当用户已经构成3子的时候,此时电脑必须拦截用户所下的第4个棋子的
落子位置,如果拦截失败,用户在某种意义上面已经取得胜利,只需要走
接下来的操作即可,此时用户胜利;如果拦截成功,则继续游戏,但是还有
一种情况,当用户连成3子的话,此时电脑已经连成3子了,此时电脑下连成
3子的位置.
2.如果用户没有构成3子的话,电脑可以走自己的步数,一次搜索有没有构
成4个棋子的,如果有,则落下此棋子;如果没有4个棋子的,再搜索有没有
3个棋子,...,择优进行选择,能赢一定赢.
3.当落满整个棋盘上面的棋子的时候,和局.*/
int a,b;
check3(f,a,b);
if(check(a,b,3-f))
{
system("cls");
print();
cout<<"很遗憾,电脑获胜!"<<endl;
return ;
}
if(check2())//落满所有的棋子时--平局
{
cout<<"您和电脑平局!"<<endl;
return ;
}
}
}
void game2()//人-人PK
{
init();
//st==1标记黑子,st==2标记白子
int f=2;
while(1)
{
system("cls");
print();
if(f%2==0)
{
int x,y;
cout<<"请您选择一个坐标(黑子):";
while(1)
{
cin>>x>>y;
if(st[x][y]) cout<<"该位置已落子,请您重新输入(黑子):";
else
{
st[x][y]=1;
mp[x][y]="○";//黑子○
if(check(x,y,1))
{
system("cls");
print();
cout<<"黑子胜!"<<endl;
return ;
}
break;
}
}
}
else
{
int x,y;
cout<<"请您选择一个坐标(白子):";
while(1)
{
cin>>x>>y;
if(st[x][y]) cout<<"该位置已落子,请您重新输入(白子):";
else
{
st[x][y]=2;
mp[x][y]="●";//白子
if(check(x,y,2))
{
system("cls");
print();
cout<<"白子胜!"<<endl;
return ;
}
break;
}
}
}
if(check2())
{
cout<<"黑白棋子平局!"<<endl;
return ;
}
f++;
if(f==4) f=2;
}
}
int main()
{
while(1)
{
memset(st,0,sizeof st);
m=9,n=9;
menu();
int op;
printf("请选择一个模式:");
cin>>op;
switch (op)
{
case 1:game1();break;
case 2:game2();break;
case 3:printf("感谢您的使用!");return 0;break;
default:cout<<"序号错误,请重新输入!"<<endl;break;
}
}
}
电脑判定用户落子还需要完善,这个程序只是拦截简单的用户落子,用户很容易取胜,后期会加强电脑检测用户落子的位置,代码也会更新。