目录
问题描述
有一个一定大小的矩阵(初级9x9,中级16x16,高级16x30或自定义大小),矩阵中随机布置一定量的地雷 (初级为 10 个,中级为 40 个,高级为 99 个) ,但是雷区大小不能超过 24 × 30。由玩家逐个翻开格子,以找出所有地雷为最终游戏目标。如果玩家翻开的格子有地雷,则游戏失败。如果玩家翻开所有没有地雷的格子,则游戏胜利。
需求分析(游戏规则);
扫雷规模类型
初级雷区,矩阵大小为9x9,内含有10个雷。
中级雷区,矩阵大小为16x16,内含有40雷。
高级雷区,矩阵大小为16x30,内含有99个类。
自定义雷区,矩阵大小不能小于9x9,不能超过24x30,雷数最小为10个,最多不能超过雷区的90%。
扫雷的操作规则和要求
操作规则
1. 左键单击。打开该格子,如果该格子周围 3 × 3 区域中有雷,则显示雷的个数;如果地雷个数为 0, 则显示为 0 并打开周围 3 × 3 区域中所有未被打开的格子。
2. 右键单击标记地雷。如果该位置为未被打开的格子或问题标记的格子,该位置可以被标记为地雷,以"!"显示。
3. 右键单击标记问题。如果该位置为未被打开的格子或地雷标记的格子,该位置可以被标记为问题,以"?"显示。
4. 右键单击取消标记。如果该位置为问题标记或地雷标记的格子,该位置可以被取消标记,恢复为未被 打开的格子。
5. 双击。当双击位置周围已标记雷数等于该位置数字时操作有效,相当于对该数字周围未标记且未打开的格子均进行一次左键单击操作。地雷未标记完全时使用双击无效。若数字周围有标错的地雷,则游戏结束。
OJ版本代码实现
游戏提示:
1. 如果玩家未触雷且游戏未胜利,提示"Game in progress"。
2. 如果玩家点开了所有没有雷的格子(不需要完全标记地雷),提示"Game over, you win"。
3. 如果玩家点开有雷的格子,提示"Hit mine, you lose"。
输入和输出
1.进行初始化
char a[maxsize][maxsize];//根据读入初始化棋盘
int i, j;
for (i = 1; i <= row; i++)
{
scanf("%s", a[i]);
}
for (i = 1; i <= row; i++)
{
for (j = 0; j < column; j++)
{
if (a[i][j] == '*')
board[i][j + 1] = 1;
else if (a[i][j] == '.')
{
board[i][j + 1] = 0;
}
}
}
int i, j, sum, i1, j1, i2, j2, i3, j3;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
range(i,j, &i1, &i2, &j1, &j2, row, column);//确定周围8块的范围
sum = 0;
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
sum += board[i3][j3];
}
}
sum = sum - board[i][j];
ThunderNumber[i][j] = sum;
}
}
void range(int i, int j, int* i1, int* i2, int* j1, int* j2, int row, int column)
{
*i1 = i - 1;
*i2 = i + 1;
if (i == 1)
{
*i1 = 1;
}
else if (i == row)
{
*i2 = row;
}
*j1 = j - 1;
*j2 = j + 1;
if (j == 1)
{
*j1 = 1;
}
else if (j == column)
{
*j2 = column;
}
}
2.读取操作步骤,更改单元状态
循环读入操作步骤以及操作位置,实现对相应单元状态的迁移和更改
void transform(int Boardstatue[][maxsize], int row, int column, int ThunderNumber[maxsize][maxsize], int board[][maxsize], int thunderleft, int thunder)
{
int operation, x, y;
int Is = 1, times = 0;
while (Is == 1 && scanf("%d", &operation) != EOF && scanf("%d %d", &x, &y) != EOF)//当操作不合法时
{
times++;
if (x<1 || x>row || y<1 || y>column||(operation!=1&&operation!=4&&operation!=2&&operation!=3&&operation!=9))
{
operation = 11;//操作不合法时直接选择跳出本次循环
}
switch (operation)
{
case 1:
Leftclick(Boardstatue,board, x, y, row, column, ThunderNumber);
break;
case 2:
Rightclick1(Boardstatue, x, y);
break;
case 3:
Rightclick2(Boardstatue, x, y);
break;
case 4:
Rightclick3(Boardstatue, x, y);
break;
case 9:
Doubleclick(Boardstatue, board, x, y, row, column, ThunderNumber);
break;
default:
break;
}
thunderleft = Thunderleft(thunder, row, column, Boardstatue);
Is = judge(board, Boardstatue, ThunderNumber, row, column, thunderleft, times);
}
}
左键单击函数代码实现,注意操作无效的情况(x,y越界或者该单元已经被打开或该单元为插旗状态)
void Leftclick(int Boardstatue[][maxsize],int board[][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize])
{
int i, i1, i2, i3, j, j1, j2, j3;
int x1, y1;
if (x<1 || x>row || y<1 || y>column || Boardstatue[x][y]==4||Boardstatue[x][y]==3)//操作无效时
{
return;
}
Boardstatue[x][y] = 4;
if (ThunderNumber[x][y] == 0&&board[x][y]!=1)
{
range(x, y, &i1, &i2, &j1, &j2, row, column);
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if (i3 == x && j3 == y)
{
continue;
}
Leftclick(Boardstatue,board, i3,j3, row, column, ThunderNumber);
}
}
}
else if (board[x][y] == 1)
{
return;
}
}
右键单击代码实现,完成相应状态的迁移(0是未被打开,2是标记为问号,3是标记为插雷,4是已经被打开)
void Rightclick2(int Boardstatue[][maxsize], int x, int y)
{
if (Boardstatue[x][y] == 0)
{
Boardstatue[x][y] = 2;
}
else if (Boardstatue[x][y] == 3)
{
Boardstatue[x][y] = 2;
}
}
void Rightclick3(int Boardstatue[][maxsize], int x, int y)
{
if (Boardstatue[x][y] == 2 || Boardstatue[x][y] == 3)
{
Boardstatue[x][y] = 0;
}
}
双击代码的实现,注意操作无效的情况和双击打开周围格子中有周围雷数为0时(递归打开周围所有格子)
void Doubleclick(int Boardstatue[][maxsize], int board[][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize])
{
int i1, i2, i3, j1, j2, j3;
int sum = 0, is = 1;
if (Boardstatue[x][y] !=4)//该块没被打开时,该操作无效
{
return;
}
range(x, y, &i1, &i2, &j1, &j2, row, column);
for (i3 = i1; i3 <= i2; i3++)//计算周围棋数
{
for (j3 = j1; j3 <= j2; j3++)
{
if (Boardstatue[i3][j3] == 3)
{
sum++;
}
}
}
if (sum == ThunderNumber[x][y])//棋数等于雷数时,才可以被打开
{
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if (Boardstatue[i3][j3] != 3 && board[i3][j3] == 1)
{
is = 0;
Boardstatue[i3][j3] = 4;
}
}
}
if (is == 1)
{
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if ( Boardstatue[i3][j3] != 3)
{
if (ThunderNumber[i3][j3] == 0)
{
Leftclick(Boardstatue,board, i3, j3, row, column, ThunderNumber);//递归打开周围所有单元
}
Boardstatue[i3][j3] = 4;
}
}
}
}
}
}
3.判断当前游戏状态
首先是要确定当前剩余雷数,总格子数减去打开的单元数,剩下的就是剩余雷数,代码实现
int Thunderleft(int thunder, int row, int column, int Boardstatue[][maxsize])//确定剩余的雷数
{
int i, j;
int sum = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Boardstatue[i][j] == 3)
{
sum++;
}
}
}
thunder = thunder - sum;
return thunder;
}
对所有单元格进行遍历,检查是否有雷单元已经被打开,如果有返回1,若所有非雷都被打开,返回2,其他返回0(表示游戏正在进行)
int Iscontinue(int Board[][maxsize], int Boardstatue[][maxsize], int row, int column)
{
int i, j, IS = 1, win = 1;
for (i = 1; i <= row && IS == 1; i++)
{
for (j = 1; j <= column && IS == 1; j++)
{
if (Board[i][j] == 1 && Boardstatue[i][j] == 4)
{
IS = 0;
break;
}
if (Board[i][j] == 0 && Boardstatue[i][j] != 4)
{
win = 0;
}
}
}
if (IS == 1 && win == 1)
return 2;
else
return IS;
}
再根据当前游戏状态输出游戏提示和当前棋盘状态
int judge(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times)
{
if (Iscontinue(Board, Boardstatue, row, column) == 1)
{
printf("Game in progress\n");
print1(Board, Boardstatue, ThunderNumber, row, column, thunderleft, times);
return 1;
}
else if (Iscontinue(Board, Boardstatue, row, column) == 0)
{
printf("Hit mine, you lose\n");
printf("%d %d\n", times, thunderleft);
print2(Board, Boardstatue, ThunderNumber, row, column);
return 0;
}
else if (Iscontinue(Board, Boardstatue, row, column) == 2)
{
printf("Game over, you win\n");
printf("%d %d\n", times, thunderleft);
print2(Board, Boardstatue, ThunderNumber, row, column);
return 2;
}
}
输出函数print1和print2
void print1(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times)
{
int i, j;
printf("%d %d\n", times, thunderleft);
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Boardstatue[i][j] == 0)
printf(".");
else if (Boardstatue[i][j] == 2)
printf("?");
else if (Boardstatue[i][j] == 3)
printf("!");
else if (Boardstatue[i][j] == 4)
printf("%d", ThunderNumber[i][j]);
}
printf("\n");
}
}
void print2(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column)
{
int i, j;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Board[i][j] == 1)
printf("*");
else if (Boardstatue[i][j] == 0)
printf(".");
else if (Boardstatue[i][j] == 2)
printf("?");
else if (Boardstatue[i][j] == 3)
printf("!");
else if (Boardstatue[i][j] == 4)
printf("%d", ThunderNumber[i][j]);
}
printf("\n");
}
}
4.OJ版本全部代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxsize 35
void initial_(int row, int column, int board[maxsize][maxsize], int ThunderNumber[maxsize][maxsize]);
int Thunderleft(int thunder, int row, int column, int Boardstatue[][maxsize]);
void CreatlistThunderNumber0(int row, int column, int board[maxsize][maxsize], int ThunderNumber[maxsize][maxsize]);
void Leftclick(int Boardstatue[][maxsize], int board[maxsize][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize]);
void Rightclick1(int Boardstatue[][maxsize], int x, int y);
void Rightclick2(int Boardstatue[][maxsize], int x, int y);
void Rightclick3(int Boardstatue[][maxsize], int x, int y);
void Doubleclick(int Boardstatue[][maxsize], int Board[][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize]);
void transform(int Boardstatue[][maxsize], int row, int column, int ThunderNumber[maxsize][maxsize], int board[][maxsize], int thunderleft, int thunder);
int judge(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times);
int Iscontinue(int Board[][maxsize], int Boardstatue[][maxsize], int row, int column);
void print1(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times);
void print2(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column);
int main()
{
int n, row, column;
int board[maxsize][maxsize] = { 0 };//将原有字符棋盘转换为0和1的二维数组排列(0表示无雷,1表示有雷)
int Boardstatue[maxsize][maxsize] = { 0 };//存储每个块的状态0表示未打开,
int ThunderNumber[maxsize][maxsize] = { 0 };//计算并存储每个块周围的雷数
int thunderleft = 0;//剩余的雷数=雷数-插旗数
int thunder;
int number = 0;
//0 未打开 1 有雷 2问号 3插旗 4已打开
scanf("%d", &n);//确定棋盘规模
switch (n) {
case 1:
row = 9;
column = 9;
thunder = 10;
break;
case 2:
row = 16;
column = 16;
thunder = 40;
break;
case 3:
row = 16;
column = maxsize;
thunder = 99;
break;
case 4:
scanf("%d", &row);
scanf("%d", &column);
scanf("%d", &thunder);
break;
}
getchar();
initial_(row, column, board, ThunderNumber);//初始化Board[][]和ThunderNumber[][]
thunderleft = thunder;
transform(Boardstatue, row, column, ThunderNumber, board, thunderleft, thunder);//进行连续的操作
}
void initial_(int row, int column, int board[][maxsize], int ThunderNumber[maxsize][maxsize])
{
char a[maxsize][maxsize];
int i, j;
for (i = 1; i <= row; i++)
{
scanf("%s", a[i]);
}
for (i = 1; i <= row; i++)
{
for (j = 0; j < column; j++)
{
if (a[i][j] == '*')
board[i][j + 1] = 1;
else if (a[i][j] == '.')
{
board[i][j + 1] = 0;
}
}
}
CreatlistThunderNumber0(row, column, board, ThunderNumber);//创建ThunderNumber[][]
}
void CreatlistThunderNumber0(int row, int column, int board[maxsize][maxsize], int ThunderNumber[maxsize][maxsize])
{
int i, j, sum, i1, j1, i2, j2, i3, j3;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
range(i,j, &i1, &i2, &j1, &j2, row, column);//确定周围8块的范围
sum = 0;
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
sum += board[i3][j3];
}
}
sum = sum - board[i][j];
ThunderNumber[i][j] = sum;
}
}
}
void range(int i, int j, int* i1, int* i2, int* j1, int* j2, int row, int column)
{
*i1 = i - 1;
*i2 = i + 1;
if (i == 1)
{
*i1 = 1;
}
else if (i == row)
{
*i2 = row;
}
*j1 = j - 1;
*j2 = j + 1;
if (j == 1)
{
*j1 = 1;
}
else if (j == column)
{
*j2 = column;
}
}
void transform(int Boardstatue[][maxsize], int row, int column, int ThunderNumber[maxsize][maxsize], int board[][maxsize], int thunderleft, int thunder)
{
int operation, x, y;
int Is = 1, times = 0;
while (Is == 1 && scanf("%d", &operation) != EOF && scanf("%d %d", &x, &y) != EOF)//当操作不合法时
{
times++;
if (x<1 || x>row || y<1 || y>column||(operation!=1&&operation!=4&&operation!=2&&operation!=3&&operation!=9))
{
operation = 11;
}
switch (operation)
{
case 1:
Leftclick(Boardstatue,board, x, y, row, column, ThunderNumber);
break;
case 2:
Rightclick1(Boardstatue, x, y);
break;
case 3:
Rightclick2(Boardstatue, x, y);
break;
case 4:
Rightclick3(Boardstatue, x, y);
break;
case 9:
Doubleclick(Boardstatue, board, x, y, row, column, ThunderNumber);
break;
default:
break;
}
thunderleft = Thunderleft(thunder, row, column, Boardstatue);
Is = judge(board, Boardstatue, ThunderNumber, row, column, thunderleft, times);
}
}
int Thunderleft(int thunder, int row, int column, int Boardstatue[][maxsize])//确定剩余的雷数
{
int i, j;
int sum = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Boardstatue[i][j] == 3)
{
sum++;
}
}
}
thunder = thunder - sum;
return thunder;
}
void Leftclick(int Boardstatue[][maxsize],int board[][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize])
{
int i, i1, i2, i3, j, j1, j2, j3;
int x1, y1;
if (x<1 || x>row || y<1 || y>column || Boardstatue[x][y]==4||Boardstatue[x][y]==3)//操作无效时
{
return;
}
Boardstatue[x][y] = 4;
if (ThunderNumber[x][y] == 0&&board[x][y]!=1)
{
range(x, y, &i1, &i2, &j1, &j2, row, column);
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if (i3 == x && j3 == y)
{
continue;
}
Leftclick(Boardstatue,board, i3,j3, row, column, ThunderNumber);
}
}
}
else if (board[x][y] == 1)
{
return;
}
}
void Rightclick1(int Boardstatue[][maxsize], int x, int y)
{
if (Boardstatue[x][y] == 0 || Boardstatue[x][y] == 2)
{
Boardstatue[x][y] = 3;
}
}
void Rightclick2(int Boardstatue[][maxsize], int x, int y)
{
if (Boardstatue[x][y] == 0)
{
Boardstatue[x][y] = 2;
}
else if (Boardstatue[x][y] == 3)
{
Boardstatue[x][y] = 2;
}
}
void Rightclick3(int Boardstatue[][maxsize], int x, int y)
{
if (Boardstatue[x][y] == 2 || Boardstatue[x][y] == 3)
{
Boardstatue[x][y] = 0;
}
}
void Doubleclick(int Boardstatue[][maxsize], int board[][maxsize], int x, int y, int row, int column, int ThunderNumber[maxsize][maxsize])
{
int i1, i2, i3, j1, j2, j3;
int sum = 0, is = 1;
if (Boardstatue[x][y] !=4)//该块没被打开直接时,该操作无效
{
return;
}
range(x, y, &i1, &i2, &j1, &j2, row, column);
for (i3 = i1; i3 <= i2; i3++)//计算周围棋数
{
for (j3 = j1; j3 <= j2; j3++)
{
if (Boardstatue[i3][j3] == 3)
{
sum++;
}
}
}
if (sum == ThunderNumber[x][y])
{
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if (Boardstatue[i3][j3] != 3 && board[i3][j3] == 1)
{
is = 0;
Boardstatue[i3][j3] = 4;
}
}
}
if (is == 1)
{
for (i3 = i1; i3 <= i2; i3++)
{
for (j3 = j1; j3 <= j2; j3++)
{
if ( Boardstatue[i3][j3] != 3)
{
if (ThunderNumber[i3][j3] == 0)
{
Leftclick(Boardstatue,board, i3, j3, row, column, ThunderNumber);
}
Boardstatue[i3][j3] = 4;
}
}
}
}
}
}
int judge(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times)
{
if (Iscontinue(Board, Boardstatue, row, column) == 1)
{
printf("Game in progress\n");
print1(Board, Boardstatue, ThunderNumber, row, column, thunderleft, times);
return 1;
}
else if (Iscontinue(Board, Boardstatue, row, column) == 0)
{
printf("Hit mine, you lose\n");
printf("%d %d\n", times, thunderleft);
print2(Board, Boardstatue, ThunderNumber, row, column);
return 0;
}
else if (Iscontinue(Board, Boardstatue, row, column) == 2)
{
printf("Game over, you win\n");
printf("%d %d\n", times, thunderleft);
print2(Board, Boardstatue, ThunderNumber, row, column);
return 2;
}
}
int Iscontinue(int Board[][maxsize], int Boardstatue[][maxsize], int row, int column)
{
int i, j, IS = 1, win = 1;
for (i = 1; i <= row && IS == 1; i++)
{
for (j = 1; j <= column && IS == 1; j++)
{
if (Board[i][j] == 1 && Boardstatue[i][j] == 4)
{
IS = 0;
break;
}
if (Board[i][j] == 0 && Boardstatue[i][j] != 4)
{
win = 0;
}
}
}
if (IS == 1 && win == 1)
return 2;
else
return IS;
}
void print1(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column, int thunderleft, int times)
{
int i, j;
printf("%d %d\n", times, thunderleft);
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Boardstatue[i][j] == 0)
printf(".");
else if (Boardstatue[i][j] == 2)
printf("?");
else if (Boardstatue[i][j] == 3)
printf("!");
else if (Boardstatue[i][j] == 4)
printf("%d", ThunderNumber[i][j]);
}
printf("\n");
}
}
void print2(int Board[][maxsize], int Boardstatue[][maxsize], int ThunderNumber[][maxsize], int row, int column)
{
int i, j;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= column; j++)
{
if (Board[i][j] == 1)
printf("*");
else if (Boardstatue[i][j] == 0)
printf(".");
else if (Boardstatue[i][j] == 2)
printf("?");
else if (Boardstatue[i][j] == 3)
printf("!");
else if (Boardstatue[i][j] == 4)
printf("%d", ThunderNumber[i][j]);
}
printf("\n");
}
}