前言
一、理清创建思路
创建几个文件来实现:
test.c //测试游戏逻辑
游戏的模块:
game.h //函数的声明
game.c //函数的实现
二、test.c代码块
**注意:**详细的分析具体到每一步是什么操作以及思路步骤的顺序,请打开下面的代码查看,按序号指引结合game.c和game.h代码块一步步理清操作思路哦🤗🤗
#define _CRT_SECURE_NO_WARNINGS 1 //13.将头文件移到game.h中,注释头文件 //#include<stdio.h> //6.在代码前面包含头文件game.h,就可以用了 #include "game.h" void menu() { printf("***************************************************\n"); printf("***************** 1.play *************\n"); printf("***************** 0.exit *************\n"); printf("***************************************************\n"); } void game() { //5.三子棋存放数据需要一个3*3的二维数组 char board[3][3] = { 0 }; //如果在这里写成char board[3][3] = { 0 };的形式,以后扩大棋盘的时候再修改非常不方便 //所以将棋盘的行和列定义变量ROW,COL;在game.h中声明,以后修改棋盘大小的时候在game.h中修改变量的大小即可 char board[ROW][COL] = { 0 }; //7.初始化棋盘 //当开始的时候棋盘中放的是空格,下棋之后空格里面变成符号 //创建一个初始化棋盘的函数,把棋盘,几行几列传进来 InitBoard(board, ROW, COL); //8.初始化函数的实现怎么实现?在game.h中声明,请见game.h //14.显示棋盘(在数字打印的基础上还要打印棋盘的框框) DisplayBoard(board, ROW, COL); char ret = 0; //48.因为最后也要用到ret,所以最好把ret定义到外面 while (1) { //20.下棋:一人下一步,每人下完打印棋盘,判断输赢 //21.玩家下棋:实际上是要落子,落到棋盘board里面,传参的时候数组要传过去,几行几列也要给过来 PlayerMove(board, ROW, COL); //25.打印棋盘 DisplayBoard(board, ROW, COL); //35.判断输赢:判断数组里面是否有三行三列或者对角线上有三个相同的元素 //还是判断数组,把数组传进去,还有几行几列 //46.要知道返回值才知道谁赢,定义变量ret来接受返回值 ret = IsWin(board, ROW, COL); //如果ret返回的不是C的话,游戏就结束 if (ret != 'C') { break; } //36.实际上还要判断四种结果:(1)电脑赢(2)玩家赢(3)平局(4)继续(如果不是玩家赢电脑赢平局,那么游戏继续) //如果电脑赢,返回'#' //如果玩家赢,返回'*' //如果平局.返回'Q' //如果继续,返回'C' //26.电脑下棋 Computermove(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //47.判断输赢:同样的道理这里也接收一下判断输赢的结果 ret = IsWin(board, ROW, COL); //如果ret返回的不是C的话,游戏就结束 if (ret != 'C') { break; } } //48.跳出上面的循环判断谁赢了,而不是在每次判断输赢的时候写上下面这段代码,避免了代码的冗余 if ('*' == ret) { printf("玩家赢\n"); }else if('#'==ret) { printf("电脑赢\n"); } else if('Q'==ret){ printf("平局\n"); } } int main() { int input = 0; srand((unsigned int)time(NULL)); //30.使用rand()函数前必须调用srand();用时间戳作为随机数生成的起点,返回类型定义为unsigned int //31.需要包含头文件,直接写到game.h中 do //1.制作一个游戏,玩玩一把不够玩,再来一把,采用do while循环 { menu(); //2.创建一个菜单函数,让它操控玩游戏和退出游戏的功能 printf("请选择:>"); scanf("%d", &input); switch (input) { //3.根据input输入的值做出判断 case 1: //选择1进入游戏 game(); //4.game函数来设计游戏 break; case 0: //选择0退出游戏 printf("退出游戏\n"); break; default: //选择的既不是1又不是0弹出选择错误 printf("选择错误,请重新选择\n"); break; } } while (input); return 0; }
三、game.h代码块
#pragma once #define ROW 3 #define COL 3 //9.函数的声明(在game.c中去写这个函数) //初始化棋盘 void InitBoard(char board[ROW][COL], int row,int col); //初始化数组里面的形参,棋盘用数组来接收,再给定行和列的形参,使用小写用于区分 //13.将头文件移到game.h中 #include<string.h> #include<stdio.h> //32.包含头文件 #include<stdlib.h> //rand()头文件 #include<time.h> //time头文件 //15.打印棋盘(棋盘传进来,几行几列) void DisplayBoard(char board[ROW][COL], int row, int col); //22.声明玩家下棋:(记得写void) void PlayerMove(char board[ROW][COL], int row, int col); //27.声明电脑下棋的函数:(记得写void) void Computermove(char board[ROW][COL], int row, int col); //37.声明判断输赢的函数: char IsWin(char board[ROW][COL], int row, int col);
四、game.c代码块
#define _CRT_SECURE_NO_WARNINGS 1 //10.实现初始化函数的时候,要用到行和列即ROW,COL,所以要包含头文件 #include "game.h" //11.(2.2)memset函数需要头文件 //#include<string.h> //12.通过观察test.c和game.c的头文件,我们发现其实只要把头文件全部写入game.h然后包含一下就都可以使用了,这样的写法更简单 // 接下来去把头文件全部写到game.h中,这里的话为了使读者看的更清晰,我就把test.c中的#include<stdio.h>注释了 //所以如果使用memset函数,那么将game.c中的#include<string.h>写在game.h中即可 //11.(1)写初始化函数方法一: void InitBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { //i遍历多行 int j = 0; for (j = 0; j < col; j++) { //j遍历多列 board[i][j] = ' '; //将每个格子放空格占位 } } //11.(2.1)写初始化函数方法一: //memset(&board[0)[0], ' ', row* col * sizeof(board[0][0]); //解释: //memset(数组首地址,置为空格,数组的总大小(把这么多字节置为空格) ); } //16.写打印棋盘的函数 //即使没有下棋的时候也要把棋盘的格子打印出来 //棋盘: // 一行数据 // 一行分割 // 一行数据 // 一行分割 // 一行数据 // (一行分割) //上面可以看成两个两个一组,最后一行分割不用打印,可以通过控制条件不用打印 //void DisplayBoard(char board[ROW][COL], int row, int col) { // int i = 0; // int j = 0; // for (i = 0; i < row; i++) { //二维数组的遍历 // printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //17.这里把列写死了,列写成三列了,当将game.h中的ROW,COL改为十行十列,打印出棋盘的运行结果是十行三列就是因为这里写死了 // //18.优化一下,注释这一整段代码 // if (i < row - 1) //最后一组的时候不打印分割线 // printf("---|---|---\n"); // // } //} //19.优化打印棋盘: void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { printf(" %c ", board[i][j]); //数据行拆分:将" %c |"看成一组 if (j < col - 1) //最后一列不同打印| printf("|"); } printf("\n"); //数据打印完换行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); //打印完数据行打印分割的符号 if (j < col - 1) printf("|"); } } printf("\n"); //分割的符号打印完换行 } } //23.实现玩家下棋: void PlayerMove(char board[ROW][COL], int row, int col) { int x=0; //行用x来控制 int y=0; //列用y来控制 printf("玩家下棋>:\n"); while(1){ //24.落棋的这个动作反复操作,所以用while循环,直到落棋正确break跳出 printf("请输入要下棋的坐标:>\n"); //输入坐标要输入行和列,所以前面要定义两个变量 scanf("%d%d", &x, &y); //请玩家输入坐标,在玩家的认识里行和列都是从第一行第一列开始,当然也有乱输入坐标的玩家,这个时候就要对他们输入的进行判断 if (x >= 1 && x <= row && y >= 1 && y <= col) { //判断玩家落棋的地方是不是空格, //但是 //比如玩家输入的1 2,对应到数组里面并不是第一行第二列,数组的下标是从0开始的,所以玩家输入的行和列的值都要-1 if (board[x - 1][y - 1] == ' ') { //是空格的时候可以落棋 board[x - 1][y - 1] = '*'; break; } else { printf("坐标被占用,请重新输入\n"); //不是空格的时候进行提示 } } else { printf("坐标非法,请重新输入\n"); } } } //28.实现电脑下棋的函数: //电脑随机下棋 void Computermove(char board[ROW][COL], int row, int col) { int x = 0; //创建坐标 int y = 0; printf("电脑下棋>:\n"); while (1) { //35.下棋的位置如果不是空格,重新生成就好了,不用提示,所以用while循环控制 x = rand() % row; //29.随机生成0-2的数字,%上row余数就是0-2,下面同理 y = rand() % col; //33.生成的坐标所在的位置万一已经有棋就不行了,需要重新设置坐标,所以要进行判断 if (board[x][y] == ' ') { board[x][y] = '#'; //34.下棋的位置如果是空格,就放置为#,break跳出, break; } } } //44.创建棋盘是否满了的函数:有空格说明没满,没空格说明满了,返回类型设置为int int IsFull(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] == ' ') { //如果是空格的话,返回0;不是的话返回1 return 0; } } } return 1; } //38.实现判断输赢的函数: //如果电脑赢,返回'#' //如果玩家赢,返回'*' //如果平局.返回'Q' //如果继续,返回'C' char IsWin(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { //39.循环row次,判断三行 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++) { //40.循环col次,判断三列 if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') { //判断一列三个是否相等,但是这三个不能都是空格,所以要排除这种情况 return board[0][i]; //如果三个一样满足赢得条件,返回这三个里面一个的符号,因为在前面已经约定好电脑赢和玩家赢的标志符号,这样做非常方便,这样的设计非常好 } } //41.判断两条对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') { return board[0][0]; } if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') { return board[0][0]; } //42.以上四种情况中的一种都是玩家赢或者是电脑赢,下面这种情况是平局情况 //判断是否为平局:前面没人赢的情况下,棋盘满了,就是平局 //也就是判断棋盘满了 if (IsFull(board, row, col)) { //43.在上面需要创建判断棋盘是否满了的函数 return 'Q'; } //45.如果前面都没有返回的话,游戏继续 return 'C'; } }
五、简易版代码块
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void menu() { printf("*******************************\n"); printf("******** 1. play ******\n"); printf("******** 0. exit ******\n"); printf("*******************************\n"); } void game() { //存放数据需要一个3*3的二维数组 char board[ROW][COL] = {0}; //初始化棋盘 InitBoard(board, ROW, COL); //显示棋盘 DisplayBoard(board, ROW, COL); char ret = 0; while (1) { //玩家下棋 PlayerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); //判断输赢 ret = IsWin(board, ROW, COL); if (ret != 'C') { break; } //电脑下棋 ComputerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); //判断输赢 ret = IsWin(board, ROW, COL); if (ret != 'C') { break; } } if ('*' == ret) { printf("玩家赢\n"); } else if ('#' == ret) { printf("电脑赢\n"); } else if ('Q' == ret) { printf("平局\n"); } } int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
2.game.h
#pragma once //头文件的包含 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 3 #define COL 3 //函数的声明 //初始化棋盘 void InitBoard(char board[ROW][COL], int row, int col); //打印棋盘 void DisplayBoard(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); //判断输赢 char IsWin(char board[ROW][COL],int row, int col);
3.game.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void InitBoard(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++) { board[i][j] = ' '; } } //memset(&board[0][0], ' ', row*col*sizeof(board[0][0])); } //void DisplayBoard(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++) // { // printf("%c ", board[i][j]); // } // printf("\n"); // } //} //void DisplayBoard(char board[ROW][COL], int row, int col) //{ // int i = 0; // int j = 0; // for (i = 0; i < row; i++) // { // printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); // if(i < row-1) // printf("---|---|---\n"); // } //} void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; int j = 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) { for (j = 0; j < col; j++) { printf("---"); if(j<col-1) printf("|"); } } printf("\n"); } } void PlayerMove(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("玩家下棋:>\n"); while (1) { printf("请输入要下棋的坐标:>"); 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) { int x = 0; int y = 0; printf("电脑下棋>:\n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == ' ') { board[x][y] = '#'; break; } } } int IsFull(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; } //判断输赢 //玩家赢 - '*' //电脑赢 - '#' //平局 - 'Q' //继续 - 'C' char IsWin(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 (IsFull(board, row, col)) { return 'Q'; } //游戏继续 return 'C'; }
六、运行结果
(1)第一次测试
(2)第二次测试
总结
今天你学会制作这个小游戏了呢小伙伴们?💕
如果哪里写的有问题,欢迎大家帮我指正.
最后,如果对友友们有所帮助的话,可以留下关注点赞收藏哦~🥰💕❤️