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;
} 
posted @ 2022-01-13 15:48  壹怪  阅读(584)  评论(0编辑  收藏  举报