【C语言】C语言实现扫雷&&三子棋
时间:2024-04-02 20:00:36 来源:网络cs 作者:往北 栏目:监控软件 阅读:
主页:醋溜马桶圈-CSDN博客
专栏:C语言_醋溜马桶圈的博客-CSDN博客
gitee:mnxcc (mnxcc) - Gitee.com
目录
1.C语言实现三子棋
1.1 整体思路
1.2 游戏菜单的创建
1.3 游戏主体的实现
1.3.1 棋盘的初始化
1.3.2 打印棋盘
1.3.3 玩家下棋
1.3.4 电脑下棋
1.3.5 判断输赢
1.3.6 棋盘满
1.3.7 game()函数
1.4 整体代码
1.4.1 test.c
1.4.2 game.c
1.4.3 game.h
2.C语言实现扫雷游戏
2.1 整体思路
2.2 游戏主体的实现
2.2.1 打印菜单
2.2.2 玩家选择
2.2.3 扫雷的逻辑
2.2.3.1 布置雷的逻辑
2.2.3.2 排雷的第一种情况
2.2.3.3 排雷的第二种情况
2.2.4 棋盘的初始化
2.2.5 打印棋盘
2.2.5.1 代码
game.c
test.c
2.2.5.2 打印效果
2.2.6 布置雷
2.2.7 排雷
2.2.8 game()函数
2.3 整体代码
2.3.1 game.h
2.3.2 game.c
2.3.3 test.c
1.C语言实现三子棋
1.1 整体思路
我们需要有三个文件:
test.c —— 测试游戏game.h —— 游戏函数的声明game.c —— 游戏函数的实现
1.2 游戏菜单的创建
进入游戏时,首先出现的是菜单界面
我们定义一个“菜单函数”menu( )来实现这一功能
游戏菜单应该实现这几个功能:
游戏的进入游戏的退出非法输入的返回提示和说明接下来是我们实现这一功能的代码块
#include<stdio.h>#include"game.h"void menu() {printf("********************\n");printf("****** 1.play ******\n");printf("****** 0.exit ******\n");printf("********************\n");}int main() {int input = 0;do{menu();printf("请输入:>");scanf("%d", &input);switch (input){case 1:printf("三子棋\n");break;case 0:printf("退出游戏\n");break;default:printf("选择错误\n");break;}} while (input); return 0;}
这是该模块菜单函数的运行截图
1.3 游戏主体的实现
1.3.1 棋盘的初始化
游戏刚开始时,我们需要对棋盘进行初始化操作,对棋盘进行清空,以保证后续游戏的正常进行。我们定义一个InitBoard()函数来进行棋盘的初始化操作
代码如下
void InitBoard(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++){board[i][j] = ' ';}}}
1.3.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");}}
1.3.3 玩家下棋
打印好棋盘,就要进行我们的下棋阶段
我们规定玩家先下棋
void PlayerMove(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("玩家下棋\n");while (1){printf("请输入下棋的坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= ROW && y >= 1 && y <= COL){if (board[x - 1][y - 1] != ' '){printf("该位置已被占用,请输入其他坐标\n");}else{board[x - 1][y - 1] = '*';break;}}else{printf("输入非法,请重新输入\n");}}}
玩家输入对应的合法坐标下棋,接下来就是电脑下棋
暂且不设计电脑对抗玩家的算法,就让电脑产生一个棋盘内部的随机坐标
1.3.4 电脑下棋
void ComputerBoard(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("电脑下棋\n");while (1){x = rand() % ROW;y = rand() % COL;if (board[x][y] == ' '){board[x][y] = '#';break;}}}
给电脑设计了随机数rand()函数,但这个函数需要srand()设置,所以我们在main()函数开头加上srand()
接下来写一个判断输赢的函数来进行判断
1.3.5 判断输赢
三子棋游戏出现的结果有以下四种,我们用各自对应的符号进行判断
//玩家赢 - *
//电脑赢 - #
//平局 - Q
//继续游戏 - C
char IsWin(char board[ROW][COL], int row, int col){int i = 0;int j = 0;for (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 (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[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 (IsFull(board, row, col))return 'Q';return 'C';}
1.3.6 棋盘满
接下来我们还需要有一个函数来判断棋盘是否已满
static int IsFull(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;}
我们用static修饰这个函数,使当前函数只能在本文件内部使用
1.3.7 game()函数
上面我们铺垫了所有三子棋所要用到的函数,这些函数在game()函数中使用
void game(){char ret = 0;char board[ROW][COL] = {0};InitBoard(board,ROW,COL);DisplayBoard(board,ROW,COL);while (1){//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C')break;//电脑下棋ComputerBoard(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C')break;}if (ret == '*'){printf("玩家赢\n");}if (ret == '#'){printf("电脑赢\n");}if (ret == 'Q'){printf("平局\n");}}
1.4 整体代码
这些代码我们在实际使用时是需要封装在不同的文件内的
所以我们定义了test.c,game.c,game.h文件封装我们所有用到的函数以及头文件
1.4.1 test.c
#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#include"game.h"void menu() {printf("********************\n");printf("****** 1.play ******\n");printf("****** 0.exit ******\n");printf("********************\n");}void game(){char ret = 0;char board[ROW][COL] = { 0 };InitBoard(board, ROW, COL);DisplayBoard(board, ROW, COL);while (1){//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C')break;//电脑下棋ComputerBoard(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C')break;}if (ret == '*'){printf("玩家赢\n");}if (ret == '#'){printf("电脑赢\n");}if (ret == 'Q'){printf("平局\n");}}int main() {int input = 0;do{menu();printf("请输入:>");scanf("%d", &input);switch (input){case 1:printf("三子棋\n");game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误\n");break;}} while (input);return 0;}
1.4.2 game.c
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>#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 (j = 0; j < col; j++){board[i][j] = ' ';}}}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 PlayerMove(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("玩家下棋\n");while (1){printf("请输入下棋的坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= ROW && y >= 1 && y <= COL){if (board[x - 1][y - 1] != ' '){printf("该位置已被占用,请输入其他坐标\n");}else{board[x - 1][y - 1] = '*';break;}}else{printf("输入非法,请重新输入\n");}}}void ComputerBoard(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("电脑下棋\n");while (1){x = rand() % ROW;y = rand() % COL;if (board[x][y] == ' '){board[x][y] = '#';break;}}}static int IsFull(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 IsWin(char board[ROW][COL], int row, int col){int i = 0;int j = 0;for (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 (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[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 (IsFull(board, row, col))return 'Q';return 'C';}
1.4.3 game.h
#pragma once#define ROW 3#define COL 3#include<stdio.h>#include<time.h>#include<stdlib.h>//初始化棋盘void InitBoard(char board[ROW][COL], int row, int col);//打印棋盘void DisplayBoard(char board[ROW][COL], int row, int col);//玩家下棋void PlayerMove(char board[ROW][COL], int row, int col);//电脑下棋void ComputerBoard(char board[ROW][COL], int row, int col);//判断输赢//有四种可能//玩家赢 - *//电脑赢 - #//平局 - Q//继续游戏 - Cchar IsWin(char board[ROW][COL], int row, int col);
我们把所有的函数声明和头文件以及宏定义都放在我们自己创建的game.h文件中
我们在其他文件中使用时只需要包含该文件用双引号引住即可
2.C语言实现扫雷游戏
2.1 整体思路
跟三子棋一样,我们首先创建三个文件:game.h , game.c , test.c
1.用define定义常量,定义数组的行和列,这样改变数组行列不需要整个修改代码,只需要改变define后面定义常量的值;2.需要一个菜单来供我们选择进入游戏还是退出游戏,menu函数;3.玩游戏肯定不止玩一局,所以需要设置循环do...while;4.需要俩个数组,一个用来设置雷(mine),存放雷的信息;一个用来让玩家排查雷(show),存放玩家输入的坐标信息;5.需要初始化俩个数组,我们把要埋雷的数组初始化为’0‘,要排雷的数组初始化为’*‘;6.需要打印棋盘让玩家来排雷;7.需要设置雷和排雷函数;
2.2 游戏主体的实现
2.2.1 打印菜单
定义一个menu()函数来打印菜单
void menu() {printf("******************\n");printf("***** 1.play *****\n");printf("***** 0.exit *****\n");printf("******************\n");}
2.2.2 玩家选择
我们在main()中采取do-while循环来实现重复游戏,用switch()来获取玩家的选择
int main() {int input = 0;do {menu();printf("请选择>");scanf("%d", &input);switch (input) {case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;}
目前我们的实现效果是这样的
2.2.3 扫雷的逻辑
2.2.3.1 布置雷的逻辑
假设我们实现一个9*9的棋盘,上面布置十个雷
这样我们就需要一个9*9的数组来存放雷
假设这是我们的棋盘
最开始每个位置都放0;0表示非雷
当我们布置雷的时候,把雷放成1
2.2.3.2 排雷的第一种情况
假设我们在排这个绿色坐标的时候,它不是雷,这时候我们需要统计它周围红圈中8个坐标的雷的个数;像上面这种情况,我们需要显示1;但是这个1会与我们表示雷的1冲突,为了解决这个问题,我们再单独给他一个数组,全部放成 ‘ * ’ ;
这个时候,我们在 ‘ * ’ 棋盘中,对应的位置显示‘1’表示这个坐标周围的八个坐标里有一个雷;我们给玩家展示的时候,展示第2个数组
第一个棋盘存雷和非雷的信息第二个棋盘存玩家排查出来的雷的信息
2.2.3.3 排雷的第二种情况
假设我们要排查边缘的这个坐标,这个是超出了我们9*9的数组范围
这个时候为了防止越界,我们再把这个数组扩充,即在设置存雷的数组的时候,范围设置成11*11
像这样
这个时候,就不存在越界行为了
为了便于计算,我们的展示棋盘同样扩大到11*11(严丝合缝);
2.2.4 棋盘的初始化
我们定一个InitBoard()函数来初始化棋盘
定义两个11*11的数组
这个数组用来放布置好的雷的信息(11*11)
这个数组用来放排查出的雷的信息(11*11)
为了保证两个数组严格的统一,包括元素类型也要统一,我们定义为char数组
game.h
#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2//初始化棋盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
game.c
//初始化棋盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char set){int i = 0, j = 0;for (i = 0; i < rows; i++) {for (j = 0; j < cols; j++) {board [i][j] = set;}}}
test.c
void game() {char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');}
2.2.5 打印棋盘
我们定义一个DisplayBoard()函数来打印棋盘
在打印的时候,我们可以打印出坐标
2.2.5.1 代码
game.c
//打印棋盘void DisplayBoard(char board[ROWS][COLS], int row, int col) {int i = 0, j = 0;for (i = 0; i <= col; i++) {printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++) {printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}}
test.c
void game() {char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);}
2.2.5.2 打印效果
2.2.6 布置雷
我们定义一个setMine()函数来布置雷
假设我要布置十个雷
随机布置用1表示雷
这里我们又要用到我们的随机数函数rand(),使用rand函数必然需要在main()函数中调用srand();
//布置雷void setMine(char mine[ROWS][COLS], int row, int col) {int count = EASY_COUNT;while (count) {int x = rand() % row + 1;int y = rand() % col + 1;if (mine[x][y] == '0') {mine[x][y] = '1';count--;}}}
2.2.7 排雷
排查雷的逻辑是:
如果这个位置不是雷,就计算这个位置周围八个坐标有几个雷,并显示雷的个数如果这个位置是雷,就炸死了,游戏结束如果把不是雷的位置都找出来了,那么游戏也结束,玩家胜利
在扫雷的过程中,我们还需要计算周围雷的个数
定义一个GetMineCount()函数来统计周围雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y) {return(mine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] - 8 * '0');}
定义一个FindMine()函数来排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {int x = 0;int y = 0;int win = 0;while (win < row * col - EASY_COUNT) {printf("请输入要排查雷的坐标:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) {if (show[x][y] == '*') {if (mine[x][y] == '1') {printf("很遗憾,你被炸死了\n");DisplayBoard(show, ROW, COL);break;}else {int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else {printf("该坐标已经被排查了\n");}}else {printf("非法坐标,请重新输入\n");}}if (win == row * col - EASY_COUNT) {printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}
2.2.8 game()函数
void game() {char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);//布置雷setMine(mine, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);}
2.3 整体代码
2.3.1 game.h
#define _CRT_SECURE_NO_WARNINGS 1#pragma once#include<stdio.h>#include<time.h>#include<stdlib.h>#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2#define EASY_COUNT 10//十个雷//初始化棋盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘void DisplayBoard(char board[ROWS][COLS], int row, int col);//布雷void setMine(char mine[ROWS][COLS], int row, int col);//扫雷void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);//计算扫出来的雷个数int GetMineCount(char mine[ROWS][COLS], int x, int y);
2.3.2 game.c
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"//初始化棋盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char set){int i = 0, j = 0;for (i = 0; i < rows; i++) {for (j = 0; j < cols; j++) {board [i][j] = set;}}}//打印棋盘void DisplayBoard(char board[ROWS][COLS], int row, int col) {int i = 0, j = 0;printf("--------扫雷--------\n");for (i = 0; i <= col; i++) {printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++) {printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("--------扫雷--------\n");}//布置雷void setMine(char mine[ROWS][COLS], int row, int col) {int count = EASY_COUNT;while (count) {int x = rand() % row + 1;int y = rand() % col + 1;if (mine[x][y] == '0') {mine[x][y] = '1';count--;}}}//扫雷int GetMineCount(char mine[ROWS][COLS], int x, int y) {return(mine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] - 8 * '0');}void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {int x = 0;int y = 0;int win = 0;while (win < row * col - EASY_COUNT) {printf("请输入要排查雷的坐标:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) {if (show[x][y] == '*') {if (mine[x][y] == '1') {printf("很遗憾,你被炸死了\n");DisplayBoard(show, ROW, COL);break;}else {int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else {printf("该坐标已经被排查了\n");}}else {printf("非法坐标,请重新输入\n");}}if (win == row * col - EASY_COUNT) {printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}
2.3.3 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 mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);//布置雷setMine(mine, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);}int main() {srand((unsigned int)time(NULL));int input = 0;do {menu();printf("请选择>");scanf("%d", &input);switch (input) {case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;}
本文链接:https://www.kjpai.cn/news/2024-04-02/152937.html,文章来源:网络cs,作者:往北,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!
上一篇:【Java初阶(七)】接口
下一篇:返回列表