大一上学期的时候,学校布置了C语言期末大作业,当时借鉴了许多CSDN上大佬的想法,半年多后想起来,决定将代码上传,共同学习。(当时是小白第一次进行较为复杂的代码,可能有些乱,多包涵!!!) 1.头文件及全局定义
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <Windows.h>
#include <ctime>
#include <cstdlib>
int t2[361];
void InitBoard(char a[20][20],int row,int col)
{
memset(a,' ',row*col*sizeof(char));
}
2.棋盘
void qi(char a[20][20])
{
for(int i=1;i<20;i++)
{
if(i==1)
{
printf(" ");
for(int m=0;m<19;m++)
{
printf("|%02d",m+1);
}
printf("\n");
for(int n=0;n<20;n++)
{
printf("---");
}
}
printf("\n");
printf("%02d",i);
for(int j=1;j<20;j++)
{
if(j!=19)
{
printf("| %c",a[i][j]);
}
if(j==19)
{
printf("| %c|",a[i][j]);
}
}
printf("\n");
for(int k=0;k<20;k++)
{
printf("-- ");
}
}
printf("\n");
}
棋盘较为简洁,主要是数组加上想象。
3.落子(人)
void ren(char a[20][20])
{
while(1)
{
printf("请选择落子行列:");
int x,y;
scanf("%d%d",&x,&y);
if((x<=0)||(x>=20)||(y<=0)||(y>=20))
{
printf("阁下莫不是老眼昏花了?\n");
continue;
}
if(a[x][y]!=' ')
{
printf("这是何意?\n");
continue;
}
a[x][y]='x';
break;
}
system("cls");
qi(a);
}
人这里主要是判断落子处是否出界,或者落在已经有子的地方。
4.落子(机)
int judge(char a[20][20],int i,int j)
{
int m=0;
int n1=1;
int n2=1;
int x1,y1;
int x2,y2;
int X[8]={0,0,1,1,1,-1,-1,-1};
int Y[8]={1,-1,0,1,-1,0,1,-1};
for(int k=0;k<8;k++)
{
x1=i+X[k];
y1=j+Y[k];
while(a[x1][y1]=='o')
{
m=m+n1;
x1=x1+X[k];
y1=y1+Y[k];
n1++;
if((n1==4)&&(a[x1][y1]==' '))
{
m=m+100;
}
if((n1==3)&&(a[x1-4*X[k]][y1-4*Y[k]]=='o')&&(a[x1-5*X[k]][y1-5*Y[k]]==' ')&&(a[x1][y1]==' '))
{
m=m+100;
}
if((n1==3)&&(a[x1][y1]==' ')&&(a[x1-4*X[k]][y1-4*Y[k]]==' ')&&(a[x1-3*X[k]+X[k+1]][y1-3*Y[k]+Y[k+1]]=='o')&&(a[x1-3*X[k]+2*X[k+1]][y1-3*Y[k]+2*Y[k+1]]=='o')&&(a[x1-3*X[k]+3*X[k+1]][y1-3*Y[k]+3*Y[k+1]]==' '))
{
m=m+500;
}
if((n1==5)&&(a[x1][y1]=='x'))
{
m=m+20000;
}
if((n1==5)&&((x1==0)||(x1==20)||(y1==0)||(y1==20)))
{
m=m+20000;
}
if((n1==3)&&(a[x1-4*X[k]][y1-4*Y[k]]=='o')&&(a[x1-5*X[k]][y1-5*Y[k]]=='o'))
{
m=m+20000;
}
if((n1==4)&&(a[x1-5*X[k]][y1-5*Y[k]]=='o'))
{
m=m+20000;
}
}
x2=i+X[k];
y2=j+Y[k];
while(a[x2][y2]=='x')
{
m=m+1;
m=m+n2;
x2=x2+X[k];
y2=y2+Y[k];
n2++;
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]==' ')&&((a[x2][y2]=='o')||(a[x2-6*X[k]][y2-6*Y[k]]=='o')))
{
m=m+500;
}
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]==' ')&&(a[x2][y2]==' '))
{
m=m+1000;
}
if((n2==4)&&(a[x2][y2]==' '))
{
m=m+1000;
}
if((n1==3)&&(a[x1][y1]==' ')&&(a[x1-4*X[k]][y1-4*Y[k]]==' ')&&(a[x1-3*X[k]+X[k+1]][y1-3*Y[k]+Y[k+1]]=='x')&&(a[x1-3*X[k]+2*X[k+1]][y1-3*Y[k]+2*Y[k+1]]=='x')&&(a[x1-3*X[k]+3*X[k+1]][y1-3*Y[k]+3*Y[k+1]]==' '))
{
m=m+3000;
}
if((n2==5)&&(a[x2][y2]=='o'))
{
m=m+6000;
}
if((n2==5)&&((x2==0)||(x2==20)||(y2==0)||(y2==20)))
{
m=m+6000;
}
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]=='x'))
{
m=m+6000;
}
if((n2==4)&&(a[x2-5*X[k]][y2-5*Y[k]]=='x'))
{
m=m+6000;
}
}
n1=1;
n2=1;
}
return m;
}
void ai(char a[20][20])
{
int max=0;
int x=0;
int y=0;
int k=0;
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
int n=judge(a,i,j);
if(n>max)
{
max=n;
x=i;
y=j;
}
}
}
}
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
int m=judge(a,i,j);
if(m==max)
{
t1[k]=i;
t2[k]=j;
k++;
}
}
}
}
srand((unsigned)time(NULL));
int z=rand()%k;
a[t1[z]][t2[z]]='o';
system("cls");
qi(a);
printf("上一步棋为(%d,%d),凡人你对付的了吗?\n",t1[z],t2[z]);
}
机器部分应该是最难的地方,我写这段代码的时候才大一上,CSDN上大佬写的剪枝算法等等根本看不懂,后来无意看到一篇文章(已找不到),通过设置两个一维数组来模拟一个棋子上下左右,及四个斜对角的位置,通过不断运行,来判断该方向上的棋子数目,在根据其已有数目来赋以对应的权值,最后通过穷举所有位置,计算最大值。这种方法说不得高明,只是对于当时大一的我恰到好处,因为需要自行赋分,所以代码人的棋艺决定了AI的上限,比如我的水平较差,AI连进攻都不会。
5.判断是否落满
int full(char a[20][20])
{
int b=1;
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
b=0;
break;
}
}
}
return b;
}
6.判断输赢
char win(char a[20][20])
{
for(int i=5;i<20;i++)
{
for(int j=1;j<16;j++)
{
if((a[i][j]==a[i-1][j+1])&&(a[i][j]==a[i-2][j+2])&&(a[i][j]==a[i-3][j+3])&&(a[i][j]==a[i-4][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
}
}
for(int i=1;i<16;i++)
{
for(int j=1;j<16;j++)
{
if((a[i][j]==a[i+1][j])&&(a[i][j]==a[i+2][j])&&(a[i][j]==a[i+3][j])&&(a[i][j]==a[i+4][j])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if((a[i][j]==a[i][j+1])&&(a[i][j]==a[i][j+2])&&(a[i][j]==a[i][j+3])&&(a[i][j]==a[i][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if((a[i][j]==a[i+1][j+1])&&(a[i][j]==a[i+2][j+2])&&(a[i][j]==a[i+3][j+3])&&(a[i][j]==a[i+4][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if(full(a))
{
return '0';
}
}
}
return NULL;
}
判断输赢只是简单的穷举加规则,当有五个相同时,输出即可。
7.输出结果
void jieguo(char a[20][20])
{
char d=win(a);
if(d=='x')
{
printf("佩服佩服!");
}
if(d=='o')
{
printf("就这点手段?");
}
if(d=='0')
{
printf("竟然与我一成功力打成平手!!!");
}
}
8.包装组合
void game(char a[20][20])
{
InitBoard(a,20,20);
qi(a);
while(1)
{
ren(a);
Sleep(1000);
char c=win(a);
if(c!=NULL)
{
jieguo(a);
break;
}
ai(a);
Sleep(1000);
c=win(a);
if(c!=NULL)
{
jieguo(a);
break;
}
}
}
9.主函数
int main()
{
printf("来一盘血脉贲张的五子棋大战吧!!!\n");
printf("我来会会你:1\n");
printf("告辞:0\n");
char a[20][20];
char c;
c=_getch();
while(c=='1')
{
game(a);
printf("小儿可敢再战?\n");
printf("今日便与你这厮大战三百回合:1\n");
printf("我妈喊我回家吃饭:0\n");
c=_getch();
}
return 0;
}
下面将完整代码全部写出,方便复制(有没有前面一点一点复制的?这算水字数吗?)
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <Windows.h>
#include <ctime>
#include <cstdlib>
int t1[361];
int t2[361];
void InitBoard(char a[20][20],int row,int col)
{
memset(a,' ',row*col*sizeof(char));
}
void qi(char a[20][20])
{
for(int i=1;i<20;i++)
{
if(i==1)
{
printf(" ");
for(int m=0;m<19;m++)
{
printf("|%02d",m+1);
}
printf("\n");
for(int n=0;n<20;n++)
{
printf("---");
}
}
printf("\n");
printf("%02d",i);
for(int j=1;j<20;j++)
{
if(j!=19)
{
printf("| %c",a[i][j]);
}
if(j==19)
{
printf("| %c|",a[i][j]);
}
}
printf("\n");
for(int k=0;k<20;k++)
{
printf("-- ");
}
}
printf("\n");
}
void ren(char a[20][20])
{
while(1)
{
printf("请选择落子行列:");
int x,y;
scanf("%d%d",&x,&y);
if((x<=0)||(x>=20)||(y<=0)||(y>=20))
{
printf("阁下莫不是老眼昏花了?\n");
continue;
}
if(a[x][y]!=' ')
{
printf("这是何意?\n");
continue;
}
a[x][y]='x';
break;
}
system("cls");
qi(a);
}
int judge(char a[20][20],int i,int j)
{
int m=0;
int n1=1;
int n2=1;
int x1,y1;
int x2,y2;
int X[8]={0,0,1,1,1,-1,-1,-1};
int Y[8]={1,-1,0,1,-1,0,1,-1};
for(int k=0;k<8;k++)
{
x1=i+X[k];
y1=j+Y[k];
while(a[x1][y1]=='o')
{
m=m+n1;
x1=x1+X[k];
y1=y1+Y[k];
n1++;
if((n1==4)&&(a[x1][y1]==' '))
{
m=m+100;
}
if((n1==3)&&(a[x1-4*X[k]][y1-4*Y[k]]=='o')&&(a[x1-5*X[k]][y1-5*Y[k]]==' ')&&(a[x1][y1]==' '))
{
m=m+100;
}
if((n1==3)&&(a[x1][y1]==' ')&&(a[x1-4*X[k]][y1-4*Y[k]]==' ')&&(a[x1-3*X[k]+X[k+1]][y1-3*Y[k]+Y[k+1]]=='o')&&(a[x1-3*X[k]+2*X[k+1]][y1-3*Y[k]+2*Y[k+1]]=='o')&&(a[x1-3*X[k]+3*X[k+1]][y1-3*Y[k]+3*Y[k+1]]==' '))
{
m=m+500;
}
if((n1==5)&&(a[x1][y1]=='x'))
{
m=m+20000;
}
if((n1==5)&&((x1==0)||(x1==20)||(y1==0)||(y1==20)))
{
m=m+20000;
}
if((n1==3)&&(a[x1-4*X[k]][y1-4*Y[k]]=='o')&&(a[x1-5*X[k]][y1-5*Y[k]]=='o'))
{
m=m+20000;
}
if((n1==4)&&(a[x1-5*X[k]][y1-5*Y[k]]=='o'))
{
m=m+20000;
}
}
x2=i+X[k];
y2=j+Y[k];
while(a[x2][y2]=='x')
{
m=m+1;
m=m+n2;
x2=x2+X[k];
y2=y2+Y[k];
n2++;
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]==' ')&&((a[x2][y2]=='o')||(a[x2-6*X[k]][y2-6*Y[k]]=='o')))
{
m=m+500;
}
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]==' ')&&(a[x2][y2]==' '))
{
m=m+1000;
}
if((n2==4)&&(a[x2][y2]==' '))
{
m=m+1000;
}
if((n1==3)&&(a[x1][y1]==' ')&&(a[x1-4*X[k]][y1-4*Y[k]]==' ')&&(a[x1-3*X[k]+X[k+1]][y1-3*Y[k]+Y[k+1]]=='x')&&(a[x1-3*X[k]+2*X[k+1]][y1-3*Y[k]+2*Y[k+1]]=='x')&&(a[x1-3*X[k]+3*X[k+1]][y1-3*Y[k]+3*Y[k+1]]==' '))
{
m=m+3000;
}
if((n2==5)&&(a[x2][y2]=='o'))
{
m=m+6000;
}
if((n2==5)&&((x2==0)||(x2==20)||(y2==0)||(y2==20)))
{
m=m+6000;
}
if((n2==3)&&(a[x2-4*X[k]][y2-4*Y[k]]=='x')&&(a[x2-5*X[k]][y2-5*Y[k]]=='x'))
{
m=m+6000;
}
if((n2==4)&&(a[x2-5*X[k]][y2-5*Y[k]]=='x'))
{
m=m+6000;
}
}
n1=1;
n2=1;
}
return m;
}
void ai(char a[20][20])
{
int max=0;
int x=0;
int y=0;
int k=0;
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
int n=judge(a,i,j);
if(n>max)
{
max=n;
x=i;
y=j;
}
}
}
}
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
int m=judge(a,i,j);
if(m==max)
{
t1[k]=i;
t2[k]=j;
k++;
}
}
}
}
srand((unsigned)time(NULL));
int z=rand()%k;
a[t1[z]][t2[z]]='o';
system("cls");
qi(a);
printf("上一步棋为(%d,%d),凡人你对付的了吗?\n",t1[z],t2[z]);
}
int full(char a[20][20])
{
int b=1;
for(int i=1;i<20;i++)
{
for(int j=1;j<20;j++)
{
if(a[i][j]==' ')
{
b=0;
break;
}
}
}
return b;
}
char win(char a[20][20])
{
for(int i=5;i<20;i++)
{
for(int j=1;j<16;j++)
{
if((a[i][j]==a[i-1][j+1])&&(a[i][j]==a[i-2][j+2])&&(a[i][j]==a[i-3][j+3])&&(a[i][j]==a[i-4][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
}
}
for(int i=1;i<16;i++)
{
for(int j=1;j<16;j++)
{
if((a[i][j]==a[i+1][j])&&(a[i][j]==a[i+2][j])&&(a[i][j]==a[i+3][j])&&(a[i][j]==a[i+4][j])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if((a[i][j]==a[i][j+1])&&(a[i][j]==a[i][j+2])&&(a[i][j]==a[i][j+3])&&(a[i][j]==a[i][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if((a[i][j]==a[i+1][j+1])&&(a[i][j]==a[i+2][j+2])&&(a[i][j]==a[i+3][j+3])&&(a[i][j]==a[i+4][j+4])&&(a[i][j]!=' '))
{
return a[i][j];
}
else if(full(a))
{
return '0';
}
}
}
return NULL;
}
void jieguo(char a[20][20])
{
char d=win(a);
if(d=='x')
{
printf("佩服佩服!");
}
if(d=='o')
{
printf("就这点手段?");
}
if(d=='0')
{
printf("竟然与我一成功力打成平手!!!");
}
}
void game(char a[20][20])
{
InitBoard(a,20,20);
qi(a);
while(1)
{
ren(a);
Sleep(1000);
char c=win(a);
if(c!=NULL)
{
jieguo(a);
break;
}
ai(a);
Sleep(1000);
c=win(a);
if(c!=NULL)
{
jieguo(a);
break;
}
}
}
int main()
{
printf("来一盘血脉贲张的五子棋大战吧!!!\n");
printf("我来会会你:1\n");
printf("告辞:0\n");
char a[20][20];
char c;
c=_getch();
while(c=='1')
{
game(a);
printf("小儿可敢再战?\n");
printf("今日便与你这厮大战三百回合:1\n");
printf("我妈喊我回家吃饭:0\n");
c=_getch();
}
return 0;
}
感谢观看!
|