目录
🐒三子棋的基本功能构思
🐎 STEP 1 : 设计游戏菜单
🐎 STEP 2 : 初始化游戏棋盘
🐎 STEP 3 : 游戏功能函数的封装
🐆功能一:人机对战
🐆功能二:PVP玩家对战
🐆功能三:游戏说明及技巧提示
🐆 针对我们的菜单打印操作自定义一个函数 meun();
🐆针对我们的游戏期盼的初始化及打印操作可以设计出函数 BoardInit(); 和BoardPrint();
🐆针对玩家操作设计出 Player1Move(); 以及 Player2Move();
🐆电脑操作可以封装出一个 ComputerMove();
🐆对于我们游戏输赢的判断可以再将其拆解成一个 is_win(); 函数。
🐒文件的创建
🐎 test.c文件:
🐎 game.c文件:
🐎 game.h文件:
🦁分开创建文件的优点:
🐅首先使主调文件 test.c 结构更加清晰,只有我们总结的具体步骤,方便理解 与观察。
🐅其次可以增加了函数的隐蔽性,在后期我们还可以对我们的部分文件进行隐 藏,这样的话就保护了我们自身的知识产权,使利益最大化。
🐅最后一点就是方便修改,当函数接口不变化时不需要改变客户接口。
🐒正式游戏制作
🦓 STEP 1 :打印菜单
🦓 STEP 2 :初始化并打印棋盘
🦓 STEP 3 :玩家1下棋
🐅 首先我们需要打印请玩家输入下棋坐标字样,提示玩家下棋。
🐅 其次在玩家输入坐标之后需要对坐标进行坐标合法性检查,如果坐标不 合法就得请玩家重新输入坐标,那么这里我们就又需要一个循环语句, 我们可以将这个内容设置为死循环即while(1)直到玩家输入正确的坐 标之后才可以跳出循环。
🐅之后需要做的就是对坐标进行判断坐标是否已经被占用,如果坐标已经 被占用的话就需要重新输入新的坐标。
🦓 STEP 4 :电脑下棋
🦓 STEP 5 :判断输赢
🦓 STEP 6 :PVP对战
🦒这个游戏相信大家都听过,三子棋,不就是井字棋吗?那么今天我们就来亲手制作一个三子棋游戏,实现人机“智能”大战以及玩家PVP对战。
🐒三子棋的基本功能构思
🦒面对一个较大的游戏程序我们要做的第一步并不是抓紧时间上手去敲代码,反而应该放慢自己的节奏仔细思考。思考游戏的设计思路,以及基本的功能,最好可以在草稿上将自己要做的事情用程序框架图表示出来,这样等到我们亲自上手敲代码的时候就会水到渠成了。那么我们先来梳理一下思路,对于我们的三子棋游戏来说,思路主要分为以下几步:
🐎 STEP 1 : 设计游戏菜单
🦒游戏菜单的设计可以提醒我们游戏需要具有哪些功能。
🐎 STEP 2 : 初始化游戏棋盘
🦒对于我们的三子棋游戏刚开始制作的时候肯定需要打印出来一个棋盘供玩家或者电脑下棋。
🐎 STEP 3 : 游戏功能函数的封装
🦒这一步是我们整个游戏设计的主体,将各部分功能封装为一个个密闭的函数,便于调用。
🐆功能一:人机对战
🐆功能二:PVP玩家对战
🐆功能三:游戏说明及技巧提示
🦒以上就是我们本次设计游戏的整体内容,我们同样也可以根据这些内容进行合理设计程序流程。例如:
🐆 针对我们的菜单打印操作自定义一个函数 meun();
🐆针对我们的游戏期盼的初始化及打印操作可以设计出函数 BoardInit(); 和BoardPrint();
🐆针对玩家操作设计出 Player1Move(); 以及 Player2Move();
🐆电脑操作可以封装出一个 ComputerMove();
🐆对于我们游戏输赢的判断可以再将其拆解成一个 is_win(); 函数。
🦒将其设计成思维导图的形式也就是一下形式:
🦒整理好我们主要的思维逻辑之后就可以进行我们的下一个步骤了——文件的创建。
🐒文件的创建
🦒很多小伙伴们可能会说文件创建有什么学的?不是很简单嘛?不,我们在这里说的不是一般的创建,我们需要的不仅仅是一个单独的文件而是三个或者多个文件。不同的文件执行相应的功能,共同协作。就比如我们这次需要创建的 test.c ,game.c,game.h,这三个文件发挥着不同的功能。我们一次解析一下他们各自的功能:
🐎 test.c文件:
🦒这个文件当中主要放的是主函数,使用者可以通过这个文件明白游戏大致的进行步骤,但是并不会完全显示个步骤的具体内容。
🐎 game.c文件:
🦒这个文件当中进行的步骤主要是函数的实现,也就是 test.c 文件中各部分内容的具体实现。
🐎 game.h文件:
🦒我们在 game.h 中进行函数实现之后要想在 test.c 文件当中使用的话就必须引用并创建一个头文件,就像是我们的 game.h 文件一样。只有引用头文件之后才可以使用我们在game.c中制作好的函数,就像是我们再正常程序书写时需要引用头文件一样,只不过我们引用的方式为双引号引用。
🦒你可能又会想,将这三部分分开创建有什么用呢?
🦁分开创建文件的优点:
🐅首先使主调文件 test.c 结构更加清晰,只有我们总结的具体步骤,方便理解 与观察。
🐅其次可以增加了函数的隐蔽性,在后期我们还可以对我们的部分文件进行隐 藏,这样的话就保护了我们自身的知识产权,使利益最大化。
🐅最后一点就是方便修改,当函数接口不变化时不需要改变客户接口。
🦒经过了上面的解释之后相信你已经了解了文件创建的重要价值,那么我们就来亲自实践一下。
🐒正式游戏制作
🦒当我们创建好三个文件之后可以将我们 test.c 文件拖到右方进行书写,方便我们进行对照以及转换。
🦒那么我们就要开始我们的第一步了!打印菜单。
🦓 STEP 1 :打印菜单
🦒首先在test.c文件中创建一个主函数,为了是我们的主函数内容更加清晰,我们将进一步操作全部封装为 test() 函数放置于test.c文件当中。我们将我们需要用到的所有头文件以及函数声明全部放入 game.h 当中即可。这样就可以在引用 game.h 头文件之后不需要重复进行定义。之后我们需要将我们的程序逻辑完善起来。我们想让我们的程序至少进行一次,那么我们需要使用do_while循环,是我们的游戏在玩过一次之后可以继续进行选择,并利用分支语句 switch 进行选择跳转至开始游戏界面,游戏说明界面,游戏技巧界面,在此步骤我们需要利用printf在 game.c 文件中实现 meun 函数以及 introduction 函数以及 skills 函数,实现之后需要将这部分函数声明放入game.h 头文件中,便于我们 test.c 文件进行使用。
🦒程序运行效果:
🦒需要特别注意的是:再写一个比较长的程序的过程中一定要边写程序边进行程序的效果验证,观察代码是否存在错误,存在错误需要及时修改,避免一错再错,整个程序写完有几十个错误使得心态爆炸。
🦒代码呈现:
//test.c文件
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:printf("开始游戏\n");break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h文件 (函数声明)
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();
//游戏介绍
void introduction();
//游戏技巧
void skills();
//game.c文件 (函数的实现)
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n"); printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}
🦓 STEP 2 :初始化并打印棋盘
🦒上面的步骤中我们的游戏开始界面只是简单的开始游戏字样,但是我们真是的游戏并不完全是这样的,因此我们将程序完善,将打印字样改为 game() 在 主函数中实现,之后进行游戏棋盘的初始化操作。实现这一步操作的时候我们需要先对我们的棋盘进行分析:
🦒我们需要对这样一个棋盘进行打印,每一个单位元素(棋子)初始化的棋盘由三个空格组成,我们每一行的分割界限也由三个减号为边界。
🦒首先我们进行此操作的时候需要先进行棋盘中的元素进行宏定义,方便我们后续对棋盘大小的修改。
🦒之后创建一个字符型二维数组以我们的ROW(行),COL(列)为数组的元素进行定义数组。
🦒接下来我们就可以将我们的二维数组,以及行数,列数作为函数参数传给 BoardInit 函数和BoardPrint函数。
🦒最后将我们的 BoardInit 函数以及BoardPrint函数在 game.h 中声明,在 game.c 中实现。效果如下:
🦒代码呈现:
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void game()
{char board[ROW][COL];//初始化棋盘BoardInit(board,ROW,COL);//打印棋盘BoardPrint(board, ROW, COL);
}void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:game();break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h
#define _CRT_SECURE_NO_WARNINGS#define COL 3 //列
#define ROW 3 //行#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();
//游戏介绍
void introduction();
//游戏技巧
void skills();
//棋盘初始化
void BoardInit(char board[ROW][COL],int row,int col);
//棋盘的打印
void BoardPrint(char board[ROW][COL], int row, int col);
//game.h
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n"); printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void BoardInit(char board[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}void BoardPrint(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}
🦒经过我们上面的操作已经将棋盘初始化完毕并打印出来了,那么下一步就轮到我们对玩家下棋的程序编写了。
🦓 STEP 3 :玩家1下棋
🦒这个步骤的核心就是数组元素改写,我们需要对之前初始化为空格的 3*3 数组进行元素改写,以 [ 0 ] [ 0 ] 元素为原点画一个坐标轴,使得玩家只需要输入坐标就可以将棋下到指定的位置。如图:
🦒当玩家输入坐标之后我们只需要对相应坐标的数组内容进行改写就好了。在我们进行改写操作之后再一次将棋盘进行打印,之后就可以验证我们的思路是否正确了。
🦒对于这一步操作我们的编码思路是:
🐅 首先我们需要打印请玩家输入下棋坐标字样,提示玩家下棋。
🐅 其次在玩家输入坐标之后需要对坐标进行坐标合法性检查,如果坐标不 合法就得请玩家重新输入坐标,那么这里我们就又需要一个循环语句, 我们可以将这个内容设置为死循环即while(1)直到玩家输入正确的坐 标之后才可以跳出循环。
🐅之后需要做的就是对坐标进行判断坐标是否已经被占用,如果坐标已经 被占用的话就需要重新输入新的坐标。
🦒我们将我们上述的操作转换为代码的形式展示给大家:
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void game()
{char board[ROW][COL];//初始化棋盘BoardInit(board,ROW,COL);//打印棋盘BoardPrint(board, ROW, COL);//玩家下棋PlayerMove(board, ROW, COL);BoardPrint(board, ROW, COL);
}void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:game();break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h
#define _CRT_SECURE_NO_WARNINGS#define COL 3 //列
#define ROW 3 //行#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();
//游戏介绍
void introduction();
//游戏技巧
void skills();
//棋盘初始化
void BoardInit(char board[ROW][COL],int row,int col);
//棋盘的打印
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n"); printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void BoardInit(char board[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}void BoardPrint(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}void PlayerMove(char board[ROW][COL], int row, int col)
{printf("玩家下棋\n");while (1){printf("请输入要下棋的坐标:>");int x = 0;int y = 0;scanf("%d %d", &x, &y);//坐标合法if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该坐标被占用,请重新输入\n");}}else//坐标非法{printf("坐标非法\n");}}
}
🦒上面就是我们玩家下棋的执行操作了,那么下一步我们需要做的就是让电脑进行下棋。
🦓 STEP 4 :电脑下棋
🦒还记得我们之前设计过的猜数字游戏吗?其实这个电脑下棋的思路和那个随机生成数字很相似,我们需要做的操作只是随机生成两个数字取模上我们的行和列之后就会得到一个坐标,这个就是我们电脑将要下棋的位置。同样的道理,我们需要对电脑下棋的坐标进行判断,检查所要修改的坐标上是否已经被下过棋了,如果下过就重新生成两个随机数,直到找到合适坐标位置。由于思路和上面的玩家下棋很相似我们就不多讲了,直接展示我们代码的运行效果并呈现我们的代码。
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void game()
{char board[ROW][COL];//初始化棋盘BoardInit(board,ROW,COL);//打印棋盘BoardPrint(board, ROW, COL);//玩家下棋PlayerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//电脑下棋ComputerMove(board, ROW, COL);BoardPrint(board, ROW, COL);
}void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:game();break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h
#define _CRT_SECURE_NO_WARNINGS#define COL 3 //列
#define ROW 3 //行#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();
//游戏介绍
void introduction();
//游戏技巧
void skills();
//棋盘初始化
void BoardInit(char board[ROW][COL],int row,int col);
//棋盘的打印
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n"); printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void BoardInit(char board[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}void BoardPrint(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}void PlayerMove(char board[ROW][COL], int row, int col)
{printf("玩家下棋\n");while (1){printf("请输入要下棋的坐标:>");int x = 0;int y = 0;scanf("%d %d", &x, &y);//坐标合法if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该坐标被占用,请重新输入\n");}}else//坐标非法{printf("坐标非法\n");}}
}void ComputerMove(char board[ROW][COL], int row, int col)
{//电脑下棋
//随机生成坐标,只要坐标没有被占用,就下棋printf("电脑下棋:\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}
🦒在这一步我们需要进行一个额外的操作就是对玩家和电脑下棋进行重复操作直到出现胜者或平局为止,因此我们需要将玩家下棋和电脑下棋操作放到一个循环中,符合条件就跳出循环,这个改变在我们后面的代码中进行体现。
🦓 STEP 5 :判断输赢
🦒对于我们的人机对战的部分判断输赢就是最后一个操作步骤了。那么我们应该怎样书写我们的 is_win 函数呢?我们可以通过 is_win 函数的返回值来判断,
🦒将 is_win 函数的返回值设置成字符类型,判断三行或者三列或者对角线当中的符号相等(除空格外)如果相等的话就返回当前的字符,判断是电脑获胜了还是玩家获胜了。
🦒在这个函数中我们还需要判断平局的情况也就是棋盘是否满了,并且找不到任何一方获胜。那么就返回一个 Q 字符给出系统提示游戏平局。否则游戏就继续。我们在这里将判断棋盘是否放满操作单独列出封装成为一个函数。
🦒那么将上述的内容化作代码的形式也就是下面的情况:
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void game()
{char ret = 0;char board[ROW][COL];//初始化棋盘BoardInit(board,ROW,COL);//打印棋盘BoardPrint(board, ROW, COL);while (1){//玩家下棋PlayerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}//电脑下棋ComputerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}}if (ret == '#')printf("电脑赢了\n");else if (ret == '*')printf("玩家赢了\n");else if (ret == 'Q')printf("平局\n");
}void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:game();break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h#define _CRT_SECURE_NO_WARNINGS#define COL 3 //列
#define ROW 3 //行#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();
//游戏介绍
void introduction();
//游戏技巧
void skills();
//棋盘初始化
void BoardInit(char board[ROW][COL],int row,int col);
//棋盘的打印
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n"); printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void BoardInit(char board[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}void BoardPrint(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}void PlayerMove(char board[ROW][COL], int row, int col)
{printf("玩家下棋\n");while (1){printf("请输入要下棋的坐标:>");int x = 0;int y = 0;scanf("%d %d", &x, &y);//坐标合法if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该坐标被占用,请重新输入\n");}}else//坐标非法{printf("坐标非法\n");}}
}void ComputerMove(char board[ROW][COL], int row, int col)
{//电脑下棋
//随机生成坐标,只要坐标没有被占用,就下棋printf("电脑下棋:\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}//判断棋盘是否满了
static int is_full(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' ')return 0;}}return 1;
}char is_win(char board[ROW][COL], int row, int col)
{int i = 0;//判断三行for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}//判断三列for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}//对角线if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//平局?if (is_full(board, row, col) == 1){return 'Q';}//继续//没有玩家或者电脑赢,也没有平局,游戏继续return 'C';
}
🦒上面就是我们人机对战的所有代码,那么我们接下来实现我们的另一个功能,PVP玩家对战。
🦓 STEP 6 :PVP对战
🦒对于这一部分我们只需要给我们上面已经完成的代码重新增添一点新的内容就可以了。我们需要做的是当我们选择游戏模式的时候可以跳出一个选择选项,可以让我们选择是人机对战还是PVP对战,那么我们只需要更改我们主函数的最后循环玩家和电脑轮流下棋的步骤即可。我们玩家2的下棋代码可以直接套用我们之前设计好的玩家1的下棋运行代码,只需要将我们的标志改为 # 即可。那么就来看一下我们的运行成果吧!
🦒代码呈现:
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void game()
{meun1();char ret = 0;int choice = 0;scanf("%d", &choice);char board[ROW][COL];//初始化棋盘BoardInit(board,ROW,COL);//打印棋盘BoardPrint(board, ROW, COL);if (choice == 2){while (1){//玩家下棋PlayerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}//电脑下棋ComputerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}}if (ret == '#')printf("电脑赢了\n");else if (ret == '*')printf("玩家赢了\n");else if (ret == 'Q')printf("平局\n");}else{while (1){//玩家下棋PlayerMove(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}//玩家2下棋Player2Move(board, ROW, COL);BoardPrint(board, ROW, COL);//判断输赢ret = is_win(board, ROW, COL);if (ret != 'C'){break;}}if (ret == '#')printf("玩家2赢了\n");else if (ret == '*')printf("玩家1赢了\n");else if (ret == 'Q')printf("平局\n");}
}void test()
{int input = 0;//打印菜单do{meun();scanf("%d", &input);switch (input){case 1:game();break;case 2:introduction();break;case 3:skills();break;case 0:break;default:printf("选择错误,请重新输入。\n");break;}} while (input);
}int main()
{test();return 0;
}
//game.h
#define _CRT_SECURE_NO_WARNINGS#define COL 3 //列
#define ROW 3 //行#include<stdio.h>
#include<Windows.h>//打印菜单
void meun();//选择对战模式
void meun1();//游戏介绍
void introduction();
//游戏技巧
void skills();
//棋盘初始化
void BoardInit(char board[ROW][COL],int row,int col);
//棋盘的打印
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);//玩家2下棋
void Player2Move(char board[ROW][COL], int row, int col);//判断输赢
char is_win(char board[ROW][COL], int row, int col);
//game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"void meun()
{printf("********************************************\n");printf("*** ***\n");printf("*** 1.游戏模式 2.游戏说明 ***\n");printf("*** ***\n");printf("*** 3.游戏技巧 0.退出游戏 ***\n");printf("*** ***\n");printf("********************************************\n");
}void meun1()
{printf("********************************\n");printf("** 1. PVP玩家对战 **\n");printf("** 2. 人机对战 **\n");printf("********************************\n");
}void introduction()
{printf("************************************************\n");printf("*** 游戏介绍: ***\n");printf("*** 三子棋是一种民间传统游戏,又叫 ***\n");printf("*** 九宫棋、圈圈叉叉棋、一条龙、井 ***\n");printf("*** 字棋等。游戏分为双方对战,双方 ***\n");printf("*** 依次在9宫格棋盘上摆放棋子,率 ***\n");printf("*** 先将自己的三个棋子走成一条线就 ***\n");printf("*** 视为胜利,而对方就算输了,但是 ***\n");printf("*** 三子棋在很多时候会出现和棋的局 ***\n");printf("*** 面。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void skills()
{printf("************************************************\n");printf("*** 三子棋技巧: ***\n");printf("*** 1、先手:正中间,对面如果走边中间 ***\n");printf("*** 位置,就落子在紧贴对方棋子的角位置。***\n");printf("*** ***\n");printf("*** 2、对方必定堵你,然后你就落子在刚才 ***\n");printf("*** 自己角位置棋子的旁边,必赢。 ***\n");printf("*** ***\n");printf("*** 3、如果对方也会玩,就会先落子在角位 ***\n");printf("*** 置,基本最后就是和棋。 ***\n");printf("*** ***\n");printf("*** 4、后手:对方中间,你就在角位置,然 ***\n");printf("*** 后堵对方就行,就是和棋。 ***\n");printf("************************************************\n");printf("你有十秒钟的阅读时间\n");Sleep(10000);system("cls");
}void BoardInit(char board[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}void BoardPrint(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}void PlayerMove(char board[ROW][COL], int row, int col)
{printf("玩家1下棋\n");while (1){printf("请输入要下棋的坐标:>");int x = 0;int y = 0;scanf("%d %d", &x, &y);//坐标合法if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该坐标被占用,请重新输入\n");}}else//坐标非法{printf("坐标非法\n");}}
}void ComputerMove(char board[ROW][COL], int row, int col)
{//电脑下棋
//随机生成坐标,只要坐标没有被占用,就下棋printf("电脑下棋:\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}//判断棋盘是否满了
static int is_full(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' ')return 0;}}return 1;
}char is_win(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;//判断三行for (i = 0; i < row; i++){int flag = 1;for (j = 0; j < col; j++){if (((j < col - 1) && (board[i][j] != board[i][j + 1]))||board[i][j]==' '){flag = 0;break;}}if (flag == 1){return board[i][0];}}//判断三列for (i = 0; i < col; i++){int flag = 1;for (j = 0; j < row; j++){if (((j < row - 1) && (board[j][i] != board[j+1][i]))||board[j][i]==' '){flag = 0;break;}}if (flag == 1){return board[0][i];}}//对角线int flag = 1;for (i = 0; i < row; i++){if (i < row-1 && board[i][i] != board[i + 1][i + 1] || board[i][i] == ' '){flag = 0;break;}}if (flag == 1){return board[0][0];}flag = 1;for (i = 0; i < row; i++){if (i < row - 1 && board[i][row - 1 - i] != board[i + 1][row - 2 - i] || board[i][row - 1 - i] == ' '){flag = 0;break;}}if (flag == 1){return board[row-1][0];}//平局?if (is_full(board, row, col) == 1){return 'Q';}//继续//没有玩家或者电脑赢,也没有平局,游戏继续return 'C';
}void Player2Move(char board[ROW][COL], int row, int col)
{printf("玩家2下棋\n");while (1){printf("请输入要下棋的坐标:>");int x = 0;int y = 0;scanf("%d %d", &x, &y);//坐标合法if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '#';break;}else{printf("该坐标被占用,请重新输入\n");}}else//坐标非法{printf("坐标非法\n");}}
}
🦒上面的程序不仅可以实现三子棋并且当我们在宏定义中改变 ROW 和COL 的定义值的时候还可以实现多子棋,并且只需要修改上面一个地方即可,这就是我们采用宏定义管理数组元素的好处。上面就是我们本次博客的全部内容了,相信一定可以帮到大家吧!感谢大家的观看,祝大家天天开心。