C-EASY-4:小应用之五子棋游戏
前言:在前面几个题中你已经入门了c语言,语言是用来使用的,只有去编写一些东西,你才会有学习的动力。因此在这道题中我们要从头开始,编写一个本地的五子棋小游戏。同时,在上面的题目中,我曾提到,在实际项目中都会使用多文件来构成一个项目,在这道题中也要使用多文件操作。你可以借助ai,但是具体的度你自己考量。
step1_项目要求和项目结构
Section titled “step1_项目要求和项目结构”功能要求:
- 在终端中显示 9×9 ASCII 方格棋盘。
- 玩家 X 先手,O 后手。
- 使用鼠标左键点击棋盘格落子。
- 已经有棋子的格子不能重复落子。
- 横向、纵向或斜向连续五子即获胜。
- 81 个格子填满且无人获胜则为平局。
在这一题中,我要求你完成上述项目,并上传你的项目文件夹和一个记录你思考过程的md文件。
相信你看完要求后一定会有自己的思考,接下来我会给出我的一套思路,你可以按照我的思路和提示完成这个项目。
建议将项目拆分为以下文件:
-
game.h
- 定义棋盘大小等常量
- 定义游戏状态枚举
- 定义落子结果枚举
- 定义 Game 结构体
- 声明游戏逻辑函数
-
game.c
- 判断胜负和平局
-
console.h
- 定义控制台相关结构体
- 声明函数
-
console.c
- 读取鼠标事件
- 将鼠标坐标转换成棋盘坐标
- 初始化棋盘
- 执行落子
-
main.c
- 初始化游戏
- 执行主游戏循环
- 协调 game 和 console 两个模块
定义一些基础数据结构辅助:
#define BOARD_SIZE 9#define WIN_LENGTH 5#define EMPTY_CELL '.'
typedef enum { GAME_RUNNING, // 游戏进行中 GAME_X_WINS, // X胜出 GAME_O_WINS, // O胜出 GAME_DRAW //平局} GameStatus; // 枚举游戏状态
typedef enum { MOVE_ACCEPTED, // 可以下棋 MOVE_OUT_OF_BOUNDS, // 当前位置在棋盘外 MOVE_OCCUPIED // 当前位置已占用} MoveResult; // 下棋结果
typedef struct { char cells[BOARD_SIZE][BOARD_SIZE]; // 棋盘信息 char current_player; int move_count; // 步数统计 GameStatus status;} Game;// 你可以不完全按照我的结构体定义,你可以自行更改变量名,或者你有别的定义方法也可以接下来让我为你简单阐述以下面对这个项目要求的一个思路:可以把问题分为两个板块,第一个是处理“五子连珠”的游戏结束判定,第二个是要解决绘制棋盘和如何落子的问题。显然,第二部分是更可视化的,是第一部分的基础,也就是我们先要解决的。
因此我们先要解决如何在终端中绘制一个棋盘的问题,接下来要解决如何下棋的问题,最后确定怎样结束游戏。
我们可以先设想主函数中的循环样式,
int main(void){ 初始化 Game; 初始化 GameConsole;
while (游戏状态为 GAME_RUNNING) { 绘制棋盘和底部状态; 等待有效的鼠标格子点击; 调用 game_place; }
绘制最终棋盘和底部胜负结果; 等待用户按键; 恢复控制台状态; return 0;}step2_引入坐标,绘制棋盘
Section titled “step2_引入坐标,绘制棋盘”“使用鼠标左键点击棋盘格落子”有这么一个要求,相信初学c语言的你可能会产生困惑,应该怎样才能实现这样的一个操作?这需要使用到c语言开发中很常用“Windows Console API ”。
这个接口用于控制终端窗口,包括读取键盘和鼠标、移动光标、修改颜色以及操作屏幕缓冲区。
现在请你自行学习这个api,在这一题中,你只需要会读取鼠标左键时光标的位置即可,不用学的很深入。
接下来我们要绘制棋盘。下面是我给出的一种棋盘的样式,每一个棋格长4宽2(字符坐标),而棋子坐标可由棋盘坐标算出。从而实现鼠标光标落点到对应棋子的转化。
+---+---+---+---+---+---+---+---+---+| . | . | . | . | . | . | . | . | . |+---+---+---+---+---+---+---+---+---+| . | . | . | . | . | . | . | . | . |+---+---+---+---+---+---+---+---+---+请你推算出字符坐标到棋盘坐标的计算公式。
为了实现下棋这一个功能,我给出我的实现思路:
- 初始化棋盘,将game初始化,cells全部赋值为“.”,currentplayer为”X”,move_count为0,status为GAME_RUNNING
- 绘制棋盘
- 读取鼠标左键位置,将光标坐标转化为棋盘坐标,将棋盘坐标对应的cells数组位置赋值为currentplayer,currentplayer变为相反元素
- 重新绘制棋盘
- 在3,4间循环直到达成游戏结束的条件
具体代码请你自己实现,循环功能可以放在主函数中,完成绘制棋盘,初始化棋盘,和改变game这几个功能函数即可。
提示:在这里,你可以先在主函数中调用这些函数,看能否打印出棋盘,能否刷新棋盘,进行简单的测试。
step3_游戏结束的条件判定
Section titled “step3_游戏结束的条件判定”要进行游戏是否结束的判定,你需要在上述的哪一步对cells数组进行检测?
你要做怎样的检测?
通过对棋盘坐标的计算可以简单的完成游戏结束的条件判定。请你说说为什么要设计棋盘坐标和字符坐标两种坐标?
相信你在思考完上述问题后,已经知道该如何补全这部分代码了。请你将这部分代码写在game.c当中。
完成功能函数后,请你根据我上面给出的提示完成主函数中的循环。
完成主循环后你就可以开始测试工作了,在这里我提几个你可能会犯的小错误:
- 当光标落在棋盘外时是否有判错?有效步数是否增加?光标落在棋格边界上呢?
- 光标到棋盘坐标的计算是否正确?是否会出现偏移情况?
- 斜向的棋子判定是否正常?当五子连珠后游戏能否正常结束?是否有考虑平局的情况?
在完成上面的工作后,你会发现现在这个项目很单调,只有一个棋盘,没有别的内容。因此你可以在刷新棋盘时添加提示语句,在棋盘下面打印current_player和game_status等信息。为什么是在棋盘下面?
在游戏结束后,你可以打印获胜一方(current_player)和有效步数等信息,丰富游戏内容。
最后在游戏结束时,别忘了加入初始化控制台,完成内存释放,规范细节。
五子棋游戏是一个很经典的c语言项目,可以帮助你提升代码熟练度,更好的面对接下来的招新题目。如果你还想写点什么,你可以研究研究贪吃蛇这个同样经典且简单的项目,想想应该如何实现。你也可以看看网上一些项目介绍视频,看看其中是怎样切入一个项目并完成项目结构的设计。
本题提交方式
Section titled “本题提交方式”出题人联系方式
Section titled “出题人联系方式”出题人:
taaaakoooo
QQ:1748798371