C语言-三子棋游戏的实现
C语言-三子棋游戏的实现
目录
- C语言-三子棋游戏的实现
- 游戏背景介绍
- 游戏实现思路
- test模块
- menu模块
- **game模块**
- init_board(初始化棋盘)
- print_board(打印棋盘)
- player_move(玩家下棋)
- computer_move(电脑下棋)
- is_win(判断输赢)
- 游戏全部代码
游戏背景介绍
《三子棋》是一款古老的民间传统游戏,又被称为一条龙、九宫棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子连成一条线的一方则视为胜利者。
游戏实现思路
我们计划创建两个源文件test.c和game.c,一个头文件game.h,来完成对这个游戏的实现。
其中,test.c文件主要用于整体框架的实现,game.c文件主要用来实现游戏中的各个步骤。
游戏的整体模块如下:
下面我们分模块进行实现。
test模块
(上图为从函数的角度的思考)
模块的代码如下:
其中,
srand((unsigned int)time(NULL))
,主要用来生成随机时间的起点。
void test()
{srand((unsigned int)time(NULL));int input = 0;do {menu();printf("请选择1(开始游戏)或0(退出游戏):>\n");//只能选择一个整数输入,其他类型的输入,均是非法操作scanf("%d",&input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("退出游戏\n");break;default :printf("输入错误,请重新输入\n");break;}} while (input);//可以多次玩耍
}
menu模块
模块的代码如下:
void menu()
{printf("********************\n");printf("*** 三子棋游戏 ***\n");printf("**** 1.play ****\n");printf("**** 2.exit ****\n");printf("********************\n");
}
game模块
模块的代码如下:
void game()
{//棋盘为3*3大小,即3*3的数组//为了可以控制棋盘的大小,我们定义一个标识符常量char board[ROW][COL];char ret = 0;//初始化棋盘init_board(board, ROW, COL);//打印棋盘print_board(board, ROW, COL);while (1){//玩家下棋player_move(board, ROW, COL);//打印当前棋盘print_board(board, ROW, COL);//判断输赢ret=is_win(board, ROW, COL);if (ret != 'C'){break;}//电脑下棋computer_move(board, ROW, COL);//打印当前棋盘print_board(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");}}
我们通过is_win函数所带回的返回值来判断是玩家赢,电脑赢,还是说结果为平局。
game模块部分是该游戏实现的核心,下面我们从函数角度来完成各步骤的实现
init_board(初始化棋盘)
初始化棋盘,对于33的棋盘来说,就是要将一个33的数组中的所有元素初始化为空格。
函数实现如下:
void init_board(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] = ' ';}}
}
print_board(打印棋盘)
我们计划打印出如上图所示的棋盘形式,采用化整为零的思路,我们将其分为一行行和一列列,
1 首先打印出全部的元素后,它是没有任何分割线的。
2 先考虑第一行,为了达到图示的目的,我们知道一个下划线占一个位置,因此,在打印元素的同时,要打印出空格和竖线与之对应;再考虑第二行,有三个下划线和一个竖线组成一组,可以打印出来
3 全部打印出来后,发现最后行和最后列的部分多余了出来,为此,我们需要对其调整。
4 我们将第一行和第二行的这种组合为一个整体,那么他们的最后一次打印,都不需要下划线,我们以j(j < col - 1)在每行的最后一次打印时,进行区分。这样右侧的尾部就解决了。
5 在4步骤的基础上,对于下侧部分的尾部,主要是针对第二行的这种元素。我们以外侧for循环的行数i(i < row - 1),进行区分。这样下侧的尾部就解决了。
代码如下:
void print_board(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if(j<col-1){printf(" %c |", board[i][j]);}else{printf(" %c ", board[i][j]);}}printf("\n");if(i<row-1){for (int j = 0; j < col; j++){if (j < col - 1){printf("---|");}else{printf("---");}}}printf("\n");}
}
player_move(玩家下棋)
对于下棋,就是要用在特定的位置(33的棋盘,共9个位置),用特定的符号(我们这里采用‘’和‘#’)将空格给替换掉。
玩家下棋,玩家下棋需要考虑到的情况:
1.判断玩家输入坐标的合法性,以三子棋为例,站在玩家的角度,要求坐标值位于1-3之间
2.输入的坐标是否被占用,如果该值不为空,则表示被占用
代码如下:
void player_move(char board[ROW][COL], int row, int col)
{printf("轮到玩家下棋了\n");while (1) {printf("请输入棋子的坐标\n");int x = 0;int y = 0;scanf("%d %d", &x, &y);if ((1 <= x && x <= row) && (1 <= y && y <= row)){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] ='*';break;}else{printf("该坐标点已被占用,请重新输入\n");}}else{printf("该坐标点超出棋盘范围,请重新输入\n");}}}
computer_move(电脑下棋)
电脑下棋与玩家下棋类似,只不过对于坐标的合法性,这里采用的是生成随机数来控制坐标的范围。且电脑下棋坐标位置随机,不具有智能性(后续有时间的话,我会回来优化这个地方)。我们也可以从两个方面考虑这里。
1 利用随机生成函数控制,随机数的生成范围为0-2
2 输入的坐标是否被占用,如果该值不为空,则表示被占用
void computer_move(char board[ROW][COL], int row, int col)
{while (1){printf("轮到电脑下棋了\n");int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}else{printf("该坐标点已被占用,请重新输入\n");}}
}
is_win(判断输赢)
判断游戏输赢的情况:电脑赢,玩家赢,平局,继续。根据不同的情况我们返回不同的符号。
玩家赢:返回*
电脑赢:返回#
平局:返回Q
游戏继续:返回C
我们可以将玩家赢和电脑赢理解为一种情况:即有一方赢。
于是,有3种不同的情况。
1 一方赢的情况:三行或三列,或两条对角线上为同一个符号,且不为空格
for (int i = 0; i < row; i++)//判断行{if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}for (int i = 0; i < col; i++)//判断列{if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')//判断主对角线{return board[1][1];}if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')//判断副对角线{return board[1][1];}
2 平局的情况:不为以上的情况,且棋盘下满(棋盘是否下满,遍历数组看是否有空格)
for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}
3 其他情况,为游戏继续
该is_win的全部代码如下:
int is_full_board(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;
}
char is_win(char board[ROW][COL], int row, int col)
{//先写死程序,后续优化改进for (int i = 0; i < row; i++)//判断行{if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}for (int i = 0; i < col; i++)//判断列{if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')//判断主对角线{return board[1][1];}if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')//判断副对角线{return board[1][1];}if (is_full_board(board, ROW, COL)){return 'Q';}return 'C';
}
至此,所有模块功能均已实现。
游戏全部代码
test.c
#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"
//游戏逻辑
//test.c
//
//game.c
//game.h
void game()
{//棋盘为3*3大小,即3*3的数组//为了可以控制棋盘的大小,我们定义一个标识符常量char board[ROW][COL];char ret = 0;//初始化棋盘init_board(board, ROW, COL);//打印棋盘print_board(board, ROW, COL);while (1){//玩家下棋player_move(board, ROW, COL);//打印当前棋盘print_board(board, ROW, COL);//判断输赢ret=is_win(board, ROW, COL);if (ret != 'C'){break;}//电脑下棋computer_move(board, ROW, COL);//打印当前棋盘print_board(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");}}
//判断游戏输赢的情况:电脑赢?玩家赢?平局?继续?
//玩家赢:返回*
//电脑赢:返回#
//平局:返回Q
//游戏继续:返回C
void menu()
{printf("********************\n");printf("*** 三子棋游戏 ***\n");printf("**** 1.play ****\n");printf("**** 2.exit ****\n");printf("********************\n");
}
void test()
{srand((unsigned int)time(NULL));int input = 0;do {menu();printf("请选择1(开始游戏)或0(退出游戏):>\n");//只能选择一个整数输入,其他类型的输入,均是非法操作scanf("%d",&input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("退出游戏\n");break;default :printf("输入错误,请重新输入\n");break;}} while (input);//可以多次玩耍
}
int main()
{test();return 0;
}
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>#define ROW 3
#define COL 3//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);//打印棋盘
void print_board(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);char is_win(char board[ROW][COL], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"//初始化棋盘,也就是将数组各元素初始化为空格
void init_board(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] = ' ';}}
}//打印棋盘,也即是打印数组
//分割行和分割列的设计思路:
//1 首先打印出全部的元素
//2 先考虑第一行,为了达到图示的目的,我们知道一个下划线占一个位置,因此,在打印元素的
//同时,要打印出空格和竖线与之对应;
//再考虑第二行,有三个下划线和一个竖线组成一组元素,可以打印出来
//3 全部打印出来后,发现最后行和最后列的部分多余了出来,我们在4和5步骤对其调整/* 4 我们将第一行和第二行的这种组合为一个整体,那么他们的最后一次打印,都不需要下划线,我们以j(j < col - 1)在每行的最后一次打印时,进行区分。这样右侧的尾部就解决了。5 在4步骤的基础上,对于下侧部分的尾部,主要是针对第二行的这种元素。我们以外侧for循环的行数i(i < row - 1),进行区分。这样下侧的尾部就解决了*/
void print_board(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if(j<col-1){printf(" %c |", board[i][j]);}else{printf(" %c ", board[i][j]);}}printf("\n");if(i<row-1){for (int j = 0; j < col; j++){if (j < col - 1){printf("---|");}else{printf("---");}}}printf("\n");}
}//玩家下棋,玩家下棋需要考虑到的情况:
//1.判断玩家输入坐标的合法性,以三子棋为例,站在玩家的角度,要求坐标值位于1-3之间
//2.输入的坐标是否被占用,如果该值不为空,则表示被占用
void player_move(char board[ROW][COL], int row, int col)
{printf("轮到玩家下棋了\n");while (1) {printf("请输入棋子的坐标\n");int x = 0;int y = 0;scanf("%d %d", &x, &y);if ((1 <= x && x <= row) && (1 <= y && y <= row)){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] ='*';break;}else{printf("该坐标点已被占用,请重新输入\n");}}else{printf("该坐标点超出棋盘范围,请重新输入\n");}}}//电脑下棋
//电脑随机生成坐标,需要考虑到的情况同玩家类似
//1 利用随机生成函数控制,随机数的生成范围为0-2
//2 输入的坐标是否被占用,如果该值不为空,则表示被占用
void computer_move(char board[ROW][COL], int row, int col)
{while (1){printf("轮到电脑下棋了\n");int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}else{printf("该坐标点已被占用,请重新输入\n");}}
}//判断游戏是否输赢
//有4种情况:其中一方赢;平局(棋盘下满,且没有出现赢的一方);棋盘未下满
//其中一方赢的情况:三行或三列,或两条对角线上为同一个符号,且不为空格
//平局的情况:不为以上的情况,且棋盘下满(棋盘是否下满,遍历数组看是否有空格)
//其他情况,为游戏继续int is_full_board(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;
}
char is_win(char board[ROW][COL], int row, int col)
{//先写死程序,后续优化改进for (int i = 0; i < row; i++)//判断行{if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}for (int i = 0; i < col; i++)//判断列{if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')//判断主对角线{return board[1][1];}if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')//判断副对角线{return board[1][1];}if (is_full_board(board, ROW, COL)){return 'Q';}return 'C';
}
C语言-三子棋游戏的实现相关推荐
- C语言三子棋游戏进阶版详解(包括多子棋)
目录 一,总体思路介绍 二,具体思路的实现 1.初始化游戏界面 2.初始化棋盘 3.打印棋盘 4.玩家移动 5.电脑移动 6.判断输赢 三,源码展示 game.h game.c test.c 一,总体 ...
- C语言三子棋游戏的编程实现
程序界面实现如图所示的人与电脑互动的三子棋游戏 文件模块 test.c 测试三子棋游戏 game.h 游戏的函数声明(头文件) game.c 游戏函数的实现 代码模块 初始化棋盘 (每个位置初始为空格 ...
- C语言三子棋游戏实现(基础版)
欢迎来到 Claffic 的博客
- 用C语言实现三子棋游戏(附上思路+项目展示+源代码)
文章目录 前言 一.三子棋游戏整体实现思路 二.实现步骤 分模板实现 (以及具体应用实列) 1.test.c 源文件讲解: 2. game.c 源文件讲解: 3.game.h 源文件讲解 三 game ...
- c语言程序设计中三子棋游戏,C语言实现简易版三子棋游戏
本文实例为大家共享了C语言实现三子棋游戏的详细代码,供大家参考,详细内容如下 什么是多文件? 多数大型的工程的头文件和源文件非常多,我们也不可能把所有的代码都写在同一个文件里,这样也不方便代码的阅读与 ...
- c语言程序下三子棋,C语言实现三子棋游戏(初级版)
本文实例为大家分享了C语言实现三子棋游戏的具体代码,供大家参考,具体内容如下 game.h #include #include #include #define ROW 3 #define COL 3 ...
- 使用c语言实现三子棋游戏
下面简介如何使用c语言的基础语法实现三子游戏的底层逻辑: 首先是菜单模块 使用switch语句进入游戏模块 前置交互完成,开始进入游戏函数. 第一部分棋盘创建,使用二维数组实现. a.初始化棋盘 为什 ...
- C语言实现三子棋游戏(规范化)
`在复习了数组之后,对有些经典的数组题进行了,其中一道就是三子棋游戏这一功能的实现.下面附上我的个人理解和代码,希望各位大佬不吝指教. 首先有一个万能游戏模板,在c语言中有好多实现游戏的代码,我总结了 ...
- 如何用C语言来实现【三子棋游戏】
目录 一.前言 二.思维导图 三.思路分析 四.运行结果 五.算法细节 1.游戏相关的测试 2.游戏函数的声明 3.游戏函数的实现 (1)初始化棋盘的函数 (2)打印棋盘的函数 (3)玩家下棋的函数 ...
最新文章
- CSS控制字体在一行内显示不换行
- 中科院基因组所高远组诚聘生物信息学方向助理/副研及博士
- Eclipse中配置Tomcat虚拟路径
- 线性表应用之线性表算法设计六大经典案例
- 利用栈进行程序的括号匹配
- haproxy详细介绍
- P2634 [国家集训队]聪聪可可(树形dp)
- 前后端分离 与 不分离
- sed 、awk用法
- JDBC04 PreparedStatement
- 手把手玩转win8开发系列课程(13)
- Vbs脚本编程简明教程之六
- PS1应用之——修改linux终端命令行各字体颜色
- excel怎么设置密码?加密文件这么做!
- 威联通212-P 安装远程迅雷,docker安装远程迅雷
- 调试The Annotated Transformer
- SAS:单变量正态性检验
- oracle扩充表空间
- LattePanda入手笔记
- 【计算机视觉】Lecture 11:LoG和DoG滤波算子