思路:
1.创建两个棋盘,一个为雷分布棋盘mine,一个为展示给玩家的棋盘show,在mine棋盘上设置雷的个数,show上展示周围雷的个数。为了避免越界,mine棋盘的行和列比show多2。ROW,COL为mine的行和列,Row,Col为show的行和列。
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include"stdio.h"
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<stdbool.h>
#include<limits.h>
#define ROW 12//行数
#define COL 12//列数
#define Row ROW-2
#define Col COL-2
void printmine(char mine[ROW][COL], int row, int col);
void printshow(char show[Row][Col], int row, int col);
void initmine(char mine[ROW][COL], int row, int col);
void initshow(char show[Row][Col], int row, int col);
void placemine(char board[ROW][COL],int row,int col,int num);
int* player(char mine[ROW][COL], char show[Row][Col], int row, int col);
int judgement(char mine[ROW][COL], char show[Row][Col], int row, int col);
void changemine(char mine[ROW][COL], int row, int col, int x, int y);
void compute_new(char mine[ROW][COL], char show[Row][Col], int row, int col, int x, int y);
void initvisted();
2.打印棋盘。printmine,printshow两个函数,二维数组传参加上行和列。
void printmine(char mine[ROW][COL], int row, int col)
{
printf(" ");
for (int y = 0; y < col - 2; y++) {
printf("%d ", y);
}
printf("\n");
for (int x = 1; x < row - 1; x++)
{
printf("%2d ", x - 1);
for (int y = 1; y < col - 1; y++)
{
printf("%c ", mine[x][y]);
}
printf("\n");
}
}
void printshow(char show[Row][Col], int row, int col)
{
printf(" ");
for (int y = 0; y < col; y++) {
printf("%d ", y);
}
printf("\n");
for (int x = 0; x < row; x++)
{
printf("%d ", x);
for (int y = 0; y < col; y++)
{
printf("%c ", show[x][y]);
}
printf("\n");
}
}
3.初始化棋盘。mine棋盘字符'0'不为雷,'1'为雷。show棋盘'*'为未排雷坐标。
void initmine(char mine[ROW][COL], int row, int col)
{
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
mine[x][y] = '0';
}
}
}
void initshow(char show[Row][Col], int row, int col)
{
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
show[x][y] = '*';
}
}
}
4.给mine棋盘设置雷。使用随机数,rand()函数,加上随机数种子,srand((unsigned int)time(NULL)),避免重复放置雷,需要判断,if (board[x][y] != '1')。
void placemine(char board[ROW][COL], int row, int col,int num)
{
int i = 0;
while (i < num)
{
int x = rand() % (row)+1;
int y = rand() % (col)+1;
if (board[x][y] != '1')
{
board[x][y] = '1';
i++;
}
}
}
5.玩家开始排雷。为了避免游戏提前结束,第一个应该不是雷。changemine函数
void changemine(char mine[ROW][COL], int row, int col, int x, int y)
{
int xm = x + 1;
int ym = y + 1;
while (1)
{
int x0 = rand() % (row)+1;
int y0 = rand() % (col)+1;
if (mine[x0][y0] != '1' && x0 != xm && y0 != ym)
{
mine[x0][y0] = '1';
break;
}
}
mine[x + 1][y + 1] = '0';
}
6.玩家输入坐标后需要判断这个位置是否为雷,是则游戏结束,否则判断这个位置周围雷个数,(使用函数compute_new,)并不断扩大范围(使用递归算法),上下左右,直到那个位置周围有雷。同时为了避免重复判断,使用visited数组,某个坐标未被判断为0,已被判断为1。一次compute_nwe函数调用后和玩家下次输入坐标时,visited需要重新置0,使用initvisited函数。玩家输入坐标,函数player返回输入的坐标以及这个位置是否为雷,是返回0,否为1;如果越界,判断后重新输入。
int* player(char mine[ROW][COL], char show[Row][Col], int row, int col)
{
int* data = (int*)malloc(sizeof(int) * 3);
printf("请输入坐标\n");
while (1) {
int x, y;
scanf("%d %d", &x, &y);
if (mine[x + 1][y + 1] == '1')
{
data[0] = 0;
data[1] = x;
data[2] = y;
return data;
}
else if (x < 0 || x >= row || y < 0 || y >= col)
{
printf("坐标非法,请重新输入\n");
}
else if (mine[x + 1][y + 1] == '0')
{
data[0] = 1;
data[1] = x;
data[2] = y;
return data;
}
}
}
void compute_new(char mine[ROW][COL], char show[Row][Col], int row, int col, int x, int y)
{
if (x >= 0 && y >= 0 && x < row && y < col && visited[x][y] == 0) {
int sum = mine[x - 1 + 1][y - 1 + 1] - '0'
+ mine[x - 1 + 1][y + 1] - '0'
+ mine[x - 1 + 1][y + 1 + 1] - '0'
+ mine[x + 1][y - 1 + 1] - '0'
+ mine[x + 1][y + 1 + 1] - '0'
+ mine[x + 1 + 1][y - 1 + 1] - '0'
+ mine[x + 1 + 1][y + 1] - '0'
+ mine[x + 1 + 1][y + 1 + 1] - '0';
show[x][y] = sum + '0';
visited[x][y] = 1;
if (show[x][y] == '0') {
if (mine[x - 1 + 1][y + 1] == '0')
{
compute_new(mine, show, Row, Col, x - 1, y);
}
if (mine[x + 1 + 1][y + 1] == '0')
{
compute_new(mine, show, Row, Col, x + 1, y);
}
if (mine[x + 1][y - 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x, y - 1);
}
if (mine[x + 1][y + 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x, y + 1);
}
if (mine[x - 1 + 1][y - 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x - 1, y - 1);
}
if (mine[x - 1 + 1][y + 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x - 1, y + 1);
}
if (mine[x + 1 + 1][y - 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x + 1, y - 1);
}
if (mine[x + 1 + 1][y + 1 + 1] == '0')
{
compute_new(mine, show, Row, Col, x + 1, y + 1);
}
}
}
}
int visited[COL][ROW] = { 0 };
void initvisted() {
for (int x = 0; x < Row; x++) {
for (int y = 0; y < Col; y++) {
visited[x][y] = 0;
}
}
}
7.每次输入坐标需要判断游戏胜利还是失败,若player函数返回的data数组的data[0]=0,则游戏失败,否则判断游戏是否胜利,使用judgement函数,返回1为胜利,否则游戏继续。
int judgement(char mine[ROW][COL], char show[Row][Col], int row, int col)
{
int count_m = 0;
int count_s = 0;
for (int x = 1; x <= row; x++)
{
for (int y = 1; y <= col; y++)
{
if (mine[x][y] == '0')
{
count_m++;
}
}
}
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
if (show[x][y] != '*')
{
count_s++;
}
}
}
if (count_m == count_s) {
return 1;
}
return 0;
}
8.调用menu函数产生游戏主界面,game函数使用循环使得玩家重复输入,并调用上述的函数。
void game();
void menu();
void menu()
{
while (true)
{
printf("******************\n");
printf(" 选择1开始游戏 \n");
printf(" 选择0结束游戏 \n");
printf("******************\n");
int n;
printf("请输入\n");
scanf("%d", &n);
if (n == 1)
{
printf("开始扫雷游戏\n");
game();
}
else if (n == 0)
{
printf("结束游戏\n");
break;
}
else
{
printf("输入错误,请重新输入\n");
}
}
}
void game()
{
printf("请输入雷的个数\n");
int num = 0;
scanf("%d", &num);
//地雷
char mine[ROW][COL];
//展示
char show[Row][Col];
//初始化
initmine(mine, ROW, COL);
initshow(show, Row, Col);
//放置地雷
placemine(mine, Row, Col,num);
//打印
//printmine(mine, ROW, COL);
printshow(show, Row, Col);
//输入坐标
//第一个不是雷
int* ty = player(mine, show, Row, Col);
initvisted();
if (ty[0] == 0 )
{
changemine(mine, Row, Col, ty[1], ty[2]);
compute_new(mine, show, Row, Col, ty[1], ty[2]);
printmine(mine, ROW, COL);
//扫描展开清除一片雷区
printshow(show, Row, Col);
}
else {
compute_new(mine, show, Row, Col, ty[1], ty[2]);
printmine(mine, ROW, COL);
printshow(show, Row, Col);
}
int judge = judgement(mine, show, Row, Col);
if (judge == 1)
{
printf("游戏胜利\n");
printmine(mine, ROW, COL);
return;
}
while (true)
{
initvisted();
int* ret = player(mine, show, Row, Col);
if (ret[0] == 0) {
printf("踩到地雷,游戏失败\n");
printmine(mine, ROW, COL);
break;
}
else if (ret[0] == 1) {
compute_new(mine, show, Row, Col, ret[1], ret[2]);
printmine(mine, ROW, COL);
printshow(show, Row, Col);
}
int judge = judgement(mine, show, Row, Col);
if (judge == 1)
{
printf("游戏胜利\n");
printmine(mine, ROW, COL);
break;
}
}
}
int main() {
srand((unsigned int)time(NULL));
menu();
return 0;
}
最终效果
上述便是扫雷简易版的代码,有更好的思路可以分享出来,有错误也希望能指正。