C语言趣味小游戏——三子棋
全篇无任何废话,本文的解释大多数都在代码段中,所以一定要看代码,边看边学边理解。
这只是初学者入门的一个小游戏,不难懂,没有什么复杂的内容
可以先学习一下比三子棋还简单的猜数字小游戏
C语言趣味小游戏——猜数字(匠心制作)
游戏的条件
1.根据坐标和电脑下棋,玩家一步棋,电脑一步棋,且不能悔棋
2.玩完一盘可以继续
可以学到的内容
1.打印一个简单的菜单
2.一些细节的用户体验
3.自定义函数 , 时间戳的运用 , #define定义
4.程序语言的一些入门逻辑
5.C语言的知识
————————————————————————————————————————
首先来一个简简单单的代码三部曲(写在test.c的文件下,后期有妙用)
// 测试三子棋游戏的逻辑#include<stdio.h>int main()
{return 0;
}
写一个返回值为void的test函数,且调用它
void test()
{}int main()
{test();return 0;
}
因为是玩游戏,所以写一个do while,并且打印菜单,和猜数字异曲同工
void menu()
{printf("*********************\n");printf("****** 1.play ******\n");printf("****** 0.over ******\n");printf("*********************\n");
}void test()
{do{menu(); // 菜单} while ();}
看到菜单之后就做出选择
void test()
{int input = 0; // 初始化do{menu();printf("请选择:>");scanf("%d", &input); // 输入} while ();}
定义一个整型并初始化,方便后期输入
void test()
{int input = 0; // 初始化do{menu();printf("请选择:>");scanf("%d", &input); // 输入} while ();
}
加入switch语句
不懂得switch,case,default语句和do while循环可以看下这个,1分钟就懂了
https://blog.csdn.net/W20223161730/article/details/126200624?spm=1001.2014.3001.5502
void test()
{int input = 0; // 初始化do{menu();printf("请选择:>");scanf("%d", &input); // 输入switch(input) // 这里使用input的原因是根据输入的值进入对应的case语句{case 1:// 假设这里有三子棋游戏printf("玩游戏!\n");break;case 0:printf("选择退出,游戏结束!\n");break;default :printf("选择错误,请重新输入!\n");break;}} while (input); // 这里使用input的原因是根据input判断是否继续,如果输入的是1 为真(继续),否则 0为假(结束)}
开始实现游戏的主体 (需要先去了解一下什么是二维数组)
1:游戏开始肯定会呈现一个九宫格的棋盘,三行三列,且中间什么都没有,输入坐标下棋后会被覆盖
2:被覆盖之后会被打印出来,也就是说,棋盘以及玩家和电脑的棋子会被存储起来
3:如果想要实现棋盘中间什么的没有,那么中间肯定是空格
正片开始 : 初始化一个名为board的二维数组,得是三行三列
void game()
{// 存放下棋的数据char board[3][3] = { 0 };
}
再初始化棋盘为全空格,后面还会有更多这样的操作,为了方便所以就直接封装成函数,分模块来写
void game()
{// 存放下棋的数据char board[3][3] = { 0 };// 初始化棋盘为全空格Initboard(board, 3, 3);
}
所以再添加一个game.c 和game.h 的两个文件
在test.c文件里面有了这个函数之后,声明就放在game.h的头文件里面
在函数声明的时候需要告诉函数它的返回类型,参数等
// 名字为game.h 的头文件// 初始化棋盘 棋盘 行 列void Initboard(char board[3][3], int row, int col);
然后再用define在.h中定义一下行和列,免得后期更改比较麻烦
#define ROW 3
#define COL 3// 初始化棋盘 棋盘 行 列void Initboard(char board[3][3], int row, int col);
把文件里的行和列都替换成define定义的ROW和COL
记得在文件中包含game.h ↓
#include"game.h"
顺便把game.h文件中写上三部曲的第一步
#include<stdio.h>
这样做的目的是其他文件包含game.h,而game.h文件又包含了行和列还有三部曲的第一部,会节省很多时间
// game.h 文件
#pragma once#include<stdio.h>#define ROW 3
#define COL 3// 初始化棋盘 棋盘 行 列void Initboard(char board[ROW][COL], int row, int col);// game.c 文件#include"game.h"void Initboard(char board[ROW][COL], int row, int col)
{}// test.c 文件#include"game.h"
然后声明完了放到game.c 的文件中实现
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] = ' ';}printf("\n");}
}
在test.c文件中来一个打印棋盘的函数
void game()
{// 存放下棋的数据char board[ROW][COL] = { 0 };// 初始化棋盘为全空格Initboard(board, ROW, COL);// 打印棋盘Displayboard(board, ROW, COL);
}
还是头文件
void Displayboard(char board[ROW][COL], int row, int col);
game.c文件
void Displayboard(char board[ROW][COL], int row, int col)
{}
棋盘打印还是需要精心设计的,这里就不过多赘述,直接上代码
void Displayboard(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){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}
效果图
后面就开始重中之重了,玩家和电脑是如何下棋的
还是继续写一个函数 用来实现玩家下棋
// test.cPlayer_move(board, ROW, COL);// game.cvoid Player_move(char board[ROW][COL], int row, int col)
{}// game.hvoid Player_move(char board[ROW][COL], int row, int col);
需要提前考虑到两点
1:玩家的非法输入
2:玩家输入并不知道数组的下标是从0开始,所以需要加1
void Player_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家下棋!\n");printf("请输入坐标!\n");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){}else{printf("坐标输入错误,请重新输入!\n");}}
玩家不可能就输入错误一次,所以加上一个循环才是合理的
void Player_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家下棋!\n");while (1){printf("请输入坐标!\n");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){}else{printf("坐标输入错误,请重新输入!\n");}}}
下一步
if (x >= 1 && x <= row && y >= 1 && y <= col)
{if (board[x - 1][y - 1] == ' ') // 玩家输入的要减1,因为数组的下标是从0开始的// 如果输入的是一个空格,那么就说明这个位置没有被占用{board[x - 1][y - 1] == '*'; // 那么就把空格替换成 * 来当作玩家下的棋break;// 一定要记得break,不然一直死循环 }else{printf("该坐标被占用,请重新输入!\n");}
}
再重新打印一下棋盘
void game()
{// 存放下棋的数据char board[ROW][COL] = { 0 };// 初始化棋盘为全空格Initboard(board, ROW, COL);// 打印棋盘Displayboard(board, ROW, COL);// 玩家下棋Player_move(board, ROW, COL);// 重新打印Displayboard(board, ROW, COL);}
效果图
然后开始写一个简单的电脑下棋函数,以后感兴趣可以自行加上堵截,优先胜利的代码,这次就先不过多介绍,因为是入门先理解
// test.cComputer_move(board, ROW, COL);// game.cvoid Computer_move(char board[ROW][COL], int row, int col)
{}// game.hvoid Computer_move(char board[ROW][COL], int row, int col);
那么问题来了,怎么控制让电脑在规定的范围内,且不重复的下棋
需要简单的了解rand,srand,time函数
这个函数调用一次,每次就归零一次(重新开始),所以不需要频繁的调用,只需要调用一次就可以了, 所以直接放到主函数的test函数里面
srand((unsigned int)time(NULL));
在game.h的头文件包含一下
#include<stdlib.h> // srand
#include<time.h> // time
电脑下棋的实现
void Computer_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("电脑下棋!\n");while (1){x = rand() % row; // 值为0到2 y = rand() % col; // 值为0到2if (board[x][y] == ' '){board[x][y] = '#';break;}}}
玩家和电脑下完棋都打印一下 ,下棋不可能只下一步,所以放到循环里面
void game() // 因为是传参,所以要带上ROW和COL
{// 存放下棋的数据char board[ROW][COL] = { 0 };// 初始化棋盘为全空格Initboard(board, ROW, COL);// 打印棋盘Displayboard(board, ROW, COL);while (1){// 玩家下棋Player_move(board, ROW, COL);// 下完棋打印一下Displayboard(board, ROW, COL);// 电脑下棋Computer_move(board, ROW, COL);// 下完棋打印一下Displayboard(board, ROW, COL);}}
效果
现在还需要实现怎么判断输赢的函数
什么情况下属于游戏结束
1:玩家赢 2:电脑赢 3:平局 或者 :继续
所以封装成一个函数来用是最方便的 那么直接硬写肯定是不太行的
所以当目的达到了,返回一个特定的符号,如果是返回的情况,一定需要一个用来接收的内容
// 玩家赢---'*'
//
// 电脑赢---'#'
//
// 平局---'Q'
//
// 继续---'C'
//
而且每下完一步棋,都需要判断一下,所以这个判断输赢的函数要放在玩家和电脑下完棋之后
void game()
{// 接收is_win的返回类型char ret = 0;// 存放下棋的数据char board[ROW][COL] = { 0 };// 初始化棋盘为全空格Initboard(board, ROW, COL);// 打印棋盘Displayboard(board, ROW, COL);while (1){// 玩家下棋Player_move(board, ROW, COL);// 下完棋打印一下Displayboard(board, ROW, COL);// 再判断一下输赢ret = is_win(board, ROW, COL);if (ret != 'C') // 等于'C'继续,不等于'C'就是有胜利的一方或者平局{break;}// 电脑下棋Computer_move(board, ROW, COL);// 下完棋打印一下Displayboard(board, ROW, COL);// 再判断一下输赢ret = is_win(board, ROW, COL);if (ret != 'C') // 等于'C'继续,不等于'C'就是有胜利的一方或者平局{break;}}// break结束跳到这里}
再来判断输赢或者平局
if (ret == '*'){printf("玩家赢\n");}else if (ret == '#'){printf("电脑赢\n");}else{printf("平局\n");}
最后一步,实现判断输赢函内容的细节
三子棋输赢的判断就是三个棋子在行,列,对角线是否三子相连
1: 用来判断行是否相等
int i = 0;for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' '){return board[i][2];}}
灵魂画手上线
如果玩家赢,返回的就是玩家的棋子 * ,如果电脑赢,返回的就是电脑的棋子 #
2: 用来判断列是否相等
int i = 0;for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '){return board[2][i];}}
一定要加上不等于 ' ' 因为要把空格排除在外
3: 用来判断两条对角线是否相等
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];}
4: 判断平局的情况
在game.c的文件中实现一个判断平局的函数,不需要在.h文件中实现,因为这个函数并不是全局的,仅仅用于判断平局
加上 static 只能在本文件下使用
static int is_full(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++){if (board[i][j] == ' '){return 0; // 棋盘还没被下满}}}return 1; // 棋盘被下满了
}
放到 is_win函数内部来使用
// 用来判断平局if (is_full(board, row, col) == 1){return 'Q';}// 游戏继续return 'C';
最后: 整体代码不会放出来的,希望大家能一步步的看,一步步的实现,多的不说了,加油!
C语言趣味小游戏——三子棋相关推荐
- 用c语言实现小游戏三子棋
小游戏之三子棋 小游戏之三子棋 三子棋的基本玩法 游戏制作思路 制作步骤 1.菜单 2.初始化棋盘 3.打印棋盘 4.玩家下棋 5.电脑下棋 6.判断胜利 完整代码 小结 三子棋的基本玩 ...
- C语言简易小游戏--三子棋
小时候,在学校和小伙伴除了互相追逐着玩闹玩游戏以外,相信很多小伙伴们也有和朋友在课堂上拿一张纸玩井字棋的美好回忆.(如下图酱紫啦~) 那今天呢,我们就用C语言制作一款简易的井字棋来练习一下对代码的感觉 ...
- (超详解)C语言实现小游戏三子棋
目录 一,实现目标 二,整体思路 1.创立三个文件:text.c(实现测试的逻辑) ...
- 童年小游戏三子棋(C语言数组实现)
目录 认识游戏 游戏框架 游戏实现 基本构思 棋子 棋盘 下棋 判断输赢 效果展示 全部代码 游戏效果 认识游戏 三子棋是黑白棋的一种.三子棋是一种民间传统游戏,又叫九宫棋.圈圈叉叉.一条龙.井字棋等 ...
- 趣味益智小游戏 三子棋+五子棋 优化版(可任意选择棋盘大小)
前言 今天牛牛给大家分享的是c语言实现三子棋和五子棋游戏,初学者可能有些不理解的地方,记得私信提问哦,牛牛会一 一回答的. 目录 前言 一.游戏介绍 二.游戏设计思路 2.1 主函数测试区(test. ...
- 简单小游戏------三子棋
目录 前言 一.整体的逻辑 创建菜单 创建棋盘 打印棋盘 玩家下棋 电脑下棋 判断输赢 整合代码 game.c test.c game.h 总结 前言 经典数组游戏三子棋 一.整体的逻辑 1.创建菜单 ...
- C语言小游戏——三子棋(井字棋)
文章目录 前言 一.前期准备 二.游戏整体结构及思路 1.程序主体结构: 2.代码解读 3.完整源代码 总结 前言 相信大家小时候都玩过井字棋小游戏,拿石子在地上画或是用笔在纸上画······今天我们 ...
- c语言小游戏 三子棋,C语言实现简单的三子棋小游戏
学习完数组就能用C语言写出的简单小游戏: 编译器使用的为VS2013 代码分为三个部分 1.头文件 game.h 2.源文件 game.c 用来存放游戏中所有的函数 3.源文件 test.c 用来存放 ...
- C语言小游戏——三子棋
C语言 -- 三子棋 本篇主要是用二维数组和多个函数来实现三子棋游戏. 让我们先来看看这个编写这个游戏的思路:首先要打印三子棋的棋盘,然后是玩家下棋,电脑下棋,最后判断谁赢了,或者看看是否平局. 我们 ...
最新文章
- freemarker中boolean变量的读取
- final,finally,finaliz的区别(Java)
- 关于ANTLR的通用库的需求:使用反射来构建元模型
- 查看Ubuntu系统的版本
- 字节跳动入局全网搜索;思科回应中国区裁员;IntelliJ IDEA 新版发布! | 极客头条...
- C语言如何捕获按下方向键
- Atitit.获取某个服务 网络邻居列表 解决方案
- qsor快排序以及cmp函数
- 基于LSM和BLP的IPC进程通信模型
- 星星之火-26:3G CDMA系统中单用户的扩频原理
- HDMI接口之HPD(热拔插)
- 副屏幕全屏_win7双屏电脑主屏副屏设置|Win7系统如何设置双屏显示?
- android使用fir.im实现版本更新
- 高校毕业生登记表计算机水平,高校毕业生登记表
- 高数 | 【概念剖析】多元函数的偏导数、方向导数、梯度以及微分之间的关系
- git add出现 “fatal: in unpopulated submodule XXX“ 错误
- python中rgb颜色_Python 转换RGB颜色值的示例代码
- 统计英文文件中单词出现频率
- android new file 产生重复文件 ~2,Android Gradle在打包httpmime期间生成重复文件
- 扇贝单词里有计算机英语吗,一个人背单词,一群人学英语:扇贝单词
热门文章
- leetcode JavaScript水桶容积最大
- Python安装pycrypto出错处理方法
- 休闲食品行业报告:渠道变革引领企业成长,连锁店业态前景广阔
- 人民日报揭礼品回收灰色利益链
- storm显微镜成像原理_生命科学与医学领域概述:知微见著-超高分辨率显微镜STORM...
- 华硕PRIME Z390-P主板设置定时开机
- 中国版我的世界弹出java_我的世界中国版JAVA不删档测试问题指引
- 微信小程序发送模版消息
- 县市经济负债升级问题严重,数字化智能化转型升级势在必行,县域知识经济创新枢纽项目,宏微两端的突破点相互照应的连贯呼应需要融智学的启迪引领
- 梦幻西游 登入不显示服务器失败怎么办,《梦幻西游三维版》登录不进去怎么解决 登录失败原因分析...