摘要:文章目录前言正文一,游戏实现基本流程二游戏实现步骤创建工程及分配功能给头文件上内容当当当,主函数出场游戏函数里面打印游戏菜单棋盘初始化打印棋盘玩家下棋电脑下棋判断结果三游戏结果演示恭喜友友获胜啦电脑获胜,很遗憾,再接再厉
Hello everyone! 好久不见,forever 又来了,最近挺忙的所以好久没更新了,上次我介绍了函数相关知识,然后这次我们中间来个小插曲,来给大家看看井字棋游戏哈!不过由于最近时间比较紧张,所以就给大家看看无心版井字棋游戏,哈哈哈哈!所谓无心版就是电脑下棋时没有携带高级算法,不会和玩家进行一场真正的博弈哈!当然后面我还会继续跟进,将这个无心版本升级,让玩家和电脑能够针锋相对,体验体验那种刺激感哈!
所以今天大家先别着急,先随 forever 一起去看看无心版本,其实看完简单的无心版本之后,大家也可以尝试挑战一下,去写一写携带高级算法,给电脑端附上高级智慧,此时电脑所表现出来的高级智慧是你给的,也就体现出你的智慧啦!听完的友友们,是不是很想去试试哈!
接下来就跟着 forever 一起来感受感受井字棋的成长历程吧!
1、创建工程,首先考虑自己的整个工程需要由多少头文件和源文件组成,forever 的详细工程创建如下面分析;
2、对应给每个文件分配什么作用,即给里面放什么内容;
3、接下来放主函数,以主函数为树干,然后分枝开叶;
4、打印游戏菜单;
5、棋盘初始化;
6、打印棋盘;
7、开始下棋:倘若定义玩家先下棋;
8、其次电脑下棋;
9、判断结果;
10、游戏结束。
forever 将整个程序分为两个模块:头文件模块和源文件模块。头文件模块包含:game.h
(包含整个程序需要调用的头文件、宏定义以及函数的声明);源文件包含:main.cpp(放主函数的源文件)、game.cpp(游戏开始的源文件)、gamelogic.cpp(游戏整体逻辑框架源文件)、test.cpp(游戏具体操作内容源文件)。
//头文件模块game.h //包含整个程序需要调用的头文件、宏定义以及函数的声明//源文件模块main.cpp //放主函数(main函数)game.cpp //游戏开始的实现gamelogic.cpp //游戏整体逻辑框架实现test.cpp //游戏具体操作内容实现
这里我就按顺序写,先写刚开始需要的,然后后面需要什么头文件,forever 会依次在每一步里面添加哈!这里就先给一个 从头到尾都需要的吧!
//game.h包含整个程序需要调用的头文件、宏定义以及函数的声明#include
//main.cpp放主函数(main函数)#include "game.h"int main(){ game();//调用游戏函数出场啦! return 0;}
友友们!玩游戏肯定都知道游戏菜单哈!就是那个界面啦!不过这个菜单超级简单,只有游戏开始和游戏结束。
//game.cpp 游戏开始的实现#include "game.h"void meau(){ printf("—————— 0.exit ——————/n"); printf("—————— 1.play ——————/n");}
这里面除了打印菜单还有一个游戏开始的函数即上面提到的 game() 函数,而此时头文件里面便会有一个game()函数的声明:
#include void game();//游戏总函数
而 game.cpp 里面的所有内容是:
#include "game.h"//打印菜单void meau(){ printf("—————— 0.exit ——————/n"); printf("—————— 1.play ——————/n");}//游戏开始void game(){ unsigned int number = 0;//用unsigned 修饰保证输入的是正整数 do { meau();//打印菜单 printf("请选择:>"); scanf("%d", &number); switch (number) { case 0:printf("注意休息,保护眼睛哈,游戏结束啦!/n"); break; case 1:printf("打起精神,认真思考哈,游戏开始啦!/n"); playgame();//游戏整体内容框架 break; default: printf("这位友友有点皮哟,请选择正确数字哈!/n"); } } while (number);}
运行相关结果:
这时就会创建一个二维字符数组来存入棋盘,因为后面这个二维字符数组会反复使用,所以此时字符数组的大小 forever 就用宏定义的方式给大家呈现出来吧!此时头文件里面就会加上宏定义,当然还有上面那个 playgame() 函数的声明:
#include #define LINE 3#define LIST 3void game();//游戏总函数void playgame();//游戏整体逻辑框架void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
宏定义的优点:
1、方便程序的修改;
2、提高程序的运行效率;
宏定义的展开是在程序的预处理阶段实现完成的,无需运行时后分配内存,能够部分实现函数的功能却没有函数调用时候的压栈等问题,效率高
3、增强代码可读性
4、增加代码的灵活性
这里将棋盘全部初始化为空格:
void Firstboard(char board[LINE][LIST], int line, int list){ for (int i = 0; i < line; i++) { for (int j = 0; j < list; j++) { board[i][j] = " "; } }}
这里头文件就会声明打印棋盘函数:
#include #define LINE 3#define LIST 3void game();//游戏总函数void playgame();//游戏整体逻辑框架void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
这里将棋盘打印呈现出来,首先给大家展示一个比较死板的版本:
void printboard(char board[line][list], int line, int list){ for (int i = 0; i < line; i++) { printf(" %c | %c | %c/n", board[i][0], board[i][1], board[i][2]); if (i < line - 1) { printf("---|---|---/n"); } }}
运行结果:
这里的打印可以看出是那种简单粗暴直接式打印方法,当然这种方法最直接,最简单,但也最死板,如果此时我们想打印更多棋盘格子呢?是不是就做不到啦,又得修改好多,按这种方法打印就要打印好多,实在是降低了代码的灵活性。因此修改该代码如下:
void printboard(char board[LINE][LIST], int line, int list){ int i = 0, j = 0; for (i = 0; i < line; i++) { for (j = 0; j < list; j++) { printf(" %c ",board[i][j]); if (j < list - 1) { printf("|"); } } printf("/n"); if (i < line - 1) { for (j = 0; j < list; j++) { printf("---"); if (j < list - 1) { printf("|"); } } printf("/n"); } }}
运行结果:
这里 forever 利用循环将整个代码写的灵活了,如果想要打印更多格子,直接对宏定义的量进行改变就行啦!所以友友们以后写代码尽量去注重一下代码的可读性,观赏性和灵活性,让你的写代码的水准更高,更牛哈!
这里头文件就会声明玩家下棋函数:
#include #define LINE 3#define LIST 3void game();//游戏总函数void playgame();//游戏整体逻辑框架void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘void printboard(char board[LINE][LIST], int line, int list);//打印棋盘void playergame(char board[LINE][LIST], int line, int list);//玩家下棋
倘若我们规定玩家先下棋,那么这里我们就得开始实现玩家下棋啦!这里我们定义一下玩家用 * 当棋子吧!
void playergame(char board[LINE][LIST], int line, int list){ printf("玩家走/n请输入坐标:>"); int x = 0, y = 0; while (1) { scanf("%d %d", &x, &y); if (x >0 && x <= line && y >0 && y <= list)//x,y为1-3是方便玩家输入 { if (board[x - 1][y - 1] == " ")//这里x-1和y-1是为了对应数组元素 { board[x - 1][y - 1] = "*"; break; } else { printf("皮友友,该坐标已有棋子,请重新下哈!/n"); } } else { printf("这位友友有点皮哟,请输入正确范围坐标哈!/n"); } }}
运行结果:
一如既往,头文件会声明电脑下棋函数:
#include #include //rand()头文件调用#include //time头文件调用#define LINE 3#define LIST 3void game();//游戏总函数void playgame();//游戏整体逻辑框架void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘void printboard(char board[LINE][LIST], int line, int list);//打印棋盘void playergame(char board[LINE][LIST], int line, int list);//玩家下棋void computergame(char board[LINE][LIST], int line, int list);//电脑下棋
此处电脑开始下棋啦!我们规定一下电脑下棋的棋子为 + 符号吧!
void computergame(char board[LINE][LIST], int line, int list){ printf("电脑走/n"); int x = 0, y = 0; while (1) { x = rand() % line;//生成随机数 y = rand() % list; if (board[x][y] == " ") { board[x][y] = "+"; break; } }}
运行结果:
x = rand() % line; //生成随机数: 这里是让电脑下棋时生成随机坐标,即随机下棋,这也对应了我们标题里的无心版本啦!哈哈哈哈!就是没有思维,随机生成什么就是什么哈!当然这里在使用rand() 时,必须要在主函数里面使用一个 srand((unsigned int) time (NULL)) ,如下展示:
int main(){ srand((unsigned int)time(NULL)); game(); return 0;}
这里就要在头文件里声明一个判断是胜负的函数:
#include #include //rand()头文件调用#include //time头文件调用#define LINE 3#define LIST 3void game();//游戏总函数void playgame();//游戏整体逻辑框架void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘void printboard(char board[LINE][LIST], int line, int list);//打印棋盘char is_win(char board[LINE][LIST], int line, int list);//判断输赢void playergame(char board[LINE][LIST], int line, int list);//玩家下棋void computergame(char board[LINE][LIST], int line, int list);//电脑下棋void is_guo(char ret);//判断最终结果
以上到这里就是头文件中的所有内容啦!
每下一步棋就需要判断该局是否结束,若未结束则继续互相博弈,若结束则还要判断胜负或平局。因此一共有四种情况:
1、未结束继续(返回 ‘w’)
2、结束后,玩家胜利(返回 ‘*’ )
3、结束后,电脑胜利(返回 ‘+’)
4、结束后平局(返回 ‘p’)
这里放判断输赢和最终结果的函数:
//判断输赢char is_win(char board[LINE][LIST], int line, int list){ //判断行 for (int i = 0; i < line; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != " ") { return board[i][1]; } } //判断列 for (int j = 0; j < list; j++) { if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != " ") { return board[1][j]; } } //判断对角线 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, line, list) == 1) { return "p"; } return "w";}//判断最终结果void is_guo(char ret){ if (ret == "*") { printf("恭喜友友,你胜利啦!/n"); } else if (ret == "+") { printf("很遗憾,友友你输啦!,再接再厉哟!/n");
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/125385.html
摘要:题目来源于面试公司先看看题目吧假设我们现在有一个的井字棋游戏,我们用一个二维数组代表棋盘,代表玩家下的棋子,代表玩家下的棋子,代表该格没有棋子。 题目来源于面试公司,先看看题目吧 假设我们现在有一个 3 x 3 的井字棋游戏,我们用一个二维数组代表棋盘,’x’ 代表玩家 X 下的棋子,’o’ 代表玩家 O 下的棋子,’e’ 代表该格没有棋子。例如:一个空白的棋盘以下面的二维数组表示: ...
摘要:今天博主将为大家带来语言入门级小游戏三子棋井字棋的详细介绍,希望这篇文章对大家能有帮助。在这里,我们使用函数来实现这一功能。 今天博主将为大家带来C语言入门级小游戏——三子棋(井字棋)的详细介绍,希望这篇文章对大家能有帮助 。 在编程的学习过程中,编写一些中这样...
摘要:三子棋目录一问题介绍三子棋,在民间又叫井字棋。因为人们在游玩时常常不画棋盘的边框,正如汉字中的井字,多称为井字棋。 三子棋 目录 一、问题介绍 三子棋,在民间又叫井字棋。因为人们在游玩时常常不画棋盘的边框,正如汉字中的井字,多称为井字棋。 三子棋的游戏规则十分的简单: ...
摘要:如果上述两种情况均不存在,当发现,位置是空时,电脑先下这一步。其他情况均随意落子。 朋友们,我们还记得以前上课经常和同桌玩起井字棋,那么我们就当我们回忆童年,现在也...
摘要:我们在前文中考虑的那张图就来自这篇文章,之后我们会用剪枝算法来改进之前的解决方案。剪枝算法的实现接下来讨论如何修改前面实现的算法,使其变为剪枝算法。现在我们已经有了现成的和剪枝算法,只要加上一点儿细节就能完成这个游戏了。 前段时间用 React 写了个2048 游戏来练练手,准备用来回顾下 React 相关的各种技术,以及试验一下新技术。在写这个2048的过程中,我考虑是否可以在其中加...
阅读 3666·2023-01-11 11:02
阅读 4206·2023-01-11 11:02
阅读 3006·2023-01-11 11:02
阅读 5145·2023-01-11 11:02
阅读 4699·2023-01-11 11:02
阅读 5483·2023-01-11 11:02
阅读 5234·2023-01-11 11:02
阅读 3860·2023-01-11 11:02