简介 在这个项目中,我们将使用C编程语言创建一个简单的基于文本的五子棋游戏。五子棋是一种两人策略棋盘游戏,目标是率先在水平、垂直或对角线上连续获得五颗棋子。我们将使用一个 15x15 的游戏棋盘来开发这个游戏。 👀 预览 🎯 任务 在这个项目中,你将学习: 如何在C语言中使用二维数组设计和实现棋盘。 如何创建一个主函数来控制游戏流程。 如何实现初始化游戏、打印棋盘以及允许玩家轮流下棋的函数。 如何开发一个函数来检查游戏中的获胜条件。 如何编译和运行程序。 🏆 成果 完成这个项目后,你将能够: 在C语言中使用二维数组。 使用函数设计和实现游戏流程。 检查游戏中的获胜条件。 编译和运行C程序。
设计棋盘 使用 'O' 和 'X' 表示棋子 首先,我们需要一个棋盘(15 * 15)来记录棋盘上每个位置的“状态”。因此,我们可以定义一个数组 chessboard[16][16]。为什么不是 [15][15] 呢?这是因为这样数组的坐标就能与棋盘的行和列精确对应,便于编写后续代码。 #include <stdio.h> #define N 15 // 定义一个数组,并将每个元素初始化为0。 int chessboard[N + 1][N + 1] = { 0 };
主函数 在开始编写主函数之前,让我们简要思考一下游戏的典型流程。首先,我们进入游戏的主界面,然后点击开始按钮进入游戏,接着显示游戏画面,判断胜负,最后结束游戏。那么,像五子棋这样的游戏流程是怎样的呢? 首先,我们进入游戏的欢迎界面,然后输入Y开始游戏(非Y则退出游戏),显示游戏棋盘,接着两位玩家轮流落子,之后判断胜负(是否有五个棋子连成一线)。 // 用于记录轮到玩家1还是玩家2,奇数表示轮到玩家1,偶数表示轮到玩家2。 int whoseTurn = 0; int main(void) { // 一个自定义函数,用于初始化游戏,即显示欢迎界面并进入游戏显示棋盘。 initGame(); // 这个循环用于两位玩家轮流操作。 while (1) { // 每次循环加1,这样两人就能轮流操作。 whoseTurn++; // 一个自定义函数,用于执行落子操作。 playChess(); } return 0; }
initGame 函数 在这个函数中,我们要实现的功能有: 显示一个简单的欢迎界面。 要求输入 'Y',输入后显示棋盘。 void initGame(void) { char c; printf("请输入'y'进入游戏:"); c = getchar(); if ('y'!= c && 'Y'!= c) exit(0); // 清屏 system("clear"); // 这里再次调用一个自定义函数,其功能是打印出棋盘。 printChessboard(); } 在 initGame 函数中,我们使用了 exit 和 system 函数,所以需要在程序顶部包含头文件 stdlib.h。 #include <stdlib.h>
函数 printChessboard 在这个函数中,我们的目标是: 打印出行号和列号,并打印出棋盘。 如果数组元素的值为 0,打印一个星号(*),表示该位置为空。 如果数组元素的值为 1,打印一个实心圆(X),代表玩家 1 的棋子。 如果数组元素的值为 2,打印一个空心圆(O),代表玩家 2 的棋子。 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(" X"); else if (2 == chessboard[i][j]) printf(" O"); else printf(" *"); } printf("\n"); } }
playChess 函数 在这个函数中,我们想要实现以下几点: 提示玩家输入放置棋子的位置。 如果当前轮到玩家 1 行动,将数组中相应元素的值设为 1。 如果当前轮到玩家 2 行动,将数组中相应元素的值设为 2。 每一步棋之后,判断当前玩家是否获胜。 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(); // 再次调用此函数。 /* * 以下部分调用自定义函数(判断函数)。 * 用于判断当前玩家这一步棋是否获胜。 */ if (judge(i, j, whoseTurn)) { if (1 == whoseTurn % 2) printf("获胜者是玩家 1!\n"); else printf("获胜者是玩家 2!\n"); } }
judge 函数 函数参数: x:当前落子的行号 y:当前落子的列号 返回值: 1 或 0。1 表示当前玩家落子后获胜。 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 循环,其目的是判断是否存在连续五个棋子的连线。 五个棋子的连线可以是水平、垂直或对角线方向。这里,我们将采用试错法,在水平、垂直和对角线方向上搜索连续的棋子。举个例子: 在上面的棋盘上,我们将根据坐标 (9, 10) 解释判断是否存在五个棋子连线的算法。 首先,我们检查从 (9, 10) 开始是否存在一条五个棋子的对角线。过程如下: 从 (9, 10) 开始,我们向左上方搜索。满足条件的坐标是 (8, 9)、(7, 8) 和 (6, 7)。由于 (5, 6) 不满足条件,我们进入下一步。 然后,我们向右下方搜索,找到 (10, 11),这是唯一满足条件的坐标。 我们找到了一条直线上的五个点,所以玩家 2 获胜。 如果在对角线方向上没有五个棋子的连线,我们接着检查垂直和水平方向。如果它们都不满足获胜条件,这意味着当前玩家不能获胜,游戏将继续。
我的棋子被“吃掉”了 我不知道大家有没有注意到,在我们的五子棋游戏中,即使某个位置已经被占用,我们在放置自己的棋子时仍然可以“吃掉”原来的棋子。 这是因为我们在编写 playChess 函数时,没有检查我们放置棋子的位置。我们可以像这样修改代码: void playChess(void) { int i, j, winner; if (1 == whoseTurn % 2) { printf("轮到玩家 1,请输入位置,格式为行号 + 空格 + 列号: "); scanf("%d %d", &i, &j); //调试 while(chessboard[i][j]!= 0) { printf("这个位置已经被占用,请重新输入位置: "); scanf("%d %d",&i, &j); } //调试 chessboard[i][j] = 1; } else { printf("轮到玩家 2,请输入位置,格式为行号 + 空格 + 列号: "); scanf("%d %d", &i, &j); //调试 while(chessboard[i][j]!= 0) { printf("这个位置已经被占用,请重新输入位置: "); scanf("%d %d",&i, &j); } //调试 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); //调试 } else { printf("获胜者是玩家 2!\n"); exit(0); //调试 } } } 除了在玩家获胜后提示获胜者之外,使用 exit(0) 退出游戏。
总结 恭喜你!你已经使用 C 语言创建了一个简单的五子棋游戏。玩家可以轮流在一个 15x15 的棋盘上放置棋子,当有玩家连成五个连续的棋子时,程序将宣布其为获胜者。和你的朋友们尽情享受这个基于文本的游戏吧!