1.实现结果
仅简单模式,9*9排雷节目大小,共有10个雷。
当排查到雷所在坐标时,游戏失败。
当排雷界面上仅有雷,也即未排查数归零时,游戏胜利。
①开始界面
②开始游戏
输入1并回车
③排查
排查4 4
重开再排查4 5、6 3
2.实现思路
①头文件引用和参数设置
整个项目包含三个文件:main.c , function.h , function.c
main.c 中是main函数、打印游戏初始界面的menu函数、和执行游戏主体的game函数
在main.c和function.c中引用function.h
function.h中:
②main函数设计
扫雷游戏需要布置雷,所以先设置随机数种子为之后雷的生成做准备
用do while循环来实现重复游玩的功能
通过intput变量的值来选择开始或结束游戏
③menu函数设计
④game函数设计
su是success的缩写,存放雷盘上未排查并且无雷的坐标数,当su值为零时,跳出while循环,游戏胜利
mine数组中存放布雷信息,无雷的坐标数组值为字符0,有雷的坐标数组值为字符1
show数组是游戏时展示的界面,初始全部显示为字符*,代表未排查
init函数初始化mine数组和show数组:
a->自定义init函数
在function.c中定义init,用两层for循环对传入的数组进行赋值,赋为传入的指定数值
b->自定义prinarr函数
打印传入的数组 ,并在第一行第一列加上坐标数方便寻找雷盘中的指定数
c->自定义putmine函数
利用随机数生成雷的位置,如果这个位置在棋盘内并且还没有布上雷,那么给这个位置的数组值赋为‘1’来代表有雷
while循环用来判断su,实现对雷盘的重复排查
对输入的坐标进行判断,首先这个数必须在雷盘之中,否则提示坐标错误
在while循环中有两个分支,一个是排查坐标刚好有雷,那么要判断游戏失败跳出循环;一个是排查坐标无雷,统计周围8个坐标的雷数并显示在展示的雷盘(show数组)中,如果周围雷数是0,那么再向四周统计并显示,知道雷数不为0
第一种情况:
if (mine[px][py] == '1')
{
system("Cls");
printf("很遗憾,你被炸死了。\n");
prinarr(show, ROWS, COLS);
prinarr(mine, ROWS, COLS);
break;
}
第二种情况:
else
{
system("Cls");
release(mine, show, px, py);
prinarr(show, ROWS, COLS);
}
接下来是整个程序设计的难点,如何实现上述向四周排查,也就是点一下可以展开一片的效果。这里我们写成一个release函数,在function.c中进行定义
d->自定义release函数
void release(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int x, int y)
{// arr1->mine arr2->show
arr2[x][y] = countsum(arr1, x, y) + '0';
//int stx = x, sty = y;
if (arr2[x][y] == '0')
{
int i = 0, j = 0;
for (j = 1; (y - j >= 1) && (countsum(arr1, x, y - j + 1) == 0); j++)
{
if (arr1[x][y - j] == '0' && arr2[x][y - j] == '*')
{
arr2[x][y - j] = countsum(arr1, x, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x, y + j - 1) == 0); j++)
{
if (arr1[x][y + j] == '0' && arr2[x][y + j] == '*')
{
arr2[x][y + j] = countsum(arr1, x, y + j) + '0';
}
else break;
}
for (i = 1; x - i >= 1; i++)
{
if (arr1[x - i][y] == '0' && arr2[x - i][y] == '*')
{
arr2[x - i][y] = countsum(arr1, x - i, y) + '0';
if (arr2[x - i][y] == '0')
{
for (j = 1; (y - j >= 1) && (countsum(arr1, x - i, y - j + 1) == 0); j++)
{
if (arr1[x - i][y - j] == '0' && arr2[x - i][y - j] == '*')
{
arr2[x - i][y - j] = countsum(arr1, x - i, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x - i, y + j - 1) == 0); j++)
{
if (arr1[x - i][y + j] == '0' && arr2[x - i][y + j] == '*')
{
arr2[x - i][y + j] = countsum(arr1, x - i, y + j) + '0';
}
else break;
}
}
else break;
}
else break;
}
for (i = 1; x + i < ROWS; i++)
{
if (arr1[x + i][y] == '0' && arr2[x + i][y] == '*')
{
arr2[x + i][y] = countsum(arr1, x + i, y) + '0';
if (arr2[x + i][y] == '0')
{
for (j = 1; (y - j >= 1) && (countsum(arr1, x + i, y - j + 1) == 0); j++)
{
if (arr1[x + i][y - j] == '0' && arr2[x + i][y - j] == '*')
{
arr2[x + i][y - j] = countsum(arr1, x + i, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x + i, y + j - 1) == 0); j++)
{
if (arr1[x + i][y + j] == '0' && arr2[x + i][y + j] == '*')
{
arr2[x + i][y + j] = countsum(arr1, x + i, y + j) + '0';
}
else break;
}
}
else break;
}
else break;
}
}
}
首先要把传入坐标的周围雷数统计并存往show数组,然后对其进行判断。如果这个值不为0,就说明周边有雷,不需要显示周围一片,如果这个值为0,if判断为真,进行展开显示的判断
开始两个for循环是在向这个坐标位置的左右方向判断,以下进行向上向下,并每一行向左右的判断
我们向上一行判断(i = 1 x - i),如果周围雷数非零,那么显示这个数到show,停止展开;如果周围雷数为0,显示这个数并且接着向下判断
以上就是对展开区域和周围雷数统计的思路,并且借助for循环使得展开判断能重复进行且保证在雷盘坐标范围之内
到此为止我们实现了对雷盘的排查,和向周围展开的效果,之后需要对su变量进行判断,判断是否需要接着排查,这就用到ifsu函数
e->自定义ifsu函数
统计传入数组(也就是show数组)中'*'字符的个数,再减去雷数,也就是还需要排查的坐标数
3.程序设计全貌
①function.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE 10
void init(char arr[ROWS][COLS], char x);
void putmine(char arr[ROWS][COLS], int x);
void prinarr(char arr[ROWS][COLS], int x, int y);
int countsum(char[ROWS][COLS], int x, int y);
void release(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int x, int y);
int ifsu(char arr[ROWS][COLS]);
②function.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "function.h"
void init(char arr[ROWS][COLS], char x)
{
int i = 0, j = 0;
for (i = 0; i < ROWS; i++)
{
for (j = 0; j < COLS; j++)
{
arr[i][j] = x;
}
}
}
void putmine(char arr[ROWS][COLS], int x)
{
int i = 0, j = 0;
while (x > 0)
{
i = rand() % 9 + 1, j = rand() % 9 + 1;
if (arr[i][j] != '1')
{
arr[i][j] = '1';
x--;
}
}
}
void prinarr(char arr[ROWS][COLS], int x, int y)
{
int i, j;
for (i = 0; i < x - 1; i++)
{
for (j = 0; j < y -1; j++)
{
if (i == 0)
printf("%d_", j);
else
{
if (j == 0)
{
printf("%d|", i);
continue;
}
printf("%c ", arr[i][j]);
}
}
printf("\n");
}
}
int countsum(char arr[ROWS][COLS], int x, int y)
{
int i = 0, j = 0, sum = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
sum += arr[i][j];
}
}
return sum -= 9*'0';
}
void release(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int x, int y)
{// arr1->mine arr2->show
arr2[x][y] = countsum(arr1, x, y) + '0';
//int stx = x, sty = y;
if (arr2[x][y] == '0')
{
int i = 0, j = 0;
for (j = 1; (y - j >= 1) && (countsum(arr1, x, y - j + 1) == 0); j++)
{
if (arr1[x][y - j] == '0' && arr2[x][y - j] == '*')
{
arr2[x][y - j] = countsum(arr1, x, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x, y + j - 1) == 0); j++)
{
if (arr1[x][y + j] == '0' && arr2[x][y + j] == '*')
{
arr2[x][y + j] = countsum(arr1, x, y + j) + '0';
}
else break;
}
for (i = 1; x - i >= 1; i++)
{
if (arr1[x - i][y] == '0' && arr2[x - i][y] == '*')
{
arr2[x - i][y] = countsum(arr1, x - i, y) + '0';
if (arr2[x - i][y] == '0')
{
for (j = 1; (y - j >= 1) && (countsum(arr1, x - i, y - j + 1) == 0); j++)
{
if (arr1[x - i][y - j] == '0' && arr2[x - i][y - j] == '*')
{
arr2[x - i][y - j] = countsum(arr1, x - i, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x - i, y + j - 1) == 0); j++)
{
if (arr1[x - i][y + j] == '0' && arr2[x - i][y + j] == '*')
{
arr2[x - i][y + j] = countsum(arr1, x - i, y + j) + '0';
}
else break;
}
}
else break;
}
else break;
}
for (i = 1; x + i < ROWS; i++)
{
if (arr1[x + i][y] == '0' && arr2[x + i][y] == '*')
{
arr2[x + i][y] = countsum(arr1, x + i, y) + '0';
if (arr2[x + i][y] == '0')
{
for (j = 1; (y - j >= 1) && (countsum(arr1, x + i, y - j + 1) == 0); j++)
{
if (arr1[x + i][y - j] == '0' && arr2[x + i][y - j] == '*')
{
arr2[x + i][y - j] = countsum(arr1, x + i, y - j) + '0';
}
else break;
}
for (j = 1; (y + j < COLS) && (countsum(arr1, x + i, y + j - 1) == 0); j++)
{
if (arr1[x + i][y + j] == '0' && arr2[x + i][y + j] == '*')
{
arr2[x + i][y + j] = countsum(arr1, x + i, y + j) + '0';
}
else break;
}
}
else break;
}
else break;
}
}
}
int ifsu(char arr[ROWS][COLS])
{
int x = 0, i, j;
for (i = 1; i <= ROW; i++)
{
for (j = 1; j <= COL; j++)
{
if (arr[i][j] == '*')
x++;
}
}
return x - MINE;
}
③main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "function.h"
void menu(void)
{
printf("**************************\n");
printf("******** 1.play ********\n");
printf("******** 0.exit ********\n");
printf("**************************\n");
}
void game(void)
{
int su = ROW*COL-MINE;
system("Cls");
printf("开始游戏!\n");
char mine[ROWS][COLS], show[ROWS][COLS];
init(mine, '0'), init(show, '*');
prinarr(show, ROWS, COLS);
putmine(mine,MINE);
while (su)
{
int px, py;
printf("剩余未排查数:%-2d\n", su);
printf("请输入你想要排查的坐标:>");
scanf("%d %d", &px, &py);
if (px > 0 && px <= COL && py > 0 && py <= ROW && show[px][py] == '*')
{
if (mine[px][py] == '1')
{
system("Cls");
printf("很遗憾,你被炸死了。\n");
prinarr(show, ROWS, COLS);
prinarr(mine, ROWS, COLS);
break;
}
else
{
system("Cls");
release(mine, show, px, py);
prinarr(show, ROWS, COLS);
}
}
else
printf("请输入有效的坐标值!\n");
su = ifsu(show);
}
if (su == 0)
{
system("Cls");
prinarr(show, ROWS, COLS);
prinarr(mine, ROWS, COLS);
printf("恭喜你胜利了!\n\n\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 1;
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;
}