文章目录

  • 前言
  • 一、三子棋游戏的玩法及规则
  • 二、设计图
    • 1.游戏菜单
    • 2.设计棋盘
    • 3.规定棋子
    • 4.实现玩家下棋
    • 5.实现电脑下棋
    • 6.对局状态
  • 三、游戏全部代码
  • 总结

前言

大家好,我是耶鲁,今天我先出一篇关于三子棋游戏的具体实现,希望能激发大家学习C的兴趣,使咱们不仅会玩游戏,还能知道玩的游戏是怎么实现的。知其然知其所以然!!废话不多说,下面我们就直接进入主题。


一、三子棋游戏的玩法及规则

三子棋是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。我相信大家小时候应该都玩过吧!

二、设计图

我们将实现三子棋游戏的程序分成下图所示的三个文件:

我们再将其细分,大概可设计为下图六大模块:

接下来我们将这几个模块一一实现,再将模块与模块之间相连接,即可实现三子棋游戏的实现。

小建议:我们写程序的时候,最好是写一部分测试一部分,特别是代码比较多的情况下,这样程序出现bug的话我们可以及时的发现,确保这一部分是正确的。如果等到最后再测试的话,出现问题,解决起来就比较麻烦。

1.游戏菜单

游戏菜单我们可以这样来设置:当玩家输入1时:开始游戏,当玩家输入0时:退出游戏,除此之外,如果玩家输入1 / 0之外的数字应该提醒玩家:输入错误,请重新输入。并且玩家可以多次进行游戏,如果玩一局不过瘾还可以再来一局。
经过上面的分析,我们大概可以知道程序要用到那些语句,我们可以使用switch语句来针对玩家所输入的数字进行相应的操作,使用循环语句使玩家可以按照自己的意愿选择是否多次进行游戏。

具体实现代码如下:

2.设计棋盘

下棋肯定是需要一个棋盘的(一般都是3×3形式的棋盘),这里的棋盘既然是三行三列的,这不跟我们学过的二维数组很像吗?所以我们可以尝试用字符型二维数组存储棋盘上的数据。
我们上面说到棋盘形式一般都是3×3,但是如果有人想改变棋盘的形式,我们还得在程序中一处处的修改数据,太过于复杂,所以我们在头文件中利用 #define 来定义 ROW3,COL 3 这两个符号,就可以将程序中使用到3的地方用ROW和COL进行替换,也可以对这两处进行修改,进而改变我们棋盘的样式。

如下图所示:

我们先将棋盘初始化为空格,再利用 ’ ‘,’|’,’—’ 这几个符号来刻画出棋盘,大概的效果图如下:

代码实现如下:
图代码运行结果图如下:

如果我们想将棋盘改为10 × 10的样式,但是我们打印出来的棋盘为什么是10 × 3的样式呢?这是因为我们程序中输出数据的那一行已经写“死”了,它的列数已经固定下来了。所以就会出现如下结果:

通过观察我们可以把 %c | 看成一组,最后一列我们只打印 %c 不打印 | ,既然我们最后一列不打印 | ,所以我们要将 %c 和 | 分开打印。

代码实现如下:

代码运行结果如下,经过我们的修改,版本2的代码的实现就非常的灵活了。

3.规定棋子

棋子可以根据大家个人的喜好来设置,我这里规定玩家的棋子是’*’, 电脑的棋子是’#’。

4.实现玩家下棋

玩家和电脑每走一步棋之后,棋盘都要进行记录。所以再设置一个打印棋盘的函数,不论玩家还是电脑下棋之后我们都会调用打印棋盘的函数,观察对局情况。

5.实现电脑下棋

在实现电脑下棋之前我们先简单介绍一下rand函数:它是C语言中用来产生一个随机数的函数,rand函数界限:<stdlib.h>头文件中有宏 #define。RAND_MAX 0x7fff,rand产生一个0-0x7fff之间的的随机数,也就是最大是32767的一个数字。rand函数确实会帮我们生成一个随机数,但是生成随机数的方法有问题,看下图:这是我从rand介绍文档里面截取的一段话。这句话的大概意思是:调用rand函数之前我得先调用srand函数,我们要用srand来设置随机数的生成器。

srand函数原型:

srand的参数应该是一个无符号整型并且是随时变化的,什么数字是随时在发生变化的?当然是时间啦!时间每分每秒都在发生变化。所以我们可以把时间传给srand这个函数。这里又得引入一个概念叫时间戳,大家如果感兴趣可以自行了解一下哈,我简单说明一下,时间戳就是目前的时间和计算机的起始时间的差值(秒)。我们想要获得时间戳就得利用C语言库函数time,time函数调用要给它传一个NULL,time_t是由typedef定义的整型值且函数头文件为<time.h>。


上述实现如下:

经过上面的一系列铺垫,电脑就可以得到一个随机数,再将随机数的数值通过取模运算控制在合法范围内即可。

6.对局状态

游戏的对局可分为四种状态
玩家赢 —’*'
电脑赢 — '#'
平均 — 'Q’
继续 ----'C’
根据返回相应的符号可知对局当前对应的状态。
分析:先设置一个判断输赢的函数,那一方三个棋子先连成一线的一方为胜方,横向、竖向、斜向均可,然后在判断是否平局,如果棋盘没有空格时就说明棋盘已经满了,此时还没有分出胜负的话,就说明此局是平局,否则就继续游戏。

代码实现如下:

三、游戏全部代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void menu()
{printf("************************\n");printf("*****   1. play   ******\n");printf("*****   0. exit   ******\n");printf("************************\n");
}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");}
}void test()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);           //玩家可能输入1 / 0 / 其它数switch (input)                //运用switch语句可以根据玩家输入的数字,执行相应的语句{case 1:                      //输入1,进入game函数game();break; case 0:                      //输入1,进入退出游戏printf("退出游戏\n");break;default:                     //输入其它数字printf("输入错误,请重新输入\n");break;}} while (input);           //输入的input为0,条件为假,跳出循环。输入的input不为0,条件为真,继续进入do...while循环
}int main()
{test();return 0;
}

game.h

#pragma once#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 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);

game.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"  //包含头文件,避免重复定义//初始化棋盘的具体实现
void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++)  //利用for循环设置出三行三列的形式{for (j = 0; j < col; j++) {board[i][j] = ' ';   //棋盘先初始化为空格}}
}//版本1
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{//  int i = 0;
//  int j = 0;
//  for (i = 0; i < row; i++)
//  {//      //数据
//      printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //列数已经固定
//
//      //分割行
//      if(i<row-1)
//          printf("---|---|---\n");
//  }
//}//版本2
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");}
}//玩家下棋
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] == ' ')      //判断输入坐标处是否有棋子,从玩家的角度去考虑数组的行和列和我们习惯上的行和列有所差别,数组是从0开始,而我们习惯从1开始{board[x - 1][y - 1] = '*';break;         //玩家下完之后,跳出循环,等待电脑下棋}else{printf("该坐标被占用,请重新输入!\n");}}else{printf("坐标非法,请重输入!\n");}}
}//电脑下棋
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   //rand函数可以产生随机数且使随机数在合法坐标范围内y = rand() % COL;//0~2if (board[x][y] == ' ')  //判断输入坐标处是否有棋子{board[x][y] = '#';break;}}
}//判断棋盘是否填满
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;
}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';
}

总结

好了,三子棋游戏具体的实现过程就介绍至此了,我坚信慢工出细活,所以文章更新得到较为缓慢,希望大家多多支持!我也会尽我最大的努力为大家讲解清楚每一处知识,但精力有限,文章不免有瑕疵之处,如果大家有什么问题或者建议的话,可以在评论区讨论指出,谢谢! ψ(*`ー´)ψ

三子棋游戏的具体实现相关推荐

  1. 用C语言实现三子棋游戏(附上思路+项目展示+源代码)

    文章目录 前言 一.三子棋游戏整体实现思路 二.实现步骤 分模板实现 (以及具体应用实列) 1.test.c 源文件讲解: 2. game.c 源文件讲解: 3.game.h 源文件讲解 三 game ...

  2. c语言程序设计中三子棋游戏,C语言实现简易版三子棋游戏

    本文实例为大家共享了C语言实现三子棋游戏的详细代码,供大家参考,详细内容如下 什么是多文件? 多数大型的工程的头文件和源文件非常多,我们也不可能把所有的代码都写在同一个文件里,这样也不方便代码的阅读与 ...

  3. c语言程序下三子棋,C语言实现三子棋游戏(初级版)

    本文实例为大家分享了C语言实现三子棋游戏的具体代码,供大家参考,具体内容如下 game.h #include #include #include #define ROW 3 #define COL 3 ...

  4. 猜数游戏控制猜测次数c语言,C语言小游戏之猜数字,三子棋游戏

    #define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void menu() { printf("************ ...

  5. 使用c语言实现三子棋游戏

    下面简介如何使用c语言的基础语法实现三子游戏的底层逻辑: 首先是菜单模块 使用switch语句进入游戏模块 前置交互完成,开始进入游戏函数. 第一部分棋盘创建,使用二维数组实现. a.初始化棋盘 为什 ...

  6. 三子棋游戏(呆呆详解版)

    文章目录 一.问题 二.游戏基本流程 三.代码具体实现步骤 1.菜单界面 2.创建棋盘 3.初始化棋盘 4.打印棋盘 5.玩家下棋 6.电脑下棋 7.判断哪一方获胜 四.完整代码 五.代码运行演示 六 ...

  7. 关于三子棋游戏的简易实现与N子棋胜利判断方法

    关于三子棋游戏的简易实现与N子棋胜利判断方法 要实现三子棋游戏,主要需要实现以下几个要求:> 需要一个棋盘,既然需要一个棋盘,棋盘是在一个平面上的,所以我们需要创建一个二维数组 棋盘的打印 玩家 ...

  8. C语言实现三子棋游戏(规范化)

    `在复习了数组之后,对有些经典的数组题进行了,其中一道就是三子棋游戏这一功能的实现.下面附上我的个人理解和代码,希望各位大佬不吝指教. 首先有一个万能游戏模板,在c语言中有好多实现游戏的代码,我总结了 ...

  9. c语言编程实现简单三子棋游戏

    分别创建test.c   game.c 两个源文件,以及game.h头文件   这里的三子棋游戏是指棋盘为3*3,玩家与电脑之间的对决,先将各自的棋下为一排(横/竖/斜)者获胜,电脑所    下位置是 ...

  10. 简易的三子棋游戏(C语言)

    目录: 1.游戏介绍 2.游戏效果 3.源代码 (1)头文件命名为为game.h (2)游戏文件命名为game.c (3)测试文件命名为test.c 1.游戏介绍 三子棋是一种民间传统游戏,又叫九宫棋 ...

最新文章

  1. mysql存储的判断if_if在数据库mysql存储中判断
  2. 利用 Laravel 花 2 小时撸一个 RSS 生成器
  3. skywalking环境搭建
  4. matlab中blur函数_游戏中的PostProcessing(后处理)
  5. Stream Part.7
  6. 经典10046剖析案例-2
  7. Git commit/pull/push的操作步骤
  8. 织梦dede所有标签调用方法大全
  9. 如何想要在开机启动登陆时,用户名也不输入
  10. Android输入事件InputReader和InputDispatcher分析
  11. springboot 和springMVC interceptor使用
  12. CS61A自学者学习指南
  13. EXCEL插入超链接——无法打开指定文件
  14. NSR | 国科大王艳芬组中国草地多维资源梯度上的单峰生产力与生物多样性关系...
  15. 微信小程序加入购物车动画
  16. Docker 配置国内镜像加速器,加速下载速度
  17. [生存志] 第51节 子产相郑铸刑书
  18. RT-Thread源码-__rt_ffs函数剖析
  19. 10.24程序员节疑问:沈从文的编程功底应该很厉害吧?
  20. Google Pay 谷歌支付(gateway = stripe)

热门文章

  1. java开发pc端和移动端的区别,移动端和PC端的区别
  2. 用计算机制作一张家庭年收支表,简洁明了的家庭收支记账表格
  3. 开发实现物理加速度移动_2019年最受物理老师欢迎的7款软件发布!不要错过!...
  4. Python爬虫搜索全网音乐并下载
  5. OSEK 网络管理之认识NM报文
  6. TestStand自定义报表生成-添加列
  7. 操作系统_第三章_处理器管理_多道程序设计
  8. Node.js文字与图片合成
  9. 物联网中无线通信技术
  10. r语言clind函数_19 函数进阶 | R语言教程