最近要完成大作业,我设计了一个人机对战模式的五子棋游戏,其实五子棋除了人机对战模式其他的模式都很简单,只有人机对战模式最难。自己实现的这个程序电脑会判断是不是需要阻挡玩家,如果不需要电脑就会按照它自己的思路连成线,如果前两者都不可以,拿就用随机数函数在玩家最后一个棋子周围随机生成一个坐标。
不过自己写的这个程序,电脑还是不够智能,原因在于电脑决策前对于棋盘的遍历检查和判断的方式不够好,对于这个程序还是要进行优化,如果进行优化,就是对电脑下棋方式进行优化,在玩家落子之后进行怎么样的一个判断会更好。应该是把棋盘全部遍历一遍不仅仅关注玩家是否要赢,还要根据规则对整个棋盘进行一个完整的判断(在自己的算法能力提高以后再优化吧!)
//-----------------------五子棋游戏------------------------
//
// 实现一个五子棋的单机游戏,仅仅实现人机对战,人人对战十
// 分简单,没有实质性意义,在字符数字混合输入时,一定注意回车符
//
// Y:完成一局之后继续下一局 N:退出游戏
// 游戏中若玩家输入两个0表示玩家想要退出游戏
// 越写发现情况越多,越无法解决这个问题。
//----------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
//------------------------【全局变量声明】-------------------
//用了很多全局变量,目的是在各函数之间通信
char chessboard[16][16]; //存储棋盘数据
int side_1=0; //记录棋手走的步数,当一局对战结束时应当置为0
int side_2=0;
char choice;
int row; int col; //记录某一方输入的位置
int flag_1=0; //记录玩家输赢的标志
int flag_2=0; //记录电脑输赢的标志
int sum[5]; //存放玩家或电脑下棋后四个方向的棋子数
int record_row=0,record_col=0; //记录电脑上一次下的地方
//-----------------------------------------------------------
//------------------------【实现函数声明】--------------------
void show_chessboard();
void model_input();
void play_input();
void com_input(); //是这个程序最难的地方
int judge();
int evaluate(int x,int y);
int ready_DSS();
//------------------------------------------------------------
//-------------------------【主程序入口】----------------------
int main()
{
printf("----------------------------五子棋游戏--------------------------\n");
printf(" Y:打完一局之后继续 N:退出游戏\n");
printf(" 玩家输入'0 0'表示玩家想中途退出\n");
printf("----------------------------------------------------------------\n\n\n");
tag_1: memset(chessboard,' ',500);
printf("是否要开始对战?Y or N\n");
model_input();
if(choice=='Y')
{
show_chessboard();
printf("玩家步数:%d 电脑步数:%d\n",side_1,side_2);
while(1)
{
play_input();
show_chessboard();
printf("玩家步数:%d 电脑步数:%d\n",side_1,side_2);
if((flag_1=evaluate(row,col))==1)
break;
com_input();
show_chessboard();
printf("玩家步数:%d 电脑步数:%d\n",side_1,side_2);
if((flag_2=evaluate(row,col))==1)
break;
}
if(flag_1==1)
printf("聪明的玩家你赢啦!\n");
else
printf("不好意思你输了!\n");
printf("继续玩吗? Y or N\n");
model_input();
if(choice=='Y')
goto tag_1;
else
exit(1);
}
return 0;
}
//-------------------------------------------------------------
//-----------------------【打印棋盘的函数】--------------------
void show_chessboard()
{
system("cls"); //先清理之前的,然后输出新的棋盘
printf(" 五子棋游戏,人机对战!\n\n");
//i为列号,j为行号
int i,j,k;
for(i=0;i<=30;i++)
{
if(i==0)
{
for(j=0;j<=15;j++)
{
if(j==0)
printf(" ");
else
{ if(j<10)
printf("%d ",j);
else
printf("%d ",j);
}
}
printf("\n");
}
else
{
if(i%2==1)
{
printf(" |");
for(j=1;j<=15;j++)
{
printf("--|");
}
}
else
{
printf("%d",i/2);
if(i/2<10)
printf(" |");
else
printf("|");
for(j=1;j<=15;j++)
{
printf("%c |",chessboard[i/2][j]);
}
}
printf("\n");
}
}
for(k=0;k<=15;k++)
{
if(k==0)
printf(" |");
else
printf("--|");
}
printf("\n");
}
//------------------------------------------------------------------------
//---------------------------【判定输赢的函数】---------------------------
int evaluate(int x,int y)
{
//以(x,y)为中心判断输赢
int i,j;
sum[1]=0,sum[2]=0,sum[3]=0,sum[4]=0;
//先查横边
for(i=x,j=y-1;j>=1;j--) //向前
{
if(chessboard[i][j]==chessboard[x][y])
sum[1]++;
else
break; //因为棋子必须是连续的,所以这里必须跳出来
}
for(i=x,j=y+1;j<=20;j++) //向后
{
if(chessboard[i][j]==chessboard[x][y])
sum[1]++;
else
break;
}
if(sum[1]>=4)
return 1;
//查竖边
for(i=x-1,j=y;i>=1;i--) //向上
{
if(chessboard[i][j]==chessboard[x][y])
sum[2]++;
else
break;
}
for(i=x+1,j=y;i<=20;i++) //向下
{
if(chessboard[i][j]==chessboard[x][y])
sum[2]++;
else
break;
}
if(sum[2]>=4)
return 1;
//查左方向斜边
for(i=x-1,j=y-1;i>=1&&j>=i;i--,j--)
{
if(chessboard[i][j]==chessboard[x][y])
sum[3]++;
else
break;
}
for(i=x+1,j=y+1;i<=20&&j<=20;i++,j++)
{
if(chessboard[i][j]==chessboard[x][y])
sum[3]++;
else
break;
}
if(sum[3]>=4)
return 1;
//查右方向斜边
for(i=x-1,j=y+1;i>=1&&j>=i;i--,j++)
{
if(chessboard[i][j]==chessboard[x][y])
sum[4]++;
else
break;
}
for(i=x+1,j=y-1;i<=20&&j<=20;i++,j--)
{
if(chessboard[i][j]==chessboard[x][y])
sum[4]++;
else
break;
}
if(sum[4]>=4)
return 1;
return 0;
}
//-------------------------------------------------------------------
//-------------------------【玩家输入棋子函数】----------------------
void play_input()
{
//玩家对应的棋子标准为o
printf("请落子:");
scanf("%d %d",&row,&col);
getchar();
if(row==0&&col==0)
{
exit(1);
}
if(row<1||row>15||col<1||col>15||chessboard[row][col]!=' ')
{
printf("下错区域!");
play_input();
}
else
{
chessboard[row][col]='o';
printf("\n%d %d\n",row,col);
side_1++;
}
}
//-------------------------------------------------------------------
//-------------------------【模式选择输入函数】----------------------
void model_input()
{
while(scanf("%c",&choice)==1)
{
getchar(); //拿走输入流中的换行符
if(choice=='Y'||choice=='N')
{
break;
}
else
{
printf("请输入正确的选择:");
}
}
}
//--------------------------------------------------------------------
//--------------------------【电脑下棋函数】--------------------------
//利用随机数函数生成坐标,且坐标并不随意,根据玩家下棋的位置和前一次
//生成的坐标确定,使电脑选择的棋子位置有实际意义
int judge()
{
int i;
for(i=1;i<5;i++)
{
if(sum[i]>=2)
return i;
}
return 0;
}
void com_input()
{
int k,i,j,y=0;//y作为防止电脑练下两步的关键字
int max=ready_DSS();
if(max==0)
goto tag_2;
if((k=judge())!=0&&max!=4) //首先要做的就是判断是不是要挡一下玩家
{
if(k==2)
{
for(i=row-1,j=col;i>=1;i--)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j; //为了让判断输赢的函数能够判断
y=1;
break;
}
if(chessboard[i][j]=='x')
break;
}
if(y==0)
{
for(i=row+1,j=col;i<=15;i++)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
break;
}
}
}
}
else if(k==1)
{
for(i=row,j=col-1;j>=1;j--)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j; //为了让判断输赢的函数能够判断
y=1;
break;
}
if(chessboard[i][j]=='x')
break;
}
if(y==0)
{
for(i=row,j=col+1;j<=15;j++)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
break;
}
}
}
}
else if(k==3)
{
for(i=row-1,j=col-1;j>=1&&i>=1;j--,i--)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
y=1;
break;
}
if(chessboard[i][j]=='x')
break;
}
if(y==0)
{
for(i=row+1,j=col+1;i<=15&&j<=15;j++,i++)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
break;
}
}
}
}
else if(k==4)
{
for(i=row-1,j=col+1;j<=15&&i>=1;j++,i--)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
y=1;
break;
}
if(chessboard[i][j]=='x')
break;
}
if(y==0)
{
for(i=row+1,j=col-1;i<=15&&j>=1;j--,i++)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
break;
}
}
}
}
}
else
{
int execute=0; //这个用于判断后续操作是否需要执行
int s=record_row,t=record_col,sum=1;
for(i=s,j=t-1;j>=1;j--) //向前
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
for(i=s,j=t+1;j<=20;j++) //向后
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
if(max==sum)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
record_row=i; record_col=j;
execute=1;
}
else
{
if(chessboard[i][j-max-1]==' ')
{
chessboard[i][j-max-1]='x';
side_2++;
row=i; col=j-max-1;
record_row=i;
record_col=j-max-1;
execute=1;
}
}
}
if(execute==0)
{
sum=1; //这个初始化相当重要,不能忘记
for(i=s-1,j=t;i>=1;i--) //向上
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
for(i=s+1,j=t;i<=20;i++) //向下
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
if(max==sum)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
record_row=i; record_col=j;
execute=1;
}
else
{
if(chessboard[i-max-1][j]==' ')
{
chessboard[i-max-1][j]='x';
side_2++;
row=i-max-1; col=j;
record_row=i-max-1;
record_col=j;
execute=1;
}
}
}
}
if(execute==0)
{
sum=1;
for(i=s-1,j=t-1;i>=1&&j>=1;i--,j--) //向左上
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
for(i=s+1,j=t+1;i<=20&&j<=20;i++,j++) //向下
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
if(max==sum)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
record_row=i; record_col=j;
execute=1;
}
else
{
if(chessboard[i-max-1][j-max-1]==' ')
{
chessboard[i-max-1][j-max-1]='x';
side_2++;
row=i-max-1; col=j-max-1;
record_row=i-max-1;
record_col=j-max-1;
execute=1;
}
}
}
}
if(execute==0)
{
sum=1;
for(i=s+1,j=t-1;i<=20&&j>=1;i++,j--) //向左下
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
for(i=s-1,j=t+1;i>=1&&j<=20;i--,j++) //向下
{
if(chessboard[i][j]==chessboard[s][t])
sum++;
else
break;
}
if(max==sum)
{
if(chessboard[i][j]==' ')
{
chessboard[i][j]='x';
side_2++;
row=i; col=j;
record_row=i; record_col=j;
execute=1;
}
else
{
if(chessboard[i+max+1][j-max-1]==' ')
{
chessboard[i+max+1][j-max-1]='x';
side_2++;
row=i+max+1; col=j-max-1;
record_row=i+max+1;
record_col=j-max-1;
execute=1;
}
}
}
}
if(execute==0)
{
tag_2: srand((unsigned int)time(NULL));//不需要挡对手自己也无法连在一起
int m,n;
while(1)
{
m=rand()%5+row-2;
n=rand()%5+col-2;
if(chessboard[m][n]==' ')
{
chessboard[m][n]='x';
row=m; col=n;
side_2++;
record_row=m;
record_col=n;
break;
}
}
}
}
}
//---------------------------------------------------------------------
//---------------------------【局势判断函数】--------------------------
//这个函数帮助电脑决策应该怎么下,是阻挡玩家,随机生成还是完成一条线。
int ready_DSS()
{
int i,j,x=record_row,y=record_col;
int sum1=1,sum2=1,sum3=1,sum4=1,max;
if(x==0&&y==0)
{
max=0;
return max;
}
//先查横边
for(i=x,j=y-1;j>=1;j--) //向前
{
if(chessboard[i][j]==chessboard[x][y])
sum1++;
else
break; //因为棋子必须是连续的,所以这里必须跳出来
}
for(i=x,j=y+1;j<=20;j++) //向后
{
if(chessboard[i][j]==chessboard[x][y])
sum1++;
else
break;
}
max=sum1;
//查竖边
for(i=x-1,j=y;i>=1;i--) //向上
{
if(chessboard[i][j]==chessboard[x][y])
sum2++;
else
break;
}
for(i=x+1,j=y;i<=20;i++) //向下
{
if(chessboard[i][j]==chessboard[x][y])
sum2++;
else
break;
}
if(sum2>max)
max=sum2;
//查左方向斜边
for(i=x-1,j=y-1;i>=1&&j>=i;i--,j--)
{
if(chessboard[i][j]==chessboard[x][y])
sum3++;
else
break;
}
for(i=x+1,j=y+1;i<=20&&j<=20;i++,j++)
{
if(chessboard[i][j]==chessboard[x][y])
sum3++;
else
break;
}
if(sum3>max)
max=3;
//查右方向斜边
for(i=x-1,j=y+1;i>=1&&j>=i;i--,j++)
{
if(chessboard[i][j]==chessboard[x][y])
sum4++;
else
break;
}
for(i=x+1,j=y-1;i<=20&&j<=20;i++,j--)
{
if(chessboard[i][j]==chessboard[x][y])
sum4++;
else
break;
}
if(sum4>max)
max=sum4;
return max;
}