C语言_三子棋游戏

article/2025/7/10 23:21:06

在这篇博客中,我将从头到尾整理三子棋游戏的代码,争取能将这个小游戏里面包含的细节能全整理出来。为什么要整理呢?因为我觉得如果不看任何参考能用C出一个小游戏,是一件蛮厉害的事情,要做到这件事情,需要对游戏的细节完完全全地掌握。当然,三子棋是个小游戏,实现这个游戏并不需要很多高深的技术,甚至连指针都不需要,单纯靠二维数组就可以做到。但是,实现这个小游戏还是蛮费劲的,需要一定的逻辑,实现过程就感觉跟做一道很长的数学分析证明题,尽管整个题的思路你很清楚,但做起来还是挺麻烦,一环套一环,要做到每个细节的准确才能做出来。(我的废话真多!)

目录

  • 三子棋游戏介绍
  • 三子棋整体思路
  • 三子棋文件划分
  • 按文件分析代码
    • 头文件
    • 主程序文件
    • 函数实现文件
  • 程序运行
    • 棋盘
    • 玩家下一个棋
    • 玩家获胜
  • 总结与畅想

三子棋游戏介绍

三子棋与五子棋很相似,规则也都差不多,相当于五子棋的简化游戏。与五子棋主要有两个区别,一是只需要有三个棋子连成一行就能赢,二是三子棋的棋盘大小是3*3的,这跟五子棋相比会简单很多,程序也好写一些。

三子棋整体思路

我们先来考虑程序需要实现什么,从一个玩家的角度来看:

  1. 我们需要输出一个菜单,让玩家选择开始游戏或者退出
  2. 选择开始游戏后,要输出一个棋盘
  3. 然后提示玩家选一个位置下棋,玩家下完棋之后,电脑下一个棋,这个过程需要多次进行
  4. 判断胜负

三子棋文件划分

三子棋游戏的代码还是有点长的,如果在一个源文件里面写完整个代码,会非常麻烦。为了方便,我们把代码放到三个文件中。具体文件划分如下:

  1. 头文件:sanziqi.h 这个文件中放我们需要引用的头文件和函数声明
  2. 主程序文件:sanziqi.c这个文件中写我们函数的主体
  3. 函数实现文件:hanshu.c这个文件中具体实现我们要用的函数

按文件分析代码

头文件

sanziqi.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>// 宏定义棋盘的大小,这样后面我们想改变棋盘大小时直接改这一处即可
#define ROW 3 // 行数
#define COL 3 // 列数// 初始化数组
void InitBoard(char Board[ROW][COL], int row, int col);// 打印棋盘
void PrintBoard(char Board[ROW][COL], int row, int col);// 玩家下棋
void PlayerWalk(char Board[ROW][COL], int row, int col);// 电脑下棋
void ComputerWalk(char Board[ROW][COL], int row, int col);// 判断输赢
int CheckWin(char Board[ROW][COL], int row, int col);

这个文件中包含的是:

  • 需要用到的头文件
  • 通过宏定义程序中经常出现的变量,方便后期修改
  • 所有的功能函数的声明

有了这个文件,我们在其他文件中引用它,这样就不用写再其它头文件的引用了,可以精简代码,程序也会更加清晰。

主程序文件

sanziqi.c

void menu()
{printf("****************************************\n");printf("***********   1. 开始游戏   ************\n");printf("***********   0. 退出游戏   ************\n");printf("****************************************\n");
}void game() // 游戏主函数
{// 初始化一个数组存储数据char Board[ROW][COL] = { 0 }; // 棋盘上每一个位位置都是存在这个数组中InitBoard(Board, ROW, COL); // 初始化一个棋盘// 打印棋盘PrintBoard(Board, ROW, COL);// 玩游戏时// 1.玩家赢 - '*'// 2.电脑赢 - '#'// 3.平局了 - 'Q'// 4.继续   - 'C'char ret = 0; // 初始化一个字符变量,按照棋盘上的情况将对应的上面的字符赋给retwhile (1){PlayerWalk(Board, ROW, COL); // 让玩家下// 不论是玩家还是电脑下了一个棋后,我们都要判断棋盘上的局势// 判断输赢ret = CheckWin(Board, ROW, COL); // 得到棋盘上的情况相对应的字符 if (ret != 'C') // 如果返回的字符是C,那么代表程序需要继续{// 如果能进入循环,说明结局已定不需要再循环了break; // 直接跳出此次循环}PrintBoard(Board, ROW, COL); // 如果没有跳出循环,那么打印玩家下完棋后的棋盘ComputerWalk(Board, ROW, COL); // 现在轮到电脑下棋了,所有流程同上// 判断输赢ret = CheckWin(Board, ROW, COL);if (ret != 'C'){break;}PrintBoard(Board, ROW, COL);}if (ret == '*') {printf("玩家赢\n");}else if (ret == '#'){printf("电脑赢\n");}else if (ret == 'Q'){printf("平局了\n");}// 打印完结局之后,需要让玩家看一下棋局PrintBoard(Board, ROW, COL);
}int main()
{int input = 0; // 初始化一个整型变量,后面用来存储玩家的选择// 下面是设置随机种子,是为了后面生成电脑下棋的随即坐标,具体用法可以参考我的上一篇博客srand((unsigned)time(NULL));// 下面使用一个 do while 循环,因为程序一运行就要看到菜单,让玩家选择do{menu();  // 打印菜单printf("请选择:>");scanf("%d", &input);// 根据用户的选择执行对应的操作switch (input){case 1:game(); // 调用游戏主函数break;case 0:printf("退出游戏!\n");exit(0);default:printf("输入错误!\n");}} while (input);return 0;
}

这个文件中写的是游戏的主体框架,game函数和menu函数并非是功能函数,所以不需要写在函数文件中。关于主体框架的详细思路,我在上述代码中写了很详细的注释,可以说是非常的详细。

函数实现文件

hanshu.c

#include "sanziqi.h"// 函数实现// 初始化存储棋盘上数据的数组,我们对棋盘上所有的位置赋上空格,因为初始时棋盘上所有位置都是空的
void InitBoard(char Board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){Board[i][j] = ' ';}}
}// 打印棋盘,包括棋盘上的落子情况
void PrintBoard(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");}}
}// 玩家下棋
void PlayerWalk(char Board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家请开始下棋:\n");while (1) // 无论如何玩家都得下一个棋{printf("请选择下棋位置:> ");scanf("%d%d", &x, &y);// 对于玩家来说,棋盘的左上角位置就是第一行第一个位置,即(1,1),但是数组却是从(0,0)开始的,// 因此我们需要对玩家输入的坐标减一,这样能保证玩家直观理解,同时也不浪费数组空间if (x >= 1 && x <= row && y >= 1 && y <= col){if (Board[x - 1][y - 1] == ' '){Board[x - 1][y - 1] = '*';break;}}else{printf("输入有误,请重新输入!\n");}}
}// 电脑下棋
// 电脑的下棋的坐标我们利用随机数生成
void ComputerWalk(char Board[ROW][COL], int row, int col)
{printf("电脑走:>\n");while (1){int x = rand() % ROW; // 这块生成的随机数范围是0~ROW-1的int y = rand() % COL;if (Board[x][y] == ' ') // 如果位置为空,那么就下一个棋{Board[x][y] = '#';break;}}
}// 判断棋盘是否满了,这块使用static关键字是因为此函数只在此文件中使用,其他文件中不会调用
// 这样写这个函数也只能在这个函数中使用
static int IsFull(char Board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (Board[i][j] == ' '){return 0; }}}return 1; // 满了返回1
}// 判断棋盘上的局势
int CheckWin(char Board[ROW][COL], int row, int col)
{// 每次判断的时候,先判断有没有赢的,没有的话就检查棋盘有没有满,根据情况返回对应字符// 按行检查有没有凑齐的for (int i = 0; i < row; i++){int flag = 1; // 定义一个标记变量 1表示凑齐了 0表示没凑齐for (int j = 0; j < col; j++){if (Board[i][0] != Board[i][j]) // 判断是否跟第一个元素相同{flag = 0; // 如果出现一个不同的,那这行剩下的就不用再判断了,直接跳到下一行break;}}if (Board[i][0] != ' ' && flag != 0) // 判断这一行元素是不是空的,有没有凑齐{return Board[i][0]; // 满足条件就返回这行的首元素,作为反馈字符} }// 按列检查有没有凑齐的,思想同上for (int i = 0; i < col; i++){int flag = 1;for (int j = 0; j < row; j++){if (Board[0][i] != Board[j][i]){flag = 0;break;}}if (Board[0][i] != ' ' && flag != 0){return Board[0][i];}}// 检查主对角线{int flag = 1;for (int i = 1; i < row; i++){if (Board[0][0] != Board[i][i]){flag = 0;break;}}if (Board[0][0] != ' ' && flag != 0){return Board[0][0];}}// 检查次对角线 下面注释的这行是只针对三子棋的/*{if (Board[0][2] == Board[1][1] && Board[1][1] == Board[2][0] && Board[0][2] != ' ')return Board[1][1];}*/// 下面的代码是针对任意情况的,如果我们更改了棋盘大小也能判断{int flag = 1;for (int i = 0, j = col - 1; i < row; i++, j--){if (Board[0][col - 1] != Board[i][j]){flag = 0;break;}}if (Board[0][col - 1] != ' ' && flag != 0){return Board[0][col - 1];}}// 检查棋盘// 判断棋盘是否满了if (IsFull(Board, ROW, COL) == 1){return 'Q';}// 不是平局,游戏继续return 'C';
}

在这个文件所实现的功能函数中,CheckWin函数最复杂也最为巧妙,复杂是因为要检查出棋盘上的所有情况,特别是判断有没有赢家的时候,要按行、按列、按对角线判断。巧妙体现在这个函数的返回值上,当我们检查某一行三个元素都相同时,那我们直接返回这一行的某个元素即可。还有值得注意的是static关键字的使用,static修饰函数会将这个函数的使用范围限制在当前文件中。其余的细节,我十分详细地加了注释在代码之中。

程序运行

棋盘

在这里插入图片描述
图片下面的水印我没有找到去除的方法。。。
我们来观察这个棋盘,直观看起来是3*3的,但其实它有5行,中间有两行是用来分隔得,具体的细节放大看这个图片就会很明显。

玩家下一个棋

在这里插入图片描述

玩家获胜

在这里插入图片描述
这个水印挡住了最下面一行位置得棋子。。。我下去再好好研究一下CSDN上传照片的规则。

总结与畅想

以上就是三子棋游戏的所有代码了,我是在VS2019编译器中写的,在别的编译器运行起来应该没毛病,但是我没有特别详细地测试代码,不过在我有限的测试下没出什么问题,不得不说测试还是蛮无聊的。上面的代码其实改一下宏定义变量的大小,立马就能改成阉割版的五子棋。
那么我为啥要写一个三子棋游戏而不去写一个五子棋呢?主要就是电脑下棋的过程和判断胜负过程实现起来有点复杂。不过我也简单思考了一下五子棋与三子棋实现起来的区别。首先就是五子棋通常是生成一个固定大小的棋盘,每下一个棋需要判断这个这个棋子周围(半径为5个棋子)所有棋子(情况还要细分),然后就是电脑自动下棋的事情,三子棋中就那么几个格子,随便下一个位置就能起到一定的影响,但是在大棋盘中,如何实现电脑智能下棋是个问题,还有如何实现电脑智能度的控制等等。这个我以后再写吧。


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

相关文章

十年前开发的平板游戏:HyllCube 三维四子棋游戏,获得了全国一等奖

昨天&#xff0c;无意间翻到了本科时候的一个视频。 那是在 2011 年 9 月&#xff0c;那时刚升大三&#xff0c;我&#xff08;打酱油&#xff09;和另外三位童鞋组队参加了第四届 Intel 杯全国大学生软件创新大赛&#xff0c;开发了 HyllCube 三维四子棋游戏。最终&#xff0c…

人机对战初体验:Python基于Pygame实现四子棋游戏

人机对战初体验—四子棋游戏 继去年3月人机大战引发全球瞩目以来&#xff0c;围棋AI&#xff08;人工智能&#xff09;再度引发跨领域的关注&#xff1a;一个叫Master的围棋AI&#xff0c;几天时间&#xff0c;面对中日韩顶尖职业围棋选手&#xff0c;已取得60胜0败的恐怖战绩&…

三子棋小游戏

今天我们来看看三子棋小游戏吧&#xff01; &#xff08;代码量有点多对于我小小白&#xff09; so分为多文件形式 test.c &#xff1a; 测试三子棋游戏&#xff08;调用其他两个&#xff09; main函数 game.h &#xff1a;三子棋游戏的函数声明 game.c &#xff1a;游戏函…

c++三子棋游戏程序

c编写三子棋游戏程序&#xff08;修改宏定义N&#xff0c;可变成四子棋、五子棋、六子棋....)&#xff0c;代码如下&#xff1a; //c小练习——编写三子棋游戏程序 #include<iostream> #include<cstdlib> #include<time.h> using namespace std; #define N …

三子棋游戏思路

今天用C语言来模拟一个三子棋游戏。 总共大概分为五部 1.构建一个菜单出来&#xff0c;让玩家可以选择是否进行游戏。 2.打印棋盘&#xff0c;通过对二维数组的运用&#xff0c;打印一个N*N的棋盘&#xff0c;主要是用空格将棋盘初始化&#xff0c;并将棋盘的框架打出。 3.…

【C语言】三子棋游戏详解

目录 一、三子棋的游戏规则 二、基本流程 三、实现步骤 3.1打印菜单 3.2 创建并初始化棋盘 3.3 打印棋盘 3.4 玩家落子 3.5 电脑落子 3.6 判断输赢 四、游戏演示 五、完整代码 一、三子棋的游戏规则 三子棋也就是经常玩的井字棋&#xff0c;游戏分为双方对战&#xff…

JAVA安卓植物大战僵尸主题四子棋游戏

前言 这里使用安卓最基本的API实现双人四子棋游戏&#xff08;无AI&#xff09;&#xff0c;开发语言为java&#xff0c;开发环境为Android Studio 2.1.2&#xff0c;目标SDK版本为24&#xff0c;最低为15&#xff1b;界面采用植物大战僵尸主题&#xff0c;图片资源来源于网络&…

三子棋游戏

目录 一、三子棋游戏简介 二、三子棋游戏创建文件 三、三子棋游戏设计 1.主菜单的创建 2.棋盘设计 四、三子棋游戏结果 五、代码源 一、三子棋游戏简介 三子棋是黑白棋的一种。三子棋是一种民间传统游戏&#xff0c;又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线…

人机对战初体验—四子棋游戏

一、实验介绍 1.1 实验内容 实验利用Python模拟AI和玩家进行四子棋游戏&#xff0c;利用游戏实验Pygame库&#xff0c;为游戏提供界面和操作支持。AI算法借用蒙特卡洛搜索树思想。通过设置AI的难度系数&#xff0c;即AI所能考虑到的未来棋子的可能走向&#xff0c;从而选择出最…

Pygame——AI重力四子棋

突然奇想&#xff0c;什么时候可以自己实现一个机器对战的小游戏&#xff0c;但一直不敢去尝试&#xff0c;直到偶尔发现了重力四子棋的规则&#xff0c;有限的空间棋盘正好可以拿来练手。 有关下棋AI的算法&#xff0c;说来说去也就那么几种&#xff0c;随机蒙特卡罗方法、UC…

C语言简单游戏编程入门之四子棋

运行截图 源代码 #include<stdio.h> #include<stdlib.h> /*四子棋1.在一个6行7列的棋盘中2.玩家1和玩家2依次交替下子3.每次下子落于棋盘可能达到的最下方4.先四子相连为胜5.棋盘已满且无四子相连为平局 *//*定义常量*/ //行数 #define ROW 7 //列数 #define C…

基于Python实现四子棋游戏

1. 实验介绍 1.1 实验内容 实验利用 Python 模拟 AI 和玩家进行四子棋游戏&#xff0c;利用游戏实验 Pygame 库&#xff0c;为游戏提供界面和操作支持。AI 算法借用蒙特卡洛搜索树思想。通过设置 AI 的难度系数&#xff0c;即 AI 所能考虑到的未来棋子的可能走向&#xff0c;…

运用Python——劳拉下棋_四连环游戏_重力四子棋游戏(代码与游戏判定)

导航 运用Python——爬虫_网易云音乐热评 运用Python——游戏_四子棋_劳拉下棋 文章目录 导航1.游戏规则2.玩法分析3.部分详解第一部分&#xff1a;初始化第二部分&#xff1a;棋盘显示第三部分&#xff1a;玩家输入第四部分&#xff1a;运行第五部分&#xff1a;胜利判断 4.完…

ISME | 热液微生物群落揭示了喷口区的生物地理学和嗜热性的进化历史

Auka热液喷口区的微生物群落揭示了喷口区的生物地理学和嗜热性的进化历史 Microbial community of recently discovered Auka vent field sheds light on vent biogeography and evolutionary history of thermophily Article The ISME Journal, [IF 10.3] DOI&#xff1a;10.…

S32K1xx 固件更新

1 介绍 随着当前技术的进步&#xff0c;车辆变得更加电子化而不是机械化。车辆中的电子创新不断增加。因此&#xff0c;车辆中的软件也在增加&#xff0c;因此存在潜在错误的风险。 每次发现软件错误时&#xff0c;都需要进行召回过程来更新软件。这些召回代表了汽车制造商的…

萤火虫算法综述

1.萤火虫算法概述 萤火虫闪烁的光芒在热带和温带地区的夏季天空中是一道令人惊叹的风景。大约有两千种萤火虫&#xff0c;大多数萤火虫会发出短暂而有节奏的闪光。闪光的模式对于特定物种来说往往是独一无二的。闪光是由生物发光过程产生的&#xff0c;这种信号系统的真正功能仍…

《闪》(霹雳战狗 bolt)电影感悟

when you stuck your head, relax, turn and pull. 有时候做人做事要转换一下方式&#xff0c;否则还是会卡住头。Because all around the planet, there are animals who feel like they cannot, like a little hamster, who once spends his day in the vehicle park dreamin…

大学英语四新视野 课后习题+答案翻译 Unit1~Unit8

Unit 1 Text A: Words in use 2022年6月16日 20:57 1 As the gender barriers crumbled, the number of women working as lawyers, doctors, or bankers began to increase significantly from the mid-20th century. 随着性别障碍的消除&#xff0c;从20世纪中期开始&am…

拉勾网爬虫

源代码&#xff1a;https://github.com/carlblocking/xxw-for-public/tree/master/LaGouSpider 前几天写了一个知乎网的爬虫并爬取了一些数据&#xff0c;然而新鲜感消失的很快。于是&#xff0c;大概2天前开始试着爬取拉勾网上的数据。 在解析数据的过程中&#xff0c;知乎爬…

爬虫实战(三) 用Python爬取拉勾网

0、前言 最近博主面临着选方向的困难&#xff08;唉&#xff0c;选择困难症患者 &#xff1e;﹏&#xff1c;&#xff09;&#xff0c;所以希望了解一下目前不同岗位的就业前景 这时&#xff0c;就不妨写个小爬虫&#xff0c;爬取一下 拉勾网 的职位数据&#xff0c;并用图形…