1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > C语言实现扫雷小游戏(排雷时可展开)

C语言实现扫雷小游戏(排雷时可展开)

时间:2021-08-25 07:27:04

相关推荐

C语言实现扫雷小游戏(排雷时可展开)

游戏介绍

扫雷想必大家都听说过吧?我们今天写的小游戏就是扫雷,只不过我们只使用C语言写。我们能够做到的就是实现扫雷的基本逻辑,没有图形化界面。

源代码

这次游戏程序的写法和上一次的三子棋的模式很像,也是三个文件。

1.game.h(游戏头文件)

//头文件引用#include <stdio.h>#include <stdlib.h>#include <time.h>//常量声明#define ROW 9//地图大小#define COL 9//地图大小#define ROWS ROW+2#define COLS COL+2#define EAZY_COUNT 10//函数声明//打印菜单void menu();//游戏函数void game();//初始化地图void init(char board[ROWS][COLS], char set);//打印地图void display_board(char board[ROWS][COLS]);//埋雷void set_mine(char board[ROWS][COLS]);//排雷void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS]);//数雷int mine_count(char board[ROWS][COLS], int r, int c);//弹开void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);//判断游戏状态int is_win(char board[ROWS][COLS]);

2.test.c(游戏测试)

#include "game.h"int main(){srand((unsigned int)time(NULL));int input = 0;//打印菜单,实现选择功能do{menu();printf("请选择:\n");scanf("%d", &input);switch (input){case 1:/*printf("play!\n");*/game();break;case 0:printf("游戏结束!\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);system("pause");return 0;}

game.c(游戏实现)

#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 };init(mine, '0');init(show, '*');set_mine(mine);//display_board(mine);display_board(show);find_mine(show, mine);}void init(char board[ROWS][COLS], char set){for (int i = 0; i < ROWS; i++){for (int j = 0; j < COLS; j++){board[i][j] = set;}}}void display_board(char board[ROWS][COLS]){for (int j = 0; j <= COL; j++){printf("%d ", j);}printf("\n");for (int i = 1; i <= ROW; i++){printf("%d ", i);for (int j = 1; j <= COL; j++){printf("%c ", board[i][j]);}printf("\n");}printf("\n");}void set_mine(char board[ROWS][COLS]){int count = EAZY_COUNT;while (count){int r = rand() % ROW + 1;int c = rand() % COL + 1;if (board[r][c] == '0'){board[r][c] = '1';count--;}}void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS]);}void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS]){int r = 0, c = 0;while (1){printf("请输入排雷的坐标:\n");scanf("%d %d", &r, &c);if (r >= 1 && r <= ROW && c >= 1 && c <= COL){if (show[r][c] == '*'){if (mine[r][c] == '0'){//show[r][c] = mine_count(mine, r, c) + '0';ExpandBoard(mine, show, r, c);if (is_win(show)){break;}display_board(show);//display_board(mine);}else{printf("踩雷了!游戏结束!\n");display_board(mine);break;}}else{printf("此位置已经排查过了!\n");}}else{printf("坐标不合法,请重新输入!\n");}}if (is_win(show)){printf("扫雷成功!\n");display_board(mine);}}int mine_count(char board[ROWS][COLS], int r, int c){return (board[r + 1][c - 1] +board[r][c - 1] +board[r - 1][c - 1] +board[r + 1][c] +board[r - 1][c] +board[r + 1][c + 1] +board[r][c + 1] +board[r - 1][c + 1] - (8 * '0'));}void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int r, int c){int ret = mine_count(mine, r, c);if (ret == 0){show[r][c] = ' ';int i = 0;int j = 0;for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if ((r + i) > 0 && (c + i) > 0 && (r + i < ROWS) && (c + j < COLS) && show[r + i][c + j] == '*'){ExpandBoard(mine, show, r + i, c + j);}}}/*if (show[r - 1][c - 1] == '*' && r - 1 > 0 && r - 1 < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r - 1, c - 1, win);if (show[r - 1][c] == '*' && r - 1 > 0 && r - 1 < ROWS && c > 0 && c < COLS)ExpandBoard(mine, show, r - 1, c, win);if (show[r - 1][c + 1] == '*' && r - 1 > 0 && r - 1 < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r - 1, c + 1, win);if (show[r][c - 1] == '*' && r > 0 && r < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r, c - 1, win);if (show[r][c + 1] == '*' && r > 0 && r < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r, c + 1, win);if (show[r + 1][c - 1] == '*' && r + 1 > 0 && r + 1 < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r + 1, c - 1, win);if (show[r + 1][c] == '*' && r + 1 > 0 && r + 1 < ROWS && c > 0 && c < COLS)ExpandBoard(mine, show, r + 1, c, win);if (show[r + 1][c + 1] == '*' && r + 1 > 0 && r + 1 < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r + 1, c + 1, win);}*/}else{show[r][c] = ret + '0';}}int is_win(char board[ROWS][COLS]){int count = 0;for (int i = 1; i <= ROW; i++){for (int j = 1; j <= COL; j++){if (board[i][j] == '*'){count++;}}}if (count == EAZY_COUNT){return 1;}else{return 0;}}

详解

接下来是游戏实现的一些详细的解释,由于很多地方是和上一期的三子棋相似的,我挑一些主要的地方讲解。

1.地图的设计(为什么地图的大小是(9+2)*(9+2)?)

白色的是我们玩家看到的地图。我们之所以要将地图扩大一圈,是因为我们后面的数坐标周围一圈的雷时,可能会导致越界访问的问题,所以我们这样设计。这一点其实和我们上一期的三子棋的棋盘设计是一个原理。我们以最右下角的个子为例,我们数它周围的雷数,需要访问这些棕色的格子,所以如果数组不够的话,就会导致越界访问。

还有一点就是我们这次定义地图时,设计了两个棋盘,他们大小一样,但是作用不同,一个是用来存放雷的信息的mine数组,另一个是用来展示给玩家的游戏地图show数组

2.初始化与打印地图

需要注意的地方有两点,第一点是我们给数组存数据时是char类型,所以记得加上'',并且最好是给整个数组都初始化一下。第二点是打印数组时,为了方便玩家输入坐标,我们最好是打印一下行号和列号,具体实现方式请看源代码。

效果展示:

3.设置雷(随机数的使用)

设置雷主要知识点就是随机数的使用,我们需要生成1-9的随机数。所以对rand生成的随机数采取以下措施:

int r = rand() % ROW + 1;int c = rand() % COL + 1;

记得要设置随机数生成器哟。

srand((unsigned int)time(NULL));

采用循环的方式设置雷是为了保证能够设置多个并且有效的雷,没设置成功一个雷,就离出口更近一步。具体实现请看源代码。

4.寻找雷

玩家游玩的部分,主要逻辑如下:玩家输入坐标,如果坐标合法的话,判断该坐标是否已经排查过了,如果该坐标没有排查过,再判断是否为雷,如果不是雷,就显示该坐标周围雷的个数。

需要注意的地方就是数该坐标周围雷的个数这里,我们需要用到字符的加减法,如果你想要得到整型变量时,需要加减一个'0',如果需要将整型转换成字符时,也是同理。

5.将不是雷的地方展开(递归实现)

逻辑:数该坐标周围的雷数,如果为0.则将该位置变成' ',再依次对该坐标周围的八个格子采用同样的方式,递归出口:坐标周围的雷数不是0。

有两种代码,实现原理一样,但是递归次数不一样,代码量也不一样:

1.

void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int r, int c){int ret = mine_count(mine, r, c);if (ret == 0){show[r][c] = ' ';int i = 0;int j = 0;for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if ((r + i) > 0 && (c + i) > 0 && (r + i < ROWS) && (c + j < COLS) && show[r + i][c + j] == '*'){//递归ExpandBoard(mine, show, r + i, c + j);}}}}else{show[r][c] = ret + '0';}}

void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int r, int c){int ret = mine_count(mine, r, c);if (ret == 0){show[r][c] = ' ';int i = 0;int j = 0;if (show[r - 1][c - 1] == '*' && r - 1 > 0 && r - 1 < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r - 1, c - 1);if (show[r - 1][c] == '*' && r - 1 > 0 && r - 1 < ROWS && c > 0 && c < COLS)ExpandBoard(mine, show, r - 1, c);if (show[r - 1][c + 1] == '*' && r - 1 > 0 && r - 1 < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r - 1, c + 1);if (show[r][c - 1] == '*' && r > 0 && r < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r, c - 1);if (show[r][c + 1] == '*' && r > 0 && r < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r, c + 1);if (show[r + 1][c - 1] == '*' && r + 1 > 0 && r + 1 < ROWS && c - 1 > 0 && c - 1 < COLS)ExpandBoard(mine, show, r + 1, c - 1);if (show[r + 1][c] == '*' && r + 1 > 0 && r + 1 < ROWS && c > 0 && c < COLS)ExpandBoard(mine, show, r + 1, c);if (show[r + 1][c + 1] == '*' && r + 1 > 0 && r + 1 < ROWS && c + 1 > 0 && c + 1 < COLS)ExpandBoard(mine, show, r + 1, c + 1);}}else{show[r][c] = ret + '0';}}

总结

这个扫雷小游戏还有需要改进的地方,比如放标记功能,调整难度功能,感兴趣的小伙伴可以继续研究。如果内容有什么错误的话,请大家提出来,一起讨论,一起进步!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。