PTA 扫雷游戏 纯c语言
题目概述:
扫雷是一款经典游戏,也是Windows操作系统最早引入的一款游戏,其最为经典的版本是Windows XP操作系统自带的扫雷游戏,曾风靡一个时代,是一代人的永恒记忆。
简单来说,其游戏界面由n行m列方格组成,其中k个方格后面隐藏着地雷。当用户点击一个方格时:
(1)如果该方格后面隐藏着地雷,则游戏结束,用户失败。
(2)如果该方格不是地雷,则该方格被打开:
若该方格与地雷相邻(即该方格上、下、左、右、左上、左下、右上、右下相邻的8个方格内有地雷),则该方格处显示一个数字,表示其周围8个方格中的地雷数。
若该方格未与地雷相邻(即该方格周围8个格子内没有地雷),则该方格的未被打开的邻居(即与该方格上、下、左、右、左上、左下、右上、右下相邻的方格)、邻居的邻居、邻居的邻居的邻居……都会被逐级打开,直到某方格与地雷相邻。这期间每个方格的处理方式同(2)。
(3)当所有没隐藏地雷的方格均被打开(即所有没打开的方格后都有地雷),则游戏结束,用户获胜。
请编写程序从初始界面开始,对于一系列用户的点击,求出点击之后的游戏界面。未打开的方格用-1表示,即游戏初始时为n行m列-1。已打开且未与雷相邻的方格用0表示,已打开且与雷相邻的方格用数字a (1≤ a ≤ 8)表示,即与之相邻的地雷数。
输入格式:
输入第一行是4个正整数n、m、k和l,其中n、m、k的含义如前所述。接下来k行,每行2个整数i和j,表示每个雷的坐标,即雷在第i行第j列的方格里。接下来l行,每行2个整数i和j,表示用户点击信息,即用户点击了第i行第j列的方格。m,n不超过20,k不超过50,l不超过200,0≤i<n,0≤j<m.
输出格式:
对于用户的每个点击:(1)如果用户点击的方格是已被打开的方格,则点击无效,忽略该点击。(2)如果点击的方格是地雷,则输出“You lose”,程序退出;(3)如果点击的方格不是地雷,则输出点击后的游戏界面,即n行m列整数,每个整数后一个空格,此时若用户获胜,则再输出“You win”。注:对用户每个有效点击所输出的信息用一个空行间隔。
输入样例1:
5 5 1 1
0 0
4 4
输出样例1:
-1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
You win
输入样例2:
4 5 1 2
1 2
3 0
1 2
输出样例2:
0 1 -1 1 0
0 1 -1 1 0
0 1 1 1 0
0 0 0 0 0
You lose
输入样例3:
4 5 1 2
1 2
3 0
0 2
输出样例3:
0 1 -1 1 0
0 1 -1 1 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 1 -1 1 0
0 1 1 1 0
0 0 0 0 0
You win
#include<stdio.h>
#define Rows 22
#define Cols 22
int n,m,k,l;
int data[Rows][Cols]; //数据数组
int game[Rows][Cols]; //玩家界面数组
void Init();
void disp();
void dispdata();
void setboom(int a,int b);
void setnumber();
void swap(int x,int y);
int tongji();
//初始化玩家界面
void Init()
{
for (int i = 0; i <Rows; i++)
{
for (int j = 0; j <Cols; j++)
{
game[i][j] = -1;
}
}
}
//打印玩家界面
void dispgame()
{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d ",game[i][j]);
}
printf("\n");
}
}
//打印后台数据
void dispdata(){
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
printf("%d ",data[i][j]);
}
printf("\n");
}
}
//设置炸弹
void setboom(int a,int b)
{
data[a+1][b+1]=-1; //data数组打印出来的是从下标1开始的
}
//将后台数据与游戏界面交互
void swap(int x,int y)
{
if(game[x][y]!=-1||x<1||x>n||y<1||y>m){
return ;
}else{
game[x][y]=data[x][y];
}
if(game[x][y]==0){
for(int i=x-1;i<=x+1;i++){
for(int j=y-1;j<=y+1;j++){
swap(i,j);
}
}
}
}
//设置后台元素数据
void setnumber()
{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(data[i][j]!=-1)
{
if(data[i-1][j-1]==-1)
data[i][j]++;
if(data[i-1][j]==-1)
data[i][j]++;
if(data[i-1][j+1]==-1)
data[i][j]++;
if(data[i][j-1]==-1)
data[i][j]++;
if(data[i][j+1]==-1)
data[i][j]++;
if(data[i+1][j-1]==-1)
data[i][j]++;
if(data[i+1][j]==-1)
data[i][j]++;
if(data[i+1][j+1]==-1)
data[i][j]++;
}
}
}
}
//统计还有多少个位置没开
int tongji()
{
int sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(game[i][j]==-1){
sum++;
}
}
}
return sum;
}
int main()
{
Init();
scanf("%d %d %d %d",&n,&m,&k,&l);//输入数据
if(n>=0&&n<=20&&m>=0&&m<=20&&k>=0&&k<=50&&l>=0&&l<=200){
//将炸弹保存进后台数组
for(int i=0;i<k;i++){
int a=0,b=0;
scanf("%d %d",&a,&b);
if(a>=0&&a<=n&&b>=0&&b<=m){
setboom(a,b);
}
}
//设置后台元素
setnumber();
//玩家操作
int x,y;
for(int i=0;i<l;i++){
scanf("%d %d",&x,&y);
//判断是否踩到雷
if(x>=0&&x<=n&&y>=0&&y<=m){
if(data[x+1][y+1]==-1){
printf("You lose\n");
break;
}
//判断重复输入
if(game[x+1][y+1]!=-1){
continue;
}else{
swap(x+1,y+1);
dispgame();
if((tongji())==k){
printf("You win\n");
break;
}else{
printf("\n");
}
}
}
}
}
return 0;
}