相信大家对扫雷小游戏都不陌生,今天我们就用C语言来实现一下9*9的扫雷游戏。
效果图:
在实习时我们会遇到两个问题
1.越界访问
因为要实现9*9的游戏棋盘,要使用9*9的二维数组,我们知道扫雷中会有统计周围8个空间雷数的步骤,当我统计第一行第一列周围雷数时,也就是数组 [0][0] 周围的雷数时,会导致越界访问,因为我们没有办法访问到该点上面的元素,所以在实现时我们实际上是使用的11*11的数组,数组最边上的元素我们不用,这样就不用担心越界访问了。
2.两个棋盘
在实现时我们需要使用两个棋盘,是因为我们在没有排雷之前是需要用 '*' 遮住整个棋盘的,而且我们还需要一个二位数组来存放雷的位置,是雷数组赋值为 '1' ,不是雷赋值为 '0'。所以一个棋盘是不够的
我们在最开始使用宏定义行和列,还有雷的数目。
#define COUNT 10//雷的数量 #define ROW 9 //行 #define COL 9 //列 #define ROWS ROW+2 #define COLS COL+2
1.定义棋盘
1. char mine[ROWS][COLS];//存放布置好的雷 2. char show[ROWS][COLS];//存放排除出雷的信息 ,显示给用户
2.初识化棋盘
InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //为了俩个棋盘都能使用,我们传入要初始化的值 //不是雷为 ‘0’ 是雷 ‘1’ //函数的定义 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = set;//初始化 } } }
3.打印棋盘
DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); //定义 void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (j = 0; j < col / 2; j++) { printf("****"); } printf("扫雷游戏"); for (j = 0; j < col / 2; j++) { printf("****"); } if (col % 2 != 0) printf("*"); printf("\n"); for (j = 0; j < col + 1; j++) { printf("----"); } printf("-\n"); for (i = 0; i < row + 1; i++) { printf("| %d |", i); for (j = 1; j < col + 1; j++) { if (i == 0) printf(" %d |", j);//打印坐标 else if (board[i][j] == '0') { printf(" |"); } else printf(" %c |", board[i][j]);//打印棋盘数组元素 } printf("\n"); if(i<row) { for (j = 0; j < col + 1; j++) { printf("|---"); } printf("|\n"); } } for (j = 0; j < col + 1; j++) { printf("----"); } printf("-\n"); }
4.布置雷
生成随机数
//布置雷 void SetMine(char mine[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = COUNT;//10 while(count>0)//生成10个雷 { x = rand() % row + 1;// 1到9 y = rand() % col + 1;// 1到9 if (mine[x][y] == '0')//确定这个位置不是雷 { mine[x][y] = '1';//布雷成功 count--; } } }
5.排查雷
统计周围雷的数量我们可以使周围9个字符相加再加减去9个‘0’。
递归展开有三个限制条件
1.不能越界数组 if (x >= 1 && x <= row && y >= 1 && y <= col)
2.展开的前提是周围没有雷 if (ShowCount(mine, show, x, y) != '0')
3.展开的是还没有排查的坐标 if (show[i][j]=='*')
展开效果图:
//显示周围雷数 char ShowCount(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y) { show[x][y] = '0'; for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { show[x][y] += mine[i][j]; } } show[x][y] -= 9 * '0'; return show[x][y]; } //递归展开 void OpenUp(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y) { if (x >= 1 && x <= row && y >= 1 && y <= col) { if (ShowCount(mine, show, x, y) != '0') { return; } else { for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { if (show[i][j]=='*') OpenUp(mine, show, row, col, i, j); } } } } else { return; } } //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = 0; while (1) { printf("请输入你要排查的坐标:>"); scanf("%d %d", &x, &y); if (x <= row && x >= 1 && y <= col && y >= 1) { if (show[x][y] == '*') { if (mine[x][y] == '1') { system("cls"); DisplayBoard(mine, ROW, COL); printf("很遗憾你被炸死了,游戏结束\n"); system("pause"); system("cls"); break; } else { system("cls"); OpenUp(mine, show, row, col, x, y); DisplayBoard(show, ROW, COL); //判断是否胜利 count = 0; for (int i = 1; i < row + 1; i++) { for (int j = 1; j < col + 1; j++) { if (show[i][j] == '*') count++; } } if (count == COUNT) { system("cls"); DisplayBoard(mine, ROW, COL); printf("恭喜你排雷成功\n"); system("pause"); system("cls"); break; } } } else { printf("该坐标已被排查,请重新输入\n"); } } else { printf("输入非法,请重新输入\n"); } } }
6.全部代码:
game.h文件
#pragma once #include<stdio.h> #include<stdlib.h> #include<math.h> #define COUNT 10//雷的数量 #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); 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);
game.c文件
#include"game.h" //初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { for (int i = 0; i < rows; i++) { for (int 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; for (j = 0; j < col / 2; j++) { printf("****"); } printf("扫雷游戏"); for (j = 0; j < col / 2; j++) { printf("****"); } if (col % 2 != 0) printf("*"); printf("\n"); for (j = 0; j < col + 1; j++) { printf("----"); } printf("-\n"); for (i = 0; i < row + 1; i++) { printf("| %d |", i); for (j = 1; j < col + 1; j++) { if (i == 0) printf(" %d |", j);//打印坐标 else if (board[i][j] == '0') { printf(" |"); } else printf(" %c |", board[i][j]);//打印棋盘数组元素 } printf("\n"); if(i<row) { for (j = 0; j < col + 1; j++) { printf("|---"); } printf("|\n"); } } for (j = 0; j < col + 1; j++) { printf("----"); } printf("-\n"); } //布置雷 void SetMine(char mine[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = COUNT; while(count>0) { x = rand() % row + 1;// 1到9 y = rand() % col + 1;// 1到9 if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } } //显示周围雷数 char ShowCount(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y) { show[x][y] = '0'; for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { show[x][y] += mine[i][j]; } } show[x][y] -= 9 * '0'; return show[x][y]; } void OpenUp(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y) { if (x >= 1 && x <= row && y >= 1 && y <= col) { if (ShowCount(mine, show, x, y) != '0') { return; } else { for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { if (show[i][j]=='*') OpenUp(mine, show, row, col, i, j); } } } } else { return; } } //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = 0; while (1) { printf("请输入你要排查的坐标:>"); scanf("%d %d", &x, &y); if (x <= row && x >= 1 && y <= col && y >= 1) { if (show[x][y] == '*') { if (mine[x][y] == '1') { system("cls"); DisplayBoard(mine, ROW, COL); printf("很遗憾你被炸死了,游戏结束\n"); system("pause"); system("cls"); break; } else { system("cls"); OpenUp(mine, show, row, col, x, y); DisplayBoard(show, ROW, COL); //判断是否胜利 count = 0; for (int i = 1; i < row + 1; i++) { for (int j = 1; j < col + 1; j++) { if (show[i][j] == '*') count++; } } if (count == COUNT) { system("cls"); DisplayBoard(mine, ROW, COL); printf("恭喜你排雷成功\n"); system("pause"); system("cls"); break; } } } else { printf("该坐标已被排查,请重新输入\n"); } } else { printf("输入非法,请重新输入\n"); } } }
test.c文件
#include "game.h" void menu() { printf("******* 扫雷游戏 ******\n"); printf("*****************************\n"); printf("******* 1.play ******\n"); printf("******* 0.exit ******\n"); printf("*****************************\n"); } void game() { char mine[ROWS][COLS];//存放布置好的雷 char show[ROWS][COLS];//存放排除出雷的信息 //初始化棋盘 InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //打印棋盘 //DisplayBoard(mine, ROW, COL); DisplayBoard(show, 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("%d", &input); switch (input) { case 1: system("cls"); printf("游戏开始\n"); game(); break; case 0: printf("退出游戏\n"); break; default: printf("输入错误,请重新输入\n"); system("pause"); system("cls"); break; } }while (input); return 0; }
谢谢观看,希望对大家有帮助