基于 元胞自动机-森林火灾模拟_vonneumann邻域-CSDN博客
进行略微修改,解决固定方向着火问题,用了一个meshv2数组记录下一状态,避免旧状态重叠数据失效。
参数调整
澳洲森林火灾蔓延数学建模,基于元胞自动机模拟多模式下火灾蔓延(附部分源码)海啸传播模型_51CTO博客_森林火灾蔓延数学模型
生命游戏 - CodeBus
// 生命游戏学习#include <easyx/easyx.h>
#include <conio.h>
#include <time.h>int world[102][102]; // 二维世界,每个格子是一个细胞
IMAGE imgLive, imgEmpty;// 方形世界
void SquareWorld() {memset(world, 0, 102 * 102 * sizeof(int)); // 分配内存for (int i = 1; i <= 100; i++) {world[i][1] = world[i][100] = 1;}for (int j = 1; j <= 100; j++) {world[1][j] = world[100][j] = 1;}
}
// 设置界面
void Init() {initgraph(640, 480);srand((unsigned)time(NULL)); // 设置随机种子Resize(&imgLive, 4, 4); // 一个格子放置一个细胞,一个细胞占4像素Resize(&imgEmpty, 4, 4);SetWorkingImage(&imgLive); // 在imgLive上绘制setfillcolor(GREEN);fillellipse(0, 0, 3, 3); // 给格子涂色SetWorkingImage(&imgEmpty); // 在imgEmpty上绘制setfillcolor(DARKGRAY);rectangle(1, 1, 2, 2); // 给格子涂色SetWorkingImage();SquareWorld(); // 产生默认的细胞以方形分布的世界
}
// 绘制世界
void PaintWorld() {for (int i = 1; i <= 100; i++)for (int j = 1; j <= 100; j++)putimage(16 + j * 4, 56 + i * 4, world[i][j] == 1 ? &imgLive : &imgEmpty); // 格子是1,就房子imgLive,否则就贴图贴入imgEmpty
}// 进化
void Evolution() {int tmp[102][102]={0}; // 临时数组 一定要初始化为0,否则会图像不对称,因为有数据残留int sum; // 九宫格中的活细胞格个数for (int i = 1; i <= 100; i++) { // 一个细胞在下一个时刻的生死取决于相邻八个方格中的活细胞数量,for (int j = 1; j <= 100; j++) {sum = world[i - 1][j - 1] + world[i - 1][j + 0] + world[i - 1][j + 1] + // 序号与排版对应,i-1就是上一行,j-1就是最左列,world[i + 0][j - 1] + + world[i + 0][j + 1] + // i是本行,j是本列world[i + 1][j - 1] + world[i + 1][j + 0] + world[i + 1][j + 1]; // i+1是下一行,j+1是最右列switch (sum) {case 3:tmp[i][j] = 1; // 若周围有 3 个活细胞,则该方格产生一个活细胞(模拟繁殖)break;case 2:tmp[i][j] = world[i][j]; // 若周围有 2 个或 3 个活细胞,保持原样。break;default:tmp [i][j] = 0; // 若周围少于 2 个活细胞,则该方格的细胞死亡(模拟人口稀疏),若周围多于 3 个活细胞,则该方格的细胞死亡(模拟极度拥挤)break;}}}// tmp 产生原因:隔断新旧世界数据// 因为 sum 需要的是旧世界周围的数据,如果直接更新,导致旧世界数据不知,直接拿新世界的数据采样,结果更不可理解,于是使用 tmp 数组记录// 将临时数组恢复为世界memcpy(world, tmp, 102 * 102 * sizeof(int)); // 就是复制粘贴,主要是int 而不是 __int8
}int main() {Init();int speed = 10; // 游戏刷新速度10毫秒while (1) {Evolution();PaintWorld();Sleep(speed);}return 0;
}
// 联系方式 b站 民用级脑的研发记录
// 细胞自动机森林火灾模型演示,
// 开发环境 小熊猫c++ 2.25.1
// 基于 //https://blog.csdn.net/weixin_43524214/article/details/105099165
// 使用 easyx 图形库
#include <stdio.h>
#include <stdlib.h>
#include <easyx/graphics.h>
#include <time.h>
#include <math.h>// 定义树木状态,给数字贴上意义,用于快速理解代码
#define no_tree 0
#define burning 2
#define nor_tree 1#define WIDTH 600 // 宽度
#define HEIGHT 600 // 高度
#define treeSize 4 // 树木大小
#define treeNum 150 // 树木个数
#define Row 150 // 150 行
#define Col 150 // 150 列
#define burning_rate 0.0001 // 初始燃烧概率0.01%
#define proTree_rate 0.02 // 空地长出新的树木的概率:10%
#define unsafe_rate 0.00005 // 新长出树木又失火的概率 0,0005%
#define N 10000/*
演化规则如下:
(1)若某树木元胞的4个邻居中有燃烧着的,那么该元胞下一时刻的状态是燃烧;
(2)一个燃烧着的元胞,在下一时刻变成空位;
(3)所有树木元胞(状态为2)以一个低概率开始燃烧(模拟闪电造成森林火灾);
(4)所有空位元胞以一个低概率变为树木(模拟新树木的生长)。
*/int treeState_Matrix[treeNum][treeNum]; // 树木格子,一个格子就是一棵树struct POS {int x;int y;
};// 画边界,画黑色线
void InitBoard() {setlinecolor(RGB(0, 0, 0)); // 黑线for (int i = 0; i < treeNum; i++) { // 每个格子横纵线line(0, i * treeSize, WIDTH, i * treeSize);line(i * treeSize, 0, i * treeSize, HEIGHT);}
}
// 随机产生树木
void InitTree(int treeState_Matrix[treeNum][treeNum]) {int i, j, count = 0;float randVal; // 记录概率for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {randVal = rand() % (N + 1) / (float)(N + 1); // % 取余数用于获取小于N+1的数字,(float)强制转换为小数,解决整数除整数只取商的默认情况导致的数据为0问题。if (randVal >= 0.40) { // 随机数大于0.40,就生成树木,格子里记录为1treeState_Matrix[i][j] = 1; // [i][j]代表当前树木的行列count++;} else {treeState_Matrix[i][j] = 0; // 随机数小,就没有树}}}
}// 画树,就是从数字数组到图片的查找过程
void drawTree(int treeState_Matrix[treeNum][treeNum]) {int i, j;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) { // 没燃烧的树是 1setfillcolor(RGB(0, 255, 0)); // 绿色} else if (treeState_Matrix[i][j] == 2) { // 燃烧的树木记录为2setfillcolor(RGB(255, 0, 0)); // 红色} else {setfillcolor(RGB(0, 0, 0)); // 记录为0就是没有树,用黑色填空}fillrectangle(j * treeSize, i * treeSize, j * treeSize + treeSize, i * treeSize + treeSize); // 数组 i 选择哪一行,就是控制选择高度 j 对应哪一列,就是对应宽 x坐标}}
}// 随机一个燃烧位置,同随机产生树木
void InitRandTreePos() {int i, j, count = 0;float randVal;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) {randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < burning_rate) {treeState_Matrix[i][j] = 2; // 树木网格里第i行第j列记录为2,对应红色,着火count++;}}}}printf("着了%d 棵树\n", count);
}
// 检查随机数,随机小于就着火
int isRight(float state) {float randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < state) {return 1;}return 0;
}// 根据旧网格存储新网格数据
void getNextTreeState(int treeState_Matrix[treeNum][treeNum]) {int meshv2[treeNum][treeNum] = {0};int i, j, state = 0;for (i = 0; i < treeNum; i++) {for (j = 0; j < treeNum; j++) {state = treeState_Matrix[i][j];if (state == 1) { // 检查上下左右if (0 || (treeState_Matrix[i - 1][j - 0] == 2) ||(treeState_Matrix[i - 0][j - 1] == 2) || (treeState_Matrix[i + 0][j + 1] == 2) ||0 || (treeState_Matrix[i + 1][j + 0] == 2)) {meshv2[i][j] = 2; // 于是被其他着火的树木点着}else{meshv2[i][j]=1; // 否则不着火}} else if (state == 2) { // 现在着火,下次就空meshv2[i][j] = 0;} else if (state == 0) { // 是空的就看看会不会长树if (isRight(proTree_rate)) { // 小于概率就长树木meshv2[i][j] = 1;}if (isRight(unsafe_rate)) { // 新的树木再着火概率meshv2[i][j] = 2;}}}}memcpy(treeState_Matrix, meshv2, treeNum* treeNum* sizeof(int));
}//主函数:程序入口
int main(int args, char* argv) {initgraph(WIDTH, HEIGHT, SHOWCONSOLE); //初始化窗体:500*500HWND hwnd = GetHWnd(); //获取窗体句柄SetWindowText(hwnd, _T("林森火灾模拟")); //设置窗体标题SetWindowPos(hwnd, NULL, 600, 200, HEIGHT, WIDTH, 0);//设置窗体位置//1、初始化网格布局InitBoard();srand((int)time(NULL)); //随机数种子//2、初始化数目状态矩阵InitTree(treeState_Matrix);//3、绘制树木drawTree(treeState_Matrix);//4、初始化燃烧树木的位置InitRandTreePos();//5、绘制森林-树木drawTree(treeState_Matrix);//开启批量绘图模式BeginBatchDraw();while (true) { //进入循环迭代//6、获取下一时刻的树木状态矩阵getNextTreeState(treeState_Matrix);//7、仍然有可能产生新的火源
// burn_again(); // 被整合进getNextTreeState//8、重新绘制森林-树木drawTree(treeState_Matrix);//显示绘图结果FlushBatchDraw(); // 显示绘制//停顿0.001sSleep(1);
// printf("ok\n");}EndBatchDraw(); //结束批量绘图模式closegraph(); //关闭设备窗口return 0;
}
getNextTreeState 微调参数
右边着火比左边快,往左跑
// 联系方式 b站 民用级脑的研发记录
// 细胞自动机森林火灾模型演示,
// 开发环境 小熊猫c++ 2.25.1
// 基于 //https://blog.csdn.net/weixin_43524214/article/details/105099165
// 使用 easyx 图形库
#include <stdio.h>
#include <stdlib.h>
#include <easyx/graphics.h>
#include <time.h>
#include <math.h>// 定义树木状态,给数字贴上意义,用于快速理解代码
#define no_tree 0
#define burning 2
#define nor_tree 1#define WIDTH 600 // 宽度
#define HEIGHT 600 // 高度
#define treeSize 4 // 树木大小
#define treeNum 150 // 树木个数
#define Row 150 // 150 行
#define Col 150 // 150 列
#define burning_rate 0.0001 // 初始燃烧概率0.01%
#define proTree_rate 0.02 // 空地长出新的树木的概率:10%
#define unsafe_rate 0.00005 // 新长出树木又失火的概率 0,0005%
#define N 10000/*
演化规则如下:
(1)若某树木元胞的4个邻居中有燃烧着的,那么该元胞下一时刻的状态是燃烧;
(2)一个燃烧着的元胞,在下一时刻变成空位;
(3)所有树木元胞(状态为2)以一个低概率开始燃烧(模拟闪电造成森林火灾);
(4)所有空位元胞以一个低概率变为树木(模拟新树木的生长)。
*/int treeState_Matrix[treeNum][treeNum]; // 树木格子,一个格子就是一棵树struct POS {int x;int y;
};// 画边界,画黑色线
void InitBoard() {setlinecolor(RGB(0, 0, 0)); // 黑线for (int i = 0; i < treeNum; i++) { // 每个格子横纵线line(0, i * treeSize, WIDTH, i * treeSize);line(i * treeSize, 0, i * treeSize, HEIGHT);}
}
// 随机产生树木
void InitTree(int treeState_Matrix[treeNum][treeNum]) {int i, j, count = 0;float randVal; // 记录概率for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {randVal = rand() % (N + 1) / (float)(N + 1); // % 取余数用于获取小于N+1的数字,(float)强制转换为小数,解决整数除整数只取商的默认情况导致的数据为0问题。if (randVal >= 0.40) { // 随机数大于0.40,就生成树木,格子里记录为1treeState_Matrix[i][j] = 1; // [i][j]代表当前树木的行列count++;} else {treeState_Matrix[i][j] = 0; // 随机数小,就没有树}}}
}// 画树,就是从数字数组到图片的查找过程
void drawTree(int treeState_Matrix[treeNum][treeNum]) {int i, j;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) { // 没燃烧的树是 1setfillcolor(RGB(0, 255, 0)); // 绿色} else if (treeState_Matrix[i][j] == 2) { // 燃烧的树木记录为2setfillcolor(RGB(255, 0, 0)); // 红色} else {setfillcolor(RGB(0, 0, 0)); // 记录为0就是没有树,用黑色填空}fillrectangle(j * treeSize, i * treeSize, j * treeSize + treeSize, i * treeSize + treeSize); // 数组 i 选择哪一行,就是控制选择高度 j 对应哪一列,就是对应宽 x坐标}}
}// 随机一个燃烧位置,同随机产生树木
void InitRandTreePos() {int i, j, count = 0;float randVal;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) {randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < burning_rate) {treeState_Matrix[i][j] = 2; // 树木网格里第i行第j列记录为2,对应红色,着火count++;}}}}printf("着了%d 棵树\n", count);
}
// 检查随机数,随机小于就着火
int isRight(float state) {float randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < state) {return 1;}return 0;
}//参数调整自 https://blog.51cto.com/u_15458165/4807865
// 根据旧网格存储新网格数据
void getNextTreeState(int treeState_Matrix[treeNum][treeNum]) {int meshv2[treeNum][treeNum] = {0};int i, j, state = 0;for (i = 0; i < treeNum; i++) {for (j = 0; j < treeNum; j++) {state = treeState_Matrix[i][j];if (state == 1) { // 检查上下左右if (0 || (treeState_Matrix[i - 1][j - 0] == 2) ||(treeState_Matrix[i - 0][j - 1] == 2) || (treeState_Matrix[i + 0][j + 1] == 2) ||(treeState_Matrix[i+0][j+2]==2)|| // 右边火势大,隔两个也能着火,于是往左跑的快0 || (treeState_Matrix[i + 1][j + 0] == 2)) {meshv2[i][j] = 2; // 于是被其他着火的树木点着}else{meshv2[i][j]=1; // 否则不着火}} else if (state == 2) { // 现在着火,下次就空meshv2[i][j] = 0;} else if (state == 0) { // 是空的就看看会不会长树if (isRight(proTree_rate)) { // 小于概率就长树木meshv2[i][j] = 1;}if (isRight(unsafe_rate)) { // 新的树木再着火概率meshv2[i][j] = 2;}}}}memcpy(treeState_Matrix, meshv2, treeNum* treeNum* sizeof(int));
}//主函数:程序入口
int main(int args, char* argv) {initgraph(WIDTH, HEIGHT, SHOWCONSOLE); //初始化窗体:500*500HWND hwnd = GetHWnd(); //获取窗体句柄SetWindowText(hwnd, _T("林森火灾模拟")); //设置窗体标题SetWindowPos(hwnd, NULL, 600, 200, HEIGHT, WIDTH, 0);//设置窗体位置//1、初始化网格布局InitBoard();srand((int)time(NULL)); //随机数种子//2、初始化数目状态矩阵InitTree(treeState_Matrix);//3、绘制树木drawTree(treeState_Matrix);//4、初始化燃烧树木的位置InitRandTreePos();//5、绘制森林-树木drawTree(treeState_Matrix);//开启批量绘图模式BeginBatchDraw();while (true) { //进入循环迭代//6、获取下一时刻的树木状态矩阵getNextTreeState(treeState_Matrix);//7、仍然有可能产生新的火源
// burn_again(); // 被整合进getNextTreeState//8、重新绘制森林-树木drawTree(treeState_Matrix);//显示绘图结果FlushBatchDraw(); // 显示绘制//停顿0.001sSleep(1);
// printf("ok\n");}EndBatchDraw(); //结束批量绘图模式closegraph(); //关闭设备窗口return 0;
}
getNextTreeState 微调参数
往下吹风
// 联系方式 b站 民用级脑的研发记录
// 细胞自动机森林火灾模型演示,
// 开发环境 小熊猫c++ 2.25.1
// 基于 //https://blog.csdn.net/weixin_43524214/article/details/105099165
// 使用 easyx 图形库
#include <stdio.h>
#include <stdlib.h>
#include <easyx/graphics.h>
#include <time.h>
#include <math.h>// 定义树木状态,给数字贴上意义,用于快速理解代码
#define no_tree 0
#define burning 2
#define nor_tree 1#define WIDTH 600 // 宽度
#define HEIGHT 600 // 高度
#define treeSize 4 // 树木大小
#define treeNum 150 // 树木个数
#define Row 150 // 150 行
#define Col 150 // 150 列
#define burning_rate 0.0001 // 初始燃烧概率0.01%
#define proTree_rate 0.02 // 空地长出新的树木的概率:10%
#define unsafe_rate 0.00005 // 新长出树木又失火的概率 0,0005%
#define N 10000/*
演化规则如下:
(1)若某树木元胞的4个邻居中有燃烧着的,那么该元胞下一时刻的状态是燃烧;
(2)一个燃烧着的元胞,在下一时刻变成空位;
(3)所有树木元胞(状态为2)以一个低概率开始燃烧(模拟闪电造成森林火灾);
(4)所有空位元胞以一个低概率变为树木(模拟新树木的生长)。
*/int treeState_Matrix[treeNum][treeNum]; // 树木格子,一个格子就是一棵树struct POS {int x;int y;
};// 画边界,画黑色线
void InitBoard() {setlinecolor(RGB(0, 0, 0)); // 黑线for (int i = 0; i < treeNum; i++) { // 每个格子横纵线line(0, i * treeSize, WIDTH, i * treeSize);line(i * treeSize, 0, i * treeSize, HEIGHT);}
}
// 随机产生树木
void InitTree(int treeState_Matrix[treeNum][treeNum]) {int i, j, count = 0;float randVal; // 记录概率for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {randVal = rand() % (N + 1) / (float)(N + 1); // % 取余数用于获取小于N+1的数字,(float)强制转换为小数,解决整数除整数只取商的默认情况导致的数据为0问题。if (randVal >= 0.40) { // 随机数大于0.40,就生成树木,格子里记录为1treeState_Matrix[i][j] = 1; // [i][j]代表当前树木的行列count++;} else {treeState_Matrix[i][j] = 0; // 随机数小,就没有树}}}
}// 画树,就是从数字数组到图片的查找过程
void drawTree(int treeState_Matrix[treeNum][treeNum]) {int i, j;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) { // 没燃烧的树是 1setfillcolor(RGB(0, 255, 0)); // 绿色} else if (treeState_Matrix[i][j] == 2) { // 燃烧的树木记录为2setfillcolor(RGB(255, 0, 0)); // 红色} else {setfillcolor(RGB(0, 0, 0)); // 记录为0就是没有树,用黑色填空}fillrectangle(j * treeSize, i * treeSize, j * treeSize + treeSize, i * treeSize + treeSize); // 数组 i 选择哪一行,就是控制选择高度 j 对应哪一列,就是对应宽 x坐标}}
}// 随机一个燃烧位置,同随机产生树木
void InitRandTreePos() {int i, j, count = 0;float randVal;for (i = 0; i < Row; i++) {for (j = 0; j < Col; j++) {if (treeState_Matrix[i][j] == 1) {randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < burning_rate) {treeState_Matrix[i][j] = 2; // 树木网格里第i行第j列记录为2,对应红色,着火count++;}}}}printf("着了%d 棵树\n", count);
}
// 检查随机数,随机小于就着火
int isRight(float state) {float randVal = rand() % (N + 1) / (float)(N + 1);if (randVal < state) {return 1;}return 0;
}// 根据旧网格存储新网格数据
void getNextTreeState(int treeState_Matrix[treeNum][treeNum]) {int meshv2[treeNum][treeNum] = {0};int i, j, state = 0;for (i = 0; i < treeNum; i++) {for (j = 0; j < treeNum; j++) {state = treeState_Matrix[i][j];if (state == 1) { // 检查上下左右if (0 || (treeState_Matrix[i - 1][j - 0] == 2) ||(treeState_Matrix[i - 0][j - 1] == 2) || (treeState_Matrix[i + 0][j + 1] == 2) ||0 // 模拟往下吹风情况,因为上面的着火树,下面着火,下面着火,上面不一定着火,吹不上去,风是往下吹
// 0 || (treeState_Matrix[i + 1][j + 0] == 2)) {meshv2[i][j] = 2; // 于是被其他着火的树木点着}else{meshv2[i][j]=1; // 否则不着火}} else if (state == 2) { // 现在着火,下次就空meshv2[i][j] = 0;} else if (state == 0) { // 是空的就看看会不会长树if (isRight(proTree_rate)) { // 小于概率就长树木meshv2[i][j] = 1;}if (isRight(unsafe_rate)) { // 新的树木再着火概率meshv2[i][j] = 2;}}}}memcpy(treeState_Matrix, meshv2, treeNum* treeNum* sizeof(int));
}//主函数:程序入口
int main(int args, char* argv) {initgraph(WIDTH, HEIGHT, SHOWCONSOLE); //初始化窗体:500*500HWND hwnd = GetHWnd(); //获取窗体句柄SetWindowText(hwnd, _T("林森火灾模拟")); //设置窗体标题SetWindowPos(hwnd, NULL, 600, 200, HEIGHT, WIDTH, 0);//设置窗体位置//1、初始化网格布局InitBoard();srand((int)time(NULL)); //随机数种子//2、初始化数目状态矩阵InitTree(treeState_Matrix);//3、绘制树木drawTree(treeState_Matrix);//4、初始化燃烧树木的位置InitRandTreePos();//5、绘制森林-树木drawTree(treeState_Matrix);//开启批量绘图模式BeginBatchDraw();while (true) { //进入循环迭代//6、获取下一时刻的树木状态矩阵getNextTreeState(treeState_Matrix);//7、仍然有可能产生新的火源
// burn_again(); // 被整合进getNextTreeState//8、重新绘制森林-树木drawTree(treeState_Matrix);//显示绘图结果FlushBatchDraw(); // 显示绘制//停顿0.001sSleep(1);
// printf("ok\n");}EndBatchDraw(); //结束批量绘图模式closegraph(); //关闭设备窗口return 0;
}