目标:
雷区大小为ROWS行、COLS列,共需要随机产生MAX颗雷,且雷不能重复。同时要把雷周围的数字校正,如下10颗雷在9x9雷区随机分布图:
约定:
在雷区当中,一格既可能是数字(表达周边的总雷数),也可能它就是一颗雷,还有可能它是一个空位。那么我做如下约定:
0:表示空位
数字1-8:表示这一格周边的总雷数(以9宫格为区域,最多存在8颗雷)
数字9:表示雷
算法:
1) 准备
char Thunders[ROWS][COLS]; //雷区
初始化雷区全部为空(即为0);
设定随机数种子;
2) count从1到max,步长为1,执行:
A) r = rand() % ROWS; //随机产生行号r
B) c = rand() % COLS; //随机产生列号c
C) 若Thunders[r][c]==9则 //该位置已经有雷则不能计数,并重新随机生成雷
count--;
continue;
D) 标记Thunders[r][c]为雷;
E) 以Thunders[r][c]为中心,对周边8格去更新数字(累加1)
更新左上格;
更新正上格;
更新右上格;
更新左侧格;
更新右侧格;
更新左下格;
更新正下格;
更新右下格;
//注:以上更新时要考虑数组越界的问题
// 同时要考虑如果周边某格本身就是雷,是不能累加的
图标变化过程如下:
编码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROWS 9 //行数
#define COLS 9 //列数
#define NUM_THUNDER 10 //总雷数
#define THUNDER 9
#define EMPTY 0
#define IS_EMPTY(n) (n==EMPTY)
#define IS_THUNDER(n) (n==THUNDER)
char *SIGNS[] = {"□","1", "2","3","4","5","6","7","8","●","■"};
int main()
{
char Thunders[ROWS][COLS] = {};
int r, c, count;
srand(time(NULL));
for(count=0; count<NUM_THUNDER; count++) {
r = rand() % ROWS;
c = rand() % COLS;
if(IS_THUNDER(Thunders[r][c])) {
count--;
continue;
}
Thunders[r][c] = THUNDER;
if(r-1>=0) {
if(!IS_THUNDER(Thunders[r-1][c])) Thunders[r-1][c]++; //正上
if(c-1>=0 && !IS_THUNDER(Thunders[r-1][c-1])) Thunders[r-1][c-1]++; //左上
if(c+1<COLS && !IS_THUNDER(Thunders[r-1][c+1])) Thunders[r-1][c+1]++; //右上
}
if(c-1>=0 && !IS_THUNDER(Thunders[r][c-1])) Thunders[r][c-1]++; //左
if(c+1<COLS && !IS_THUNDER(Thunders[r][c+1])) Thunders[r][c+1]++; //右
if(r+1<ROWS) {
if(!IS_THUNDER(Thunders[r+1][c])) Thunders[r+1][c]++; //正下
if(c-1>=0 && !IS_THUNDER(Thunders[r+1][c-1])) Thunders[r+1][c-1]++; //左下
if(c+1<COLS && !IS_THUNDER(Thunders[r+1][c+1])) Thunders[r+1][c+1]++; //右下
}
}
//预览雷的分布情况,检查程序是否有错误
for(r=0; r<ROWS; r++) {
for(c=0; c<COLS; c++) {
printf("%s", SIGNS[Thunders[r][c]]);
}
printf("\n");
}
return 0;
}
程序运行结果可能是下面这样子的:
以上代码在Codeblocks17.12,Win10环境下编译正常。
后绪:
编写扫雪游戏,有几个关键算法问题
1)正确的分布有效个数的雷,并校准雷周边的数字(本篇文章介绍)。
2)排雷时若遇到空位,应该自动排开空位及空位周边的数字(下篇介绍)。