五子棋大家一定都玩过,想不想试着用 C 语言来实现一个简易版的五子棋呢?下面就让我们现在开始,用最简单易懂的代码来编写一个控制台下的五子棋,并逐步完善它,每个人都能轻松学会哦!
注:实验楼环境无法输入中文,可以用O和X来代替棋子
我们首先需要一个棋盘(15 * 15),记录棋盘中每一个位置的“情况”。 那么我们可以定义一个 chessboard[16][16] 的数组,为什么不是 [15][15] 呢?因为这样我们就可以让数组的坐标正好对应棋盘的行和列,方便后面代码的编写。
#include <stdio.h> #define N 15 //定义一个数组并为每一个元素赋初值0 int chessboard[N + 1][N + 1] = { 0 };
开始编写主函数之前,我们先简单的考虑一下,一个游戏通常的流程是怎么样的 (⊙o⊙?)首 先肯定是进入游戏的一个主界面,然后点击开始按钮进入游戏,接着显示游戏画面,判断输赢,游戏结束。那么一个五子棋游戏的流程呢?
//用来记录轮到玩家1还是玩家2,奇数表示轮到玩家1,偶数轮到玩家2 int whoseTurn = 0; int main(void) { //自定义函数,用来初始化游戏,也就是显示欢迎界面并且进入游戏显示棋盘 initGame(); //这个循环就是用来让两个玩家轮流落子的 while (1) { //每次循环自增1,这样就可以做到2人轮流 whoseTurn++; //自定义函数,用来执行落子操作 playChess(); } return 0; }
在这个函数中,我们要实现的功能是
下面,我们就开始吧!
void initGame(void) { char c; printf("欢迎^_^请输入y进入游戏:"); c = getchar(); if ('y' != c && 'Y' != c) exit(0); //清屏,windows下为system("cls") system("clear"); //这里我们又调用了一个自定义函数,函数的功能是打印出棋盘 printChessboard(); }
我们在 initGame 函数中使用了 exit 以及 system 这两个函数,所以要在程序的最上面包含 stdlib.h 这个头文件
#include <stdlib.h>
功能:
void printChessboard(void) { int i, j; for (i = 0; i <= N; i++) { for (j = 0; j <= N; j++) { if (0 == i) //这样可以打印出列号 printf("%3d", j); else if (j == 0) //打印出行号 printf("%3d", i); else if (1 == chessboard[i][j]) //windows下●占2列,前面只需加一个空格 printf(" X"); else if (2 == chessboard[i][j]) printf(" O"); else printf(" *"); } printf("\n"); } }
函数功能:
void playChess(void) { int i, j, winner; //判断轮到玩家1还是玩家2,然后把值赋给数组中对应的元素 if (1 == whoseTurn % 2) { printf("轮到玩家1,请输入棋子的位置,格式为行号+空格+列号:"); scanf("%d %d", &i, &j); chessboard[i][j] = 1; } else { printf("轮到玩家2,请输入棋子的位置,格式为行号+空格+列号:"); scanf("%d %d", &i, &j); chessboard[i][j] = 2; } //重新打印一次棋盘 system("clear"); printChessboard(); //再次调用了这个函数 /* *下面这段调用了自定义函数(judge函数) *用来判断当前玩家下完这步棋后,他有没有获胜 *具体怎么判断的,马上就给大家解释哦 */ if (judge(i, j, whoseTurn)) { if (1 == whoseTurn % 2) printf("玩家1胜!\n"); else printf("玩家2胜!\n"); } }
函数参数:
返回值:
int judge(int x, int y) { int i, j; int t = 2 - whoseTurn % 2; const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}}; for(int i=0;i<4;++i) { const int d[2]={-1,1}; int count=1; for(int j=0;j<2;++j) for(int k=1;k<=4;++k){ int row=x+k*d[j]*step[i][0]; int col=y+k*d[j]*step[i][1]; if( row>=1 && row<=N && col>=1 && col<=N && chessboard[x][y]==chessboard[row][col]) count+=1; else break; } if(count>=5) return 1; } return 0; }
judge 这个函数中,有 3 个嵌套的 for 循环,这 3 个循环的目的在于判断是否有五子连城一条线。
五子连线,无非是在一行上,一列或者斜方向上有连续的五个子。在这里,我们将采取一种试探的方法,即沿着水平,竖直,倾斜等方向分别寻找是否有五子连线。下面举一个例子:
在上面的对局中,我们以(9,10)来讲解判断五子是否成线的算法。
首先判断(9,10)的倾斜方向是否出现五子连线,判断方式如下:
如果倾斜方向不满足取胜的条件,就再判断竖直方向,水平方向,如果均不成立,这意味着当前玩家无法取得胜利,对局将会继续。
到这里,我们的五子棋游戏就基本上完成了。不过,我们的项目课并没有结束,我们还要对项目做一个后期的维护工作。
不知道大家发现没有,我们的五子棋小游戏在落子时,即便是落子的位置已经被占用,依旧可以“吃掉”原棋子。 这是因为我们在写 playChess 函数的时候,没有对落子位置进行检测。我们可以这样修改我们的代码:
void playChess(void) { int i, j, winner; if (1 == whoseTurn % 2) { printf("轮到玩家1,请输入棋子的位置,格式为行号+空格+列号:"); scanf("%d %d", &i, &j); //修复BUG while(chessboard[i][j] != 0) { printf("您要下的位置已经被占用了哦,请重新输入:"); scanf("%d %d", &i, &j); } //修复BUG chessboard[i][j] = 1; } else { printf("轮到玩家2,请输入棋子的位置,格式为行号+空格+列号:"); scanf("%d %d", &i, &j); //修复BUG while(chessboard[i][j] != 0) { printf("您要下的位置已经被占用了哦,请重新输入:"); scanf("%d %d", &i, &j); } //修复BUG chessboard[i][j] = 2; } system("clear"); printChessboard(); if (judge(i, j)) { if (1 == whoseTurn % 2) printf("玩家1胜!\n"); else printf("玩家2胜!\n"); } }
在函数中加入一个循环,当落子位置已经被占用时,给出提示,并且要求重新输入。
当出现五子连线的时候,提示玩家1或玩家2获胜之后,又提示“轮到玩家*,请输入棋子位置……” 是不是很郁闷呢? 其实我们只要加一句代码就行!
if (judge(i, j)) { if (1 == whoseTurn % 2) { printf("玩家1胜!\n"); exit(0); //修复BUG } else { printf("玩家2胜!\n"); exit(0); //修复BUG } } }
在获胜后除了提示玩家某某获胜意外,退出游戏exit(0)
#include <stdio.h> #include <stdlib.h> #define N 15 int chessboard[N+1][N+1]={0}; int whoseTurn=0; void initGame(void); void printChessboard(void); void playChess(void); int judge(int ,int ); int main(void) { initGame(); while(1) { whoseTurn++; playChess(); } return 0; } void initGame(void) { char c; printf("Please intput \'y\' to enter the game:"); c = getchar(); if('y'!=c&&'Y'!=c) exit(0); system("clear"); printChessboard(); } void printChessboard(void){ int i,j; for(i=0;i<=N;i++){ for(j=0;j<=N;j++){ if(0==i) printf("%3d",j); else if(j==0) printf("%3d",i); else if(1==chessboard[i][j]) printf(" 0"); else if(2==chessboard[i][j]) printf(" X"); else printf(" *"); } printf("\n"); } } void playChess(void) { int i,j,winner; if(1==whoseTurn%2) { printf("Turn to player 1,please input the position:"); scanf("%d %d",&i,&j); while(chessboard[i][j]!=0) { printf("This position has been occupied,please input the position again:"); scanf("%d %d",&i,&j); } chessboard[i][j]=1; } else { printf("Turn to player 2,please input the position:"); scanf("%d %d",&i,&j); while(chessboard[i][j]!=0) { printf("This position has been occupied,please input the position again:"); scanf("%d %d",&i,&j); } chessboard[i][j]=1; } system("clear"); printChessboard(); if(judge(i,j)) { if(1==whoseTurn%2) { printf("Winner is player 1!\n"); exit(0); } else { printf("Winner is player 2!\n"); exit(0); } } } int judge(int x,int y) { int i,j; int t= 2 - whoseTurn%2; const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}}; for(int i=0;i<4;i++){ const int d[2]={-1.1}; int count=1; for(int j=0;j<2;++j) for(int k=1;k<=4;k++){ int row=x+k*d[j]*step[i][0]; int col=y+k*d[j]*step[i][1]; if(row>=1&&row<=N&& col>=1&&col<=N&& chessboard[x][y]==chessboard[row][col]) count+=1; else break; } if(count>=5) return 1; } return 0; }