C初阶-扫雷

上次完成了三子棋的做法,利用了二维数组。扫雷也是一样,需要我们利用二维数组去完成。扫雷有所不同的地方在于,我们需要两个二维数组。一个用来展示棋盘,另外一个用于展示我们的下雷过程,因为每一个点击有可能是雷或者不是雷。

关于扫雷的编程思想我们与三子棋相比是有一些不同的地方。但归途同属,我们只需要想清楚每一个步骤就可以。

还是先创建一个工程,并且我还是习惯于一个头文件定义函数,一个源文件测试。

我们首先设置一个选择功能,让我们在看的时候,比较美观。毕竟好看的事务会给别人留下的印象也比较深。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>


void Start(){
    int choice == Menu();
    while(1){
        if(choice == 0){
            break;
        }
        Game();
    }
}

int Menu(){
    printf("====================\n");
    printf("    1.开始游戏\n");
    printf("    2.退出游戏\n");
    printf("====================\n");
    int choice = 0;
    scanf("%d",&choice);
    return choice;
}

基本开始样式就ok了。之后我们开始需要对每个关键步骤写代码了。

我们先想象一下扫雷的规则与步骤。

1.我们首先得有一个地图的样式,然后初始化它最初的样子

2.打印这个棋盘。(这两步与三子棋的思路比较像)

3.进行点击,之后判断点击的情况。

4.判定是否踩雷,如果踩雷,GG。

5.如果没踩雷,判定是否掀开了所有格子。

6.如果没有掀开所有格子。那么更新周围有几个雷。显示到地图上。

3-6这是一个循环的过程,所以我们将用while来判断什么时候胜利或者失败。

#define MAX_ROW 10
#define MAX_COL 10
#define DEFAULT_LEIZI_COUNT 10
void Game(){
    char show_map[MAX_ROW + 2][MAX_COL + 2];
    char mine_map[MAX_ROW + 2][MAX_COL + 2];
    Init_map();
    Print_map();
    while(1){
        int count = 0;
        int row,col;
        	printf("请输入坐标,例如1 2\n")scanf("%d",&row,&col);
        if(row <= 0 || row > MAX_ROW || col <= 0 || col > MAX_COL){
            printf("请重新输入坐标\n");
            continue;
        }
        if(mine_map[row][col] == '1'){
            printf("游戏结束,此处有雷\n");
            Print_map();
            break;
        }
		if (count==DEFAULT_LEIZI_COUNT + 1){
			printf("扫雷成功\n");
			Print_map(mine_map);
			break;
		}
        for (int i = 1; i <= MAX_ROW; i++){
			for (int j = 1; j <= MAX_COL; j++){
				if (show_map[i][j] == '*'){
					count++;
				}
			}
		}
		if (count == DEFAULT_LEIZI_COUNT){
			printf("扫雷成功\n");
			Print_map(mine_map);
			break;
		}
        Updateshowmap();
        Showaround();
        Print_map();
    }
}

这就是上面描述的一个基本的流程。也就是扫雷对输赢的判断规则。接着对每一个函数去完善。函数内参数我是没有直接添加进去的。我是都定义完成之后,才慢慢添加进去的。

首先是对我们地图的一个初始化

void Init_map(char show_map[MAX_ROW + 2][MAX_COL + 2];
    char mine_map[MAX_ROW + 2][MAX_COL + 2]){
    //在这里就要解释一下,我们为什么要加上一个2了。因为我们要保证我们需要一个边框
    //大多数人的潜意识中喜欢输入都是1 1,这样我们定义一个边框,我们就可以将其上下包围这些地图
    //那么这个地图将是从1 1到 10 10的所有点了。
    for(int row = 0;row < MAX_ROW;row++){
        for(int col = 0;col <MAX_COL;col++){
            show_map[row][col] = '*';
        }
    }
    for(int row = 0;row < MAX_ROW;row++){
        for(int col = 0;col <MAX_COL;col++){
            mine_map[row][col] = '*';
        }
    }
    int mine_count = DEFAULT_LEIZI_COUNT;
    while(mine_count > 0){
        int row = rand() % 10 + 1;
        int col = rand() % 10 + 1;
        if(mine[row][col] == '1'){
            continue;
        }
        mine[row][col] = '1';
        mine_count--;
    }
}

初始化完成之后,我们开始打印地图

void Print_map((char map[MAX_ROW + 2][MAX_COL + 2],int row,int col){
    printf("    ");
    for(int i = 1;i < MAX_ROW + 2;i++){
        printf("%d ",row);
    }
    printf("\n");
    for(int i = 1;i < MAX_ROW +2 ;i++){
            printf("---\n");
    }
    for(int row = 1;row < MAX_ROW + 2;row++){
        printf("%02d |\n",row);
        for(int col = 1;col < MAX_COL + 2;col++){
            printf("%c ",map[row][col]);
        }
        printf("\n");
    }
    
}

打印完地图之后,就是扫雷中最关键的一个部分了。判断周围雷的个数,然后将它打印到地图中。

void Updateshowmap(char show_map[MAX_ROW + 2][MAX_COL + 2];
    char mine_map[MAX_ROW + 2][MAX_COL + 2],int row,int col){
    int leizi_num = (mine_map[row][col + 1] - '0')+
        (mine_map[row][col - 1] - '0')+
        (mine_map[row + 1][col + 1] - '0')+
        (mine_map[row + 1][col] - '0')+
        (mine_map[row + 1][col - 1] - '0')+
        (mine_map[row - 1][col + 1] - '0')+
        (mine_map[row - 1][col] - '0')+
        (mine_map[row - 1][col - 1] - '0');
    show_map[row][col] = leizi_num + '0';
    return show_map[row][col];
}

在这里我是将周围八个格子是否有雷的情况统计下来,然后将其赋给中间的格子,这样我们就可以知道周围有几个雷了。

我们都知道扫雷的规则,当你点开一部分后,如果周围没雷的话,我们就将会点开空白区域。所以我们要写一个递归来去不断的调用。

void Showaround(char show_map[MAX_ROW + 2][MAX_COL + 2],
	char mine_map[MAX_ROW + 2][MAX_COL + 2], int row, int col){
	if (mine_map[row][col] == '0' && show_map[row][col] == '*'){
		show_map[row][col] = Updateshowmap(show_map, mine_map, row, col);
	}

	if (mine_map[row][col - 1] == '0' && show_map[row][col - 1]=='*'){
		show_map[row][col - 1] = Updateshowmap(show_map, mine_map, row, col - 1);
		if (Updateshowmap(show_map, mine_map, row, col) == '0'){
			Showaround(show_map, mine_map, row, col - 1);
		}
	}
	if (mine_map[row + 1][col] == '0' && show_map[row + 1][col] == '*'){
		show_map[row + 1][col] = Updateshowmap(show_map, mine_map, row + 1, col);
		if (Updateshowmap(show_map, mine_map, row + 1, col) == '0'){
			Showaround(show_map, mine_map, row + 1, col);
		}
	}

	if (mine_map[row - 1][col] == '0' && show_map[row - 1][col] == '*'){
		show_map[row - 1][col] = Updateshowmap(show_map, mine_map, row - 1, col);
		if (Updateshowmap(show_map, mine_map, row - 1, col) == '0'){
			Showaround(show_map, mine_map, row - 1, col);
		}
	}
	if (mine_map[row][col + 1] == '0' && show_map[row][col + 1] == '*'){
		show_map[row][col + 1] = Updateshowmap(show_map, mine_map, row, col + 1);
		if (Updateshowmap(show_map, mine_map, row, col + 1) == '0'){
			Showaround(show_map, mine_map, row, col + 1);
		}
	}

}

我觉得扫雷对周围的判断是根据上下左右来进行的。如果周围没雷,那么它就是相当于空白的。当分成八个方向去判断时,那么就将产生一键排雷的这种奇葩操作。

最后就是一个源文件了。将Start()放入测试即可。但是不要忘了随机种子,否则扫雷的布置雷数是没有变化的。

猜你喜欢

转载自blog.csdn.net/skrskr66/article/details/84709806