- 首先,要考虑如何实现棋盘,如何存放棋子。
- C语言中字符数组可以实现存放位置,用三乘三的字符数组作为棋盘的一部分,C语言中其中一个字符 “ ' ' ”可以作为无棋子时状态,字符 ‘X ’可以代表一方棋子,‘O’作为另一方棋子,用三种字符'- ','+', '|'可以实现棋盘。
- 先用两个循环进行初始化棋盘
int i,j;
for(i=0;i<3;i++) //初始化棋盘
for(j=0;j<3;j++)
a[i][j]=' ';
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[0][0],a[0][1],a[0][2]);
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[1][0],a[1][1],a[1][2]);
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[2][0],a[2][1],a[2][2]);
printf("+--+--+--+\n");
- 然后就可以加个游戏开始界面(此步骤过于简单,代码随后一同和其它的登场。)
- 这里最最重要的必然是考虑如何让电脑走棋,我才用的是让电脑进行一个个位置遍历,然后根据哪个位置最重要(能让电脑自己胜利>能阻止让对方胜利>其他情况),并储存。
- 为了让电脑确定某位置最高分,我采用平时老师讲的评分机制。
- 得到的代码如下:
-
int score(i,j)//i代表着 'O';j代表着 'X'
{
if(j==2&&i==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线有两个×,则得5分;
return 5;
else if(i==2&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线有两个○,则得6分;
return 6;
else if(i==1&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线其他棋格有一个○和一个没有棋子,则得4分;
return 4;
else if(i==0&&j==1) //如果棋格上没有棋子,但棋格所在行、列、或对角线其他棋格有一个×和一个没有棋子,则得4分;
return 4;
else if(i==0&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线没有棋子,则得2分;
return 2;
else if(i==1&&j==1) //如果棋格上没有棋子,但棋格所在行、列、或对角线有一个○和一个×,则得1分
return 1;
}
- 电脑遍历数组这个是最简单的,代码如下:
void option_2() //对数组进行遍历
{
int i,j;
int q,p,max=0,m;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
if(a[i][j]==' ')
{
m=elect(i,j);
if(max<m) //找到此时棋盘最高分的位置
{
max=m;
q=i;p=j; //记住此位置
}}
}
a[q][p]='O'; //电脑下棋
print(); //打印棋盘
}
- 电脑进行每一个位置遍历,就需要通过某种机制来确定某个位置是否是自己最佳选择,我选用的是将每个位置对应的行和列和对角线的情况:有多少个X和多少个O。然后将此位置最多O的情况(即对电脑来说是目前最好等情况) 用m记录下来,接下来会用到。确定了某个位置的最高分的情况后,记录在temp中,返回后记录。
- 代码如下:
int elect(int i,int j) //确定某个位置的所在行或所在列或所在对角线的 X,O 的情况,
也包括没有的情况
{
int k1=0,k2=0;
int i1,j1,temp,k;
for(j1=0;j1<3;j1++) //判断某行有多少个'X','O'
{
if(a[i][j1]=='X')
k2++;
if(a[i][j1]=='O')
k1++;
}
temp=score(k1,k2); //用来记录所在行有多少分
k1=0;k2=0;
for(i1=0;i1<3;i1++) //判断某列有多少个'X','O'
{
if(a[i1][j]=='X')
k2++;
if(a[i1][j]=='O')
k1++;
}
k=score(k1,k2); //用来记录所在列有多少分
temp=temp>k?temp:k; //判断所在行所在列最高分
k1=0;k2=0;
if(i==2&&j==0||i==0&&j==2||i==1&&j==1) //判断特殊点(右上角和左下角及中间位置
)所在的对角线又多少个 'X','O'
{
for(i1=2;i1>=0;i1--)
{
j1=2-i1;
if(a[i1][j1]=='X')
k2++;
if(a[i1][j1]=='O')
k1++;
}
k=score(k1,k2);
temp=temp>k?temp:k;
k1=0;k2=0;
}
if(i==j) //判断特殊点(左上角或右下角及中间位置)所在的对角线又多少个 'X','O'
{
for(i1=2;i1>=0;i1--)
{
j1=i1;
if(a[i1][j1]=='X')
k2++;
if(a[i1][j1]=='O')
k1++;
}
k=score(k1,k2);
temp=temp>k?temp:k;
}
return temp;
}
- 如何让电脑走棋,基本上已经解决了,接下来就需要进行胜利或平局的判定了,判断方法基本上玩过井字棋的都知道,就不再叙述了。这个我选择了用代码堆出判定(此方法被老师上课吐槽过):
void judge() //判断此时是否有一方赢了
{
int temp=0;
if(a[0][0]==a[0][1]&&a[0][1]==a[0][2]&&a[0][0]!=' ') //第一行
{
if(a[0][0]=='X') //如果全为'X'则标记 temp=1
temp=1;
else
temp=2; //如果全为'O'则标记 temp=2
}
else if(a[1][0]==a[1][1]&&a[1][1]==a[1][2]&&a[1][0]!=' ') //第二行
{
if(a[1][0]=='X')
temp=1;
else
temp=2;
}
else if(a[2][0]==a[2][1]&&a[2][1]==a[2][2]&&a[2][0]!=' ') //第三行
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][0]==a[1][0]&&a[1][0]==a[2][0]&&a[0][0]!=' ') //第一列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][1]==a[1][1]&&a[1][1]==a[2][1]&&a[0][1]!=' ') //第二列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][2]==a[1][2]&&a[1][2]==a[2][2]&&a[0][2]!=' ') //第三列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][0]==a[1][1]&&a[1][1]==a[2][2]&&a[0][0]!=' ') //主对角线
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][2]==a[1][1]&&a[1][1]==a[2][0]&&a[2][0]!=' ') //副对角线
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
if(temp==1) //如果temp==1,则说明此时玩家胜利,若为temp==2,则说明电脑胜利
{
printf("GAME OVER\n");
printf("YOU WIN!");
exit(0);
}
if(temp==2)
{
printf("GAME OVER\n");
printf("THE COMPUTER WIN!");
exit(0);
}
}
- 人机对战,由于第一步比较特殊,我就将它单独隔离了:它需要由人决定谁先走。
- 代码如下(包含游戏初始页面(超简陋版)):
void menu() //输出游戏开始页面
{
void option_1(c1);
printf("\t\t------------------------------------------\n");
printf("\t\t 井字棋\n");
printf("\t\t 玩家棋子为:X\n");
printf("\t\t 电脑棋子为:O\n");
printf("\t\t------------------------------------------\n");
printf("是否先走?\n");
printf("是:y 否:n\n");
scanf("%c",&c1);
if(c1!='y'&&c1!='n') //如果输入的字符不是y或者n,则终止程序
{
printf("输入错误,程序终止!");
exit(0);
}
option_1(c1);
}
void option_1(c1) //第一步不同情况
{
void Py(); //Py函数在次函数后面,先声明才能够调用
int i,j;
srand(time(NULL)); //用来防止电脑每次用rand函数都取同样值,具体作用请自行去网上查找
if(c1=='y') //如果玩家要选择自己先走
{
printf("请输入你要下的位置的坐标(x,y):");
scanf("%d,%d",&i,&j);
a[i][j]='X';
}
else //电脑先走,电脑通过rand函数来确定自己第一步走在哪里
{
i=rand()%3; //随机选取0~2之间的数字作为横坐标
j=rand()%3; //随机选取0~2之间的数字作为纵坐标
a[i][j]='O';
}
print(a); //输出棋盘情况
Py(); //调用Py函数,进行博弈
}
- 所有的基本上都已经解决了,就剩下用一个循环来控制人与电脑的对弈过程了,根据玩家选择的谁先走,来决定接下来的顺序,代码如下(其中包含着平局判定):
void Py() //控制对弈次数以及是否为平局
{
int i,j,step=1; //temp代表已走几步棋,最多走九步
while(step<=9)
{
if(c1=='n'||step>1) //如果玩家选择电脑先走或者轮到玩家,则玩家开始下子
{
printf("轮到你了:");
scanf("%d,%d",&i,&j);
a[i][j]='X';
step++; //两个函数分别打印棋盘,并判断此时是否有一方已经胜利
print();
judge();
if(step>=9)
break;
}
printf("轮到电脑了:\n"); //轮到电脑的回合
option_2(); //引用函数,确定电脑要放棋子的位置上
step++;
judge();
if(step>=9)
break;
}
printf("TIE GAME!\n"); //如果走完九步,则说明双方平局
printf("GAME OVER!");
}
int main()
{
int i,j;
for(i=0;i<3;i++) //初始化棋盘
for(j=0;j<3;j++)
a[i][j]=' ';
menu(); //调用函数,打印游戏开始页面
getchar();
getchar(); //目前可有可无的函数
return 0;
}
// 井字棋
#include"stdio.h"
#include"stdlib.h"
#include"time.h"
char a[3][3]; //用来储存棋盘各个位置的情况
char c1; //用来储存玩家选择第一步是否为自己先走,且在函数间传递信息
void menu() //输出游戏开始页面
{
void option_1(c1);
printf("\t\t------------------------------------------\n");
printf("\t\t 井字棋\n");
printf("\t\t 玩家棋子为:X\n");
printf("\t\t 玩家棋子为:O\n");
printf("\t\t------------------------------------------\n");
printf("是否先走?\n");
printf("是:y 否:n\n");
scanf("%c",&c1);
if(c1!='y'&&c1!='n') //如果输入的字符不是y或者n,则终止程序
{
printf("输入错误,程序终止!");
exit(0);
}
option_1(c1);
}
void print() //输出棋盘的情况
{
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[0][0],a[0][1],a[0][2]);
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[1][0],a[1][1],a[1][2]);
printf("+--+--+--+\n");
printf("|%c |%c |%c |\n",a[2][0],a[2][1],a[2][2]);
printf("+--+--+--+\n");
}
void option_1(c1) //第一步不同情况
{
void Py(); //Py函数在次函数后面,先声明才能够调用
int i,j;
srand(time(NULL)); //用来防止电脑每次用rand函数都取同样值,具体作用请自行去网上查找
if(c1=='y') //如果玩家要选择自己先走
{
printf("请输入你要下的位置的坐标(x,y):");
scanf("%d,%d",&i,&j);
a[i][j]='X';
}
else //电脑先走,电脑通过rand函数来确定自己第一步走在哪里
{
i=rand()%3; //随机选取0~2之间的数字作为横坐标
j=rand()%3; //随机选取0~2之间的数字作为纵坐标
a[i][j]='O';
}
print(a); //输出棋盘情况
Py(); //调用Py函数,进行博弈
}
int score(i,j)//i代表着 'O';j代表着 'X'
{
if(j==2&&i==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线有两个×,则得5分;
return 5;
else if(i==2&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线有两个○,则得6分;
return 6;
else if(i==1&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线其他棋格有一个○和一个没有棋子,则得4分;
return 4;
else if(i==0&&j==1) //如果棋格上没有棋子,但棋格所在行、列、或对角线其他棋格有一个×和一个没有棋子,则得4分;
return 4;
else if(i==0&&j==0) //如果棋格上没有棋子,但棋格所在行、列、或对角线没有棋子,则得2分;
return 2;
else if(i==1&&j==1) //如果棋格上没有棋子,但棋格所在行、列、或对角线有一个○和一个×,则得1分
return 1;
}
int elect(int i,int j) //确定某个位置的所在行或所在列或所在对角线的 X,O 的情况,也包括没有的情况
{
int k1=0,k2=0;
int i1,j1,temp,k;
for(j1=0;j1<3;j1++) //判断某行有多少个'X','O'
{
if(a[i][j1]=='X')
k2++;
if(a[i][j1]=='O')
k1++;
}
temp=score(k1,k2); //用来记录所在行有多少分
k1=0;k2=0;
for(i1=0;i1<3;i1++) //判断某列有多少个'X','O'
{
if(a[i1][j]=='X')
k2++;
if(a[i1][j]=='O')
k1++;
}
k=score(k1,k2); //用来记录所在列有多少分
temp=temp>k?temp:k; //判断所在行所在列最高分
k1=0;k2=0;
if(i==2&&j==0||i==0&&j==2||i==1&&j==1) //判断特殊点(右上角和左下角及中间位置)所在的对角线又多少个 'X','O'
{
for(i1=2;i1>=0;i1--)
{
j1=2-i1;
if(a[i1][j1]=='X')
k2++;
if(a[i1][j1]=='O')
k1++;
}
k=score(k1,k2);
temp=temp>k?temp:k;
k1=0;k2=0;
}
if(i==j) //判断特殊点(左上角或右下角及中间位置)所在的对角线又多少个 'X','O'
{
for(i1=2;i1>=0;i1--)
{
j1=i1;
if(a[i1][j1]=='X')
k2++;
if(a[i1][j1]=='O')
k1++;
}
k=score(k1,k2);
temp=temp>k?temp:k;
}
return temp;
}
void option_2() //对数组进行遍历
{
int i,j;
int q,p,max=0,m;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
if(a[i][j]==' ')
{
m=elect(i,j);
if(max<m) //找到此时棋盘最高分的位置
{
max=m;
q=i;p=j; //记住此位置
}}
}
a[q][p]='O'; //电脑下棋
print(); //打印棋盘
}
void judge() //判断此时是否有一方赢了
{
int temp=0;
if(a[0][0]==a[0][1]&&a[0][1]==a[0][2]&&a[0][0]!=' ') //第一行
{
if(a[0][0]=='X') //如果全为'X'则标记 temp=1
temp=1;
else
temp=2; //如果全为'O'则标记 temp=2
}
else if(a[1][0]==a[1][1]&&a[1][1]==a[1][2]&&a[1][0]!=' ') //第二行
{
if(a[1][0]=='X')
temp=1;
else
temp=2;
}
else if(a[2][0]==a[2][1]&&a[2][1]==a[2][2]&&a[2][0]!=' ') //第三行
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][0]==a[1][0]&&a[1][0]==a[2][0]&&a[0][0]!=' ') //第一列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][1]==a[1][1]&&a[1][1]==a[2][1]&&a[0][1]!=' ') //第二列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][2]==a[1][2]&&a[1][2]==a[2][2]&&a[0][2]!=' ') //第三列
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][0]==a[1][1]&&a[1][1]==a[2][2]&&a[0][0]!=' ') //主对角线
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
else if(a[0][2]==a[1][1]&&a[1][1]==a[2][0]&&a[2][0]!=' ') //副对角线
{
if(a[0][0]=='X')
temp=1;
else
temp=2;
}
if(temp==1) //如果temp==1,则说明此时玩家胜利,若为temp==2,则说明电脑胜利
{
printf("GAME OVER\n");
printf("YOU WIN!");
exit(0);
}
if(temp==2)
{
printf("GAME OVER\n");
printf("THE COMPUTER WIN!");
exit(0);
}
}
void Py() //控制对弈次数以及是否为平局
{
int i,j,step=1; //temp代表已走几步棋,最多走九步
while(step<=9)
{
if(c1=='n'||step>1) //如果玩家选择电脑先走或者轮到玩家,则玩家开始下子
{
printf("轮到你了:");
scanf("%d,%d",&i,&j);
a[i][j]='X';
step++; //两个函数分别打印棋盘,并判断此时是否有一方已经胜利
print();
judge();
if(step>=9)
break;
}
printf("轮到电脑了:\n"); //轮到电脑的回合
option_2(); //引用函数,确定电脑要放棋子的位置上
step++;
judge();
if(step>=9)
break;
}
printf("TIE GAME!\n"); //如果走完九步,则说明双方平局
printf("GAME OVER!");
}
int main()
{
int i,j;
for(i=0;i<3;i++) //初始化棋盘
for(j=0;j<3;j++)
a[i][j]=' ';
menu(); //调用函数,打印游戏开始页面
getchar();
getchar(); //目前可有可无的函数
return 0;
}
- 最后附上:此井字棋代码对于经常见几十行代码的人来讲过于长(二百多行),且顺序混乱,不易阅读,代码并不完善,不能够阻止玩家重复下某一位置。
- 但,应付作业应该是绰绰有余了。
- 如有时间和精力,且需要这几百行代码,建议自行更改,让代码更加完善。