一、实现思路
- 创建一个与玩家交互的菜单
- 利用二维数组创建两个棋盘,分别为mine(雷盘)和show盘,mine盘不可见,而show盘可见
- 随机在雷盘上布置雷
- 以输入坐标的方式扫雷
- 选择标记雷区
- 选择取消对雷的标记
- 判断游戏是否结束
二、实现过程
1、创建菜单
选择 1 进行游戏
选择 0 退出游戏
2、创建、初始化以及展示mine盘和show盘
用宏定义的方法定义棋盘的行和列,方便后期维护
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2
用二维数组的方式定义两个盘
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息 char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
利用初始化函数对两个盘进行初始化,mine盘全部初始化为 ‘0’ ,show盘全部初始化为 ‘*’
InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*');
初始化函数
//初始化 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; int 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; int j = 0; printf("----—扫雷游戏—----\n"); for (j = 0; j <= col; j++) { printf("%d ", j); } 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"); }
效果
3、随机布雷
用宏定义的方式设置要布置的雷数,方便随时修改
#define EASY_COUNT 10
利用rand和srand函数以及时间戳生成随机雷
//设置随机数生成起点 srand((unsigned int)time(NULL));
void SetMine(char board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1;//1——9 int y = rand() % col + 1;//1——9 if (board[x][y] == '0') { board[x][y] = '1'; count--; } } }
3、 玩家排雷
玩家选择扫雷,通过输入坐标进行排雷
4、统计所选位置周围八个位置中雷的个数,并打印在show盘上
//获取四周的雷数 int get_mine_count(char board[ROWS][COLS], int x, int y) { //法一 /* return board[x - 1][y] + board[x - 1][y - 1] + board[x][y - 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1] + board[x][y + 1] + board[x - 1][y + 1] - 8 * '0'; */ //法2 int count = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (board[x + i][y + j] == '1') { count++; } } } return count ; }
5、用递归的方法拓展周围不是雷的区域
用递归的方法拓展排雷
void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { //判断坐标是否越界 if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1) return; //判断是否已经排查 if (show[x][y] != '*') return; int count = get_mine_count(mine, x, y); if (count > 0) { show[x][y] = count + '0'; return; } //拓展 if (count == 0) { show[x][y] = '0'; broad(mine, show, x - 1, y); broad(mine, show, x - 1, y - 1); broad(mine, show, x, y - 1); broad(mine, show, x + 1, y - 1); broad(mine, show, x + 1, y); broad(mine, show, x + 1, y + 1); broad(mine, show, x, y + 1); broad(mine, show, x - 1, y + 1); } }
6、对认为是雷的位置用 !进行标记
int Flagmine(char show[ROWS][COLS], int row, int col,int flag_count) { int x = 0; int y = 0; if (flag_count == EASY_COUNT) { printf("标记的雷数与实际雷数相等,无法再标记\n"); return; } printf("请输入你要标记的位置:\n"); scanf_s("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col) { //判断该位置是否被排除 if (show[x][y] == '*') { show[x][y] = '!'; flag_count++; } else { printf("该位置已经排除,无法再标记\n"); } } else { printf("输入坐标非法,请重新输入:\n"); } return flag_count; }
7、取消标记
int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count) { int x = 0; int y = 0; printf("请输入你要取消标记的位置:\n"); scanf_s("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col) { //判断该位置是否被标记 if (show[x][y] == '!') { show[x][y] = '*'; flag_count--; } else { printf("该位置未被标记过,无法取消标记!\n"); } } else { printf("输入坐标非法,请重新输入:\n"); } return flag_count; }
8、判断游戏是否结束
- 若踩雷,则游戏失败,游戏结束
- 排除所有的雷,获得胜利,游戏结束
遍历棋盘,如果show盘中剩下的 ‘*’ 和 ‘!’ 数量的和加起来对于雷的数量,则排雷成功
//遍历雷盘 int TravelBoard(char show[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int win = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { if (show[i][j] == '*' || show[i][j] == '!') { win++; } } } return win; }
if (win == EASY_COUNT) { printf("恭喜你,排雷成功!\n"); DisplayBoard(mine, ROW, COL); }
三、代码展示
1、game.h
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.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 board[ROWS][COLS], int row, int col); //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //拓展周围不是雷的区域 void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y); //标记 int Flagmine(char show[ROWS][COLS], int row, int col, int flag_count); //取消标记 int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count);
2、game.c
#include"game.h" //菜单2 void menu2() { printf("**************************\n"); printf("******* 1.扫 雷 *******\n"); printf("******* 2.标 记 *******\n"); printf("******* 3.取消标记 *******\n"); printf("**************************\n"); } //初始化 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; int 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; int j = 0; printf("----—扫雷游戏—----\n"); for (j = 0; j <= col; j++) { printf("%d ", j); } 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 board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1;//1——9 int y = rand() % col + 1;//1——9 if (board[x][y] == '0') { board[x][y] = '1'; count--; } } } //遍历雷盘 int TravelBoard(char show[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int win = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { if (show[i][j] == '*' || show[i][j] == '!') { win++; } } } return win; } //获取四周的雷数 int get_mine_count(char board[ROWS][COLS], int x, int y) { //return board[x - 1][y] + // board[x - 1][y - 1] + // board[x][y - 1] + // board[x + 1][y - 1] + // board[x + 1][y] + // board[x + 1][y + 1] + // board[x][y + 1] + // board[x - 1][y + 1] - 8 * '0'; int count = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (board[x + i][y + j] == '1') { count++; } } } return count ; } //拓展周围不是雷的区域 void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { //判断坐标是否越界 if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1) return; //判断是否已经排查 if (show[x][y] != '*') return; int count = get_mine_count(mine, x, y); if (count > 0) { show[x][y] = count + '0'; return; } //拓展 if (count == 0) { show[x][y] = '0'; broad(mine, show, x - 1, y); broad(mine, show, x - 1, y - 1); broad(mine, show, x, y - 1); broad(mine, show, x + 1, y - 1); broad(mine, show, x + 1, y); broad(mine, show, x + 1, y + 1); broad(mine, show, x, y + 1); broad(mine, show, x - 1, y + 1); } } //标记 int Flagmine(char show[ROWS][COLS], int row, int col,int flag_count) { int x = 0; int y = 0; if (flag_count == EASY_COUNT) { printf("标记的雷数与实际雷数相等,无法再标记\n"); return; } printf("请输入你要标记的位置:\n"); scanf_s("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col) { //判断该位置是否被排除 if (show[x][y] == '*') { show[x][y] = '!'; flag_count++; } else { printf("该位置已经排除,无法再标记\n"); } } else { printf("输入坐标非法,请重新输入:\n"); } return flag_count; } //取消标记 int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count) { int x = 0; int y = 0; printf("请输入你要取消标记的位置:\n"); scanf_s("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col) { //判断该位置是否被标记 if (show[x][y] == '!') { show[x][y] = '*'; flag_count--; } else { printf("该位置未被标记过,无法取消标记!\n"); } } else { printf("输入坐标非法,请重新输入:\n"); } return flag_count; } //扫雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int choice = 0;//选择 int flag_count = 0;//标记雷的个数 int win = 0;//判断是否赢 while (1) { menu2(); scanf_s("%d", &choice); if (choice == 1) { int x = 0; int y = 0; printf("请输入要排查的坐标:\n"); scanf_s("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] != '*') { printf("改坐标已经被排查过了,不能重复排查!\n"); system("pause"); } else { //如果是雷 if (mine[x][y] == '1') { printf("很遗憾,你被炸死了!!!\n"); DisplayBoard(mine, ROW, COL); break; } else//如果不是雷 { broad(mine, show, x, y); //统计mine数组中(x,y) 周围有几个雷 DisplayBoard(show, ROW, COL); } } } else { printf("输入坐标非法,请重新输入\n"); } } else if (choice == 2) { printf("请标记雷:\n"); flag_count = Flagmine(show, ROW, COL,flag_count); DisplayBoard(show, ROW, COL); } else if (choice == 3) { flag_count = CancelFlag(show, ROW, COL, flag_count); DisplayBoard(show, ROW, COL); } else { printf("输入错误,请重新输入!\n"); } win = TravelBoard(show, ROW, COL); if (win == EASY_COUNT) { break; } } if (win == EASY_COUNT) { printf("恭喜你,排雷成功!\n"); DisplayBoard(mine, ROW, COL); } }
3、test.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 };//存放排查出的雷的信息 //初始化数组内容为指定的内容 //mine 数组在没有布置雷的时候,都是'0' InitBoard(mine, ROWS, COLS, '0'); //show 数组在没有排查雷的时候, 都是'*' InitBoard(show, ROWS, COLS, '*'); DisplayBoard(show, ROW, COL); //DisplayBoard(mine, ROW, COL); //设置雷 SetMine(mine, ROW, COL); //DisplayBoard(mine, ROW, COL); //排查雷 FindMine(mine, show, ROW, COL); } int main() { //设置随机数生成起点 srand((unsigned int)time(NULL)); int input = 0; do { menu(); printf("请选择:"); scanf_s("%d", &input); switch (input) { case 1: //printf("扫雷\n"); system("cls"); game(); system("pause"); system("cls"); break; case 0: system("cls"); printf("退出游戏\n"); system("pause"); break; default: printf("输入错误,请重新输入:\n"); system("pause"); system("cls"); break; } } while (input); return 0; }