[ C语言 ] 用C语言实现小游戏 ---- 三子棋 代码 + 解析

article/2025/8/23 12:50:30





前言

本篇文章记录了用C语言实现三子棋小游戏,主要目的是对之前C语言知识学习的巩固,联系各个知识,以及怎么样实际使用各个知识。





一、三子棋的游戏规则

玩家将会看到一个3X3的网格棋盘,默认玩家先下棋,电脑后下棋。

规定:先连成一条直线(3个棋子)的玩家获胜,行,列,对角线均可。若在棋盘下满时仍未分出胜负,则为平局





二、使用到的头文件

#include <stdio.h>
#include <stdlib.h>
#include <time.h>





定义3*3的棋盘

#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 player_move(char board[ROW][COL], int row, int col); 

电脑下棋:

void computer_move(char board[ROW][COL], int row, int col);

判断输赢:

//玩家赢  - '*'
//电脑赢  - '#'
//平局  -  'Q'
//继续  - 'C'
char is_win(char board[ROW][COL],int row,int col);

三、游戏的测试

主函数:

int main() {test();//调用test测试函数return 0;
}

test函数:

void test() {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);
}

解析test函数主要构成:

i>菜单menu()函数:

void menu() {printf("******************************\n");printf("*****   1. play       ********\n");printf("*****   0. exit       ********\n");printf("******************************\n");}

实现效果:

 ii>switch case 语句:实现了玩家通过不同输入选择实现不同的功能。

效果显示:

iii>game()函数:当玩家输入1时,跳入到游戏的实现代码之中。

void game() {// 数据存储,玩家下棋'*',电脑下棋是'#'char board[ROW][COL] = {0};//数组的内容 应该是全部空格InitBoard(board,ROW,COL);// 初始化棋盘// 打印棋盘DisplayBoard(board,ROW,COL);//下棋char  ret = 0;while (1) {player_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C') {break;}computer_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C') {break;}}if (ret == '*') {printf("玩家赢\n");}else if (ret == '#') {printf("电脑赢\n");}else{printf("平局\n");}}

game()函数里面包括了:打印棋盘函数,初始化棋盘函数,玩家下棋函数,电脑下棋函数,判断输赢函数的调用,已经规定输赢的条件,具体每个函数的实现代码和问题如下。

注:最后有game()函数的逻辑顺序。

四、游戏的实现

游戏的实现逻辑:

(一)打印棋盘

我们首先实现对棋盘的打印:

我们在头文件中规定了 3行3列

#define ROW 3 
#define COL 3 

自定义函数DisplayBoard实现对棋盘的打印:

预期实现的棋盘模样:

 我们发现里面包含了数据和分割行,实现代码:

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]);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");}
}

(二)初始化棋盘函数

定义InitBoard()函数,主要实现代码如下:

void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++) {    //3行for (j = 0; j < col; j++) { // 3列board[i][j] = ' ';}}
}

初始化棋盘全为空格

(三)玩家下棋

自定义函数 player_move 实现,代码如下:

void player_move(char board[ROW][COL], int row, int col) {printf("玩家下棋:>");int x = 0;int y = 0;while (1) {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");}}
}

这里面包含了很多小问题和解决方案:

1:输入的坐标不在棋盘的范围内怎么办?

答:使用if else 选择语句,如果输入的坐标合法,则输入成功,如果输入的坐标不合法则会提醒“坐标非法,请重新输入!”字样。

if (x >= 1 && x <= row && y >= 1 && y <= col)

2:输入的坐标在棋盘上已被占用怎么办?

这个问题我们需要转化成这个问题解决:

i>怎么判断输入坐标被占用?

答:我们通过对选择语句if else 对改坐标进行判断,由于我们在初始化棋盘时,初始化棋盘全部为空格,如果输入坐标所对应的格子是空格,则说明未被占用,如果输入坐标所对应的格子不是空格,则说明该格子已经被占用。

if (board[x - 1][y - 1] == ' ')

ii>如何正确输入棋子?

如果输入坐标所对应的格子是空格,则可以成功输入,如果不是空格,则会else提醒玩家“该坐标被占用,请重新输入!”字样。利用while循环语句可再次输入正确的未被占用的坐标。

(四)电脑下棋

自定义函数 computer_move 实现,代码如下:

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 ~ 2y = rand() % COL; // 0 ~ 2if (board[x][y] == ' ') {board[x][y] = '#';break;}}
}

这里也包含了几个小问题和解决方案:

1:这里电脑的输入是随机输入,如何实现?

答:这里我们并非是真的随机值,只是利用了时间戳,由于时间在每时每刻的改变,所以在不同的时间,经过处理后的时间我们也无法知道,可当做随机值使用。这里调用了time函数,实现代码如下:

#include <time.h>
srand((unsigned int)time(NULL));

由于在这里强制转化为正整数。

2:如何控制电脑随机输入的值合法?

答:这个问题的意思是,如果不对这个随机值进行处理,那么这个值很可能超出棋盘,所以要对这个值进行控制,由于棋盘规定3行3列,数组下标由0开始,所以随机值只要在0~2之内即可。所以我们对这个随机值进行取模(取余数)处理即可解决此问题:

x = rand() % ROW; // 0 ~ 2
y = rand() % COL; // 0 ~ 2

为了区分玩家和电脑的棋子不同,在此规定

玩家使用 ' * ' , 电脑使用 ' # '

因为这里电脑输入坐标均为随机值,所以不具有判断的能力,读者可以思考一种优化算法,写出一种最快赢下比赛的算法。而不至于出现可能都已经一行出现2个棋子了,随机值可能再下到别处的情况(哈哈 人工“智障”)。

 (五)判断输赢

实现代码:

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][1] != ' ')return board[i][1];}// 三列for (i = 0; i < col; i++) {if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')return board[1][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 (1 == is_full(board, row, col)) {return 'Q';}//继续return 'C';
}

游戏规定,首先完成一行或者一列或者对角线的玩家获胜,在此我们只需要进行三行,三列,对角线的判断以及平局的判断,游戏继续判断。具体是玩家赢还是电脑赢,我们在测试函数test中有规定,不同的玩家对应不同的字符,在此规定:

三行的判断:

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][1];}

三列的判断:

	for (i = 0; i < col; i++) {if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')return board[1][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];}

平局的判断:

游戏规定,当棋盘下满时,还未分出胜负时,则为平局。

因此首先我们思考如何判断棋盘是否下满?

答:在这里我们通过返回值的数字来判断是否下满

自定义函数 is_full函数,具体代码:

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;
}

代码逻辑:我们通过返回值来判断棋盘是否下满,

如果未被下满,则返回值是0(return 0 )

如果下满我们将返回1(return 1)

小问题:我们如何判断是否下满?

我们遍历数组的过程中,如果发现还有空格存在,说明棋盘还没有被下满,我们立刻返回0,否则说明棋盘没有空格存在,说明已经下满,返回1.

所以我们就可以通过返回值判断平局,代码如下:

	if (1 == is_full(board, row, col)) {return 'Q';}

如果返回值 == 1 说明 棋盘被下满 我们返回字符  ' Q ' (我们刚刚已经规定Q为平局)

、game()函数

我们再次将game()函数调出进行详解:

void game() {// 数据存储,玩家下棋'*',电脑下棋是'#'char board[ROW][COL] = {0};//数组的内容 应该是全部空格InitBoard(board,ROW,COL);// 初始化棋盘// 打印棋盘DisplayBoard(board,ROW,COL);//下棋char  ret = 0;while (1) {player_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C') {break;}computer_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C') {break;}}if (ret == '*') {printf("玩家赢\n");}else if (ret == '#') {printf("电脑赢\n");}else{printf("平局\n");}}

根据代码发现主要逻辑顺序:

 这是game()函数内部的主要逻辑顺序,每一步所对应的函数调用和判断也均在图中显示。

、演示

完整代码: 完整代码我放在我的Gitee仓库内,链接如下:

https://gitee.com/Yaulixingyu/c-language/tree/master/三子棋/三子棋

游戏演示:

 

总结

以上就是我对三棋子小游戏的实现,有兴趣的小伙伴可以对代码进行优化,可实现五子棋等,也可以对电脑下棋记性优化,使电脑不再人工“智障”。

哈哈哈~由于文章较长,感谢各位小伙伴的观看,由于本人的技术水平有待提高,如果遇到错误也请及时指正。如果各位小伙伴觉得不错的话,可以点赞关注一波~多谢多谢

下期预告:扫雷  小游戏

链接:[ C语言 ] 扫雷 ------> 用C语言实现game2_小白又菜的博客-CSDN博客


http://chatgpt.dhexx.cn/article/NSOvcPnx.shtml

相关文章

一个好玩的小游戏(纯C语言编写)

最近在看知乎是发现了一个这一个专栏 https://zhuanlan.zhihu.com/c2game 从中获取的许多知识&#xff0c;本文中的游戏也是从里面学到的&#xff0c;不过本人又自己加了一些功能。 这是一个类似于飞机大战的游戏&#xff0c;不过目前代码量比较小&#xff0c;所以看起来非常…

【用游戏学C语言】几个基本的小游戏的实现(缓慢更新中~)

目录 ​更新说明 前言 1.相关函数的简单介绍&#xff08;预备知识&#xff09; &#xff08;1&#xff09;关于函数getch() &#xff08;2&#xff09;关于函数system() &#xff08;3&#xff09;关于函数sleep() &#xff08;4&#xff09;关于函数kbhit() &#xff…

【C语言】游戏项目:《疯狂赛车》,每个人都要加油活下去

序 交换一个苹果&#xff0c;得到一个苹果&#xff1b;交换一种思想&#xff0c;得到一种思想。选择与你才干&#xff0c;性格不同的人&#xff0c;他可以弥补你的缺陷。 嗨&#xff01;这里是狐狸~~ 最近有点网抑云了&#xff0c;脑子很乱&#xff0c;不晓得想些什么&#…

Qt学习之QFile和QFileInfo

Qt项目中对文件操作是必不可少的。顾名思义&#xff1a;QFile是文件对象类&#xff0c;QFileInfo是文件信息对象类&#xff0c;结合例子我们看一下用法。 读的文件内容如下&#xff0c;以字符 “#” 或者 “;” 开始的为注释行。 [Extern_Item1] ;名称 Namelibccgext_cvi_64.so…

QT5 QFile读/写文件操作方法

文档打开读/写操作命令说明 值描述QIODevice::NotOpen未打开QIODevice::ReadOnly以只读方式打开QIODevice::WriteOnly以只写方式打开QIODevice::ReadWrite以读写方式打开QIODevice::Append以追加的方式打开&#xff0c;新增加的内容将被追加到文件末尾QIODevice::Truncate以重…

qt5之QFile读写文件

1、效果 读写文件用到的是QFile类&#xff0c; 这里&#xff0c;我显示文件内容用到的是 QTextEdit 2、创建打开和关闭按钮 // 打开文件btnOpenFile new QToolButton;btnOpenFile->setText(tr("open a file"));btnOpenFile->setToolTip(tr("open …

Qt 创建文件 用QFile和QDir类

项目需求是 根据日期创建多级子文件夹, 根目录保存 log.txt 控制台程序实现 如下执行结果 createFile 为程序目录 文档结构: 源码: #include <QtCore/QCoreApplication> #include <QDir> #include <QFile> #include <QDebug> #include <QDateTim…

QFile(文件)

QFile QFile提供一个用于读/写的接口&#xff0c;是一个可以用来读/写二进制文件的Qt资源的I/O设备&#xff0c;QFile可以单独使用&#xff0c;一般配合QTextStream或QDataStream 输入文件路径时最好使用"/"作为分隔符 构造函数&#xff1a; 常用的函数&#xff1a;…

QFileDialog

一、描述 QFileDialog 类使用户能够遍历文件系统以选择一个或多个文件或目录。 创建 QFileDialog 最简单的方法是使用静态函数&#xff1a; fileName QFileDialog::getOpenFileName(this, tr("Open Image"), "/home/jana", tr("Image Files (*.p…

Qt -- QFile文件读写操作

对于文件的读写操作&#xff0c;C 和 C 都各有一套方式。而在 Qt 中也有一套&#xff0c;即使用 QFile 对文件进行读和写操作。 文件的打开方式 文件路径说明&#xff1a;&#xff08;windows-release编译&#xff09; QFile *file new QFile("EcgCap.dat");表示这…

[QT_032]Qt学习之基本文件读写QFile

本文转自&#xff1a;《Qt编程指南》 作者&#xff1a;奇先生 Qt编程指南&#xff0c;Qt新手教程&#xff0c;Qt Programming Guide 7.2 基本文件读写QFile Qt 常见的文件读写类有三个 QFile、QTextStream 和 QDataStream&#xff0c;本节先概要介绍这三个文件读写类&…

QFileInfo

一、描述 QFileInfo 提供有关文件系统中文件的名称和位置&#xff08;路径&#xff09;、访问权限、文件类型等信息。 FileInfo 还可用于获取有关 Qt 资源的信息。这个类是隐式共享的。 二、成员函数 2.1、判断函数 1、bool isAbsolute() 文件路径是否绝对路径。 注意&am…

QFile详解(文件如果不存在则创建、判断文件是否存在、获得文件的各种详细信息、读写文件)

目录 一、QFile文件如果不存在则创建的方法 二、QFile判断文件是否存在的方法 三、QFileInfo的方法获得文件的各种详细信息 四、QFile读写文件的内容 一、QFile文件如果不存在则创建的方法 QFile f("./1234.ini");if(!f.open(QIODevice::Append)){return 0;} op…

QFile文件读写

文章目录 简介常用apiQFile类读写文件QFileQTextStream读写文件 简介 QFile类提供了一个读取和写入文件的接口&#xff0c;一个读写文本、二进制文件和资源的I/O设备。 QFile读写文件的两种方式&#xff1a; 1.QFile可以单独使用。 2.QFile与QTextStream或QDataStream一起使用…

Qt之Qfile读取文件操作

文件系统&#xff1a;   文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。下面是 I/O 设备的类图&#xff08;Qt5&#xff09;&#x…

常用性能测试工具的比较

目录 性能测试的重要性针对接口的性能测试 性能测试基准接口性能测试的主要指标abenchjMeterKelude性能脚本各种监控工具 参考总结 性能测试的重要性 众所周知性能测试在软件测试中占有举足轻重的作用&#xff0c;尤其是对于互联网产品这种具有大用户量&#xff0c;大数据量&a…

推荐几款常用的性能测试工具

“ 对内容不感兴趣拉到最后领取今天的外卖红包。” 常用的性能测试工具 对于开发人员来说&#xff0c;首选是一些开源免费的性能&#xff08;压力&#xff09;测试软件&#xff0c;例如 ab&#xff08;ApacheBench&#xff09;、JMeter 等&#xff1b;对于专业的测试团队来说&…

10款主流的软件测试工具,你用过吗?

随着软件快速交付需求的增长&#xff0c;越来越多的企业开始通过DevOps方法加速软件开发速度但这样的话&#xff0c;有时候就无法保证质量&#xff0c;所以今天小编就来给大家介绍10款主流的软件测试工具&#xff0c;供大家参考。 1、UFT / QTP UFT&#xff0c;前身为Quick …

10款好用的自动化测试工具

&#x1f4cc; 博客主页&#xff1a; 程序员二黑 &#x1f4cc; 专注于软件测试领域相关技术实践和思考&#xff0c;持续分享自动化软件测试开发干货知识&#xff01; &#x1f4cc; 如果你也想学习软件测试&#xff0c;文末卡片有我的交流群&#xff0c;加入我们&#xff0c;一…

常用的软件测试工具大全

开源测试管理工具&#xff1a;Bugfree、Bugzilla、TestLink、mantis 开源功能自动化测试工具&#xff1a;Watir、Selenium、MaxQ、WebInject 开源性能自动化测试工具&#xff1a;Jmeter、OpenSTA、DBMonster、TPTEST、Web Application Load Simulator **[TestDirector]&…