Implement the Drossel and Schwabl definition of the forest-fire model.
It is basically a 2D cellular automaton where each cell can be in three distinct states (empty, tree and burning) and evolves according to the following rules (as given by Wikipedia)
- A burning cell turns into an empty cell
- A tree will burn if at least one neighbor is burning
- A tree ignites with probability f even if no neighbor is burning
- An empty space fills with a tree with probability p
Neighborhood is the Moore neighborhood; boundary conditions are so that on the boundary the cells are always empty (“fixed” boundary condition).
At the beginning, populate the lattice with empty and tree cells according to a specific probability (e.g. a cell has the probability 0.5 to be a tree). Then, let the system evolve.
Task’s requirements do not include graphical display or the ability to change parameters (probabilities p and f) through a graphical or command line interface.
#include <windows.h> #include <string> //-------------------------------------------------------------------------------------------------- using namespace std; //-------------------------------------------------------------------------------------------------- enum states { NONE, TREE, FIRE }; const int MAX_SIDE = 500; //-------------------------------------------------------------------------------------------------- class myBitmap { public: myBitmap() : pen( NULL ) {} ~myBitmap() { DeleteObject( pen ); DeleteDC( hdc ); DeleteObject( bmp ); } bool create( int w, int h ) { BITMAPINFO bi; ZeroMemory( &bi, sizeof( bi ) ); bi.bmiHeader.biSize = sizeof( bi.bmiHeader ); bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biWidth = w; bi.bmiHeader.biHeight = -h; HDC dc = GetDC( GetConsoleWindow() ); bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 ); if( !bmp ) return false; hdc = CreateCompatibleDC( dc ); SelectObject( hdc, bmp ); ReleaseDC( GetConsoleWindow(), dc ); width = w; height = h; return true; } void clear() { ZeroMemory( pBits, width * height * sizeof( DWORD ) ); } void setPenColor( DWORD clr ) { if( pen ) DeleteObject( pen ); pen = CreatePen( PS_SOLID, 1, clr ); SelectObject( hdc, pen ); } void saveBitmap( string path ) { BITMAPFILEHEADER fileheader; BITMAPINFO infoheader; BITMAP bitmap; DWORD wb; GetObject( bmp, sizeof( bitmap ), &bitmap ); DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight]; ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) ); ZeroMemory( &infoheader, sizeof( BITMAPINFO ) ); ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) ); infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8; infoheader.bmiHeader.biCompression = BI_RGB; infoheader.bmiHeader.biPlanes = 1; infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader ); infoheader.bmiHeader.biHeight = bitmap.bmHeight; infoheader.bmiHeader.biWidth = bitmap.bmWidth; infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ); fileheader.bfType = 0x4D42; fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER ); fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage; GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS ); HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL ); WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL ); WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL ); CloseHandle( file ); delete [] dwpBits; } HDC getDC() const { return hdc; } int getWidth() const { return width; } int getHeight() const { return height; } private: HBITMAP bmp; HDC hdc; HPEN pen; void *pBits; int width, height; }; //-------------------------------------------------------------------------------------------------- class forest { public: forest() { _bmp.create( MAX_SIDE, MAX_SIDE ); initForest( 0.05f, 0.005f ); } void initForest( float p, float f ) { _p = p; _f = f; seedForest(); } void mainLoop() { display(); simulate(); } void setHWND( HWND hwnd ) { _hwnd = hwnd; } private: float probRand() { return ( float )rand() / 32768.0f; } void display() { HDC bdc = _bmp.getDC(); DWORD clr; for( int y = 0; y < MAX_SIDE; y++ ) { for( int x = 0; x < MAX_SIDE; x++ ) { switch( _forest[x][y] ) { case FIRE: clr = 255; break; case TREE: clr = RGB( 0, 255, 0 ); break; default: clr = 0; } SetPixel( bdc, x, y, clr ); } } HDC dc = GetDC( _hwnd ); BitBlt( dc, 0, 0, MAX_SIDE, MAX_SIDE, _bmp.getDC(), 0, 0, SRCCOPY ); ReleaseDC( _hwnd, dc ); } void seedForest() { ZeroMemory( _forestT, sizeof( _forestT ) ); ZeroMemory( _forest, sizeof( _forest ) ); for( int y = 0; y < MAX_SIDE; y++ ) for( int x = 0; x < MAX_SIDE; x++ ) if( probRand() < _p ) _forest[x][y] = TREE; } bool getNeighbors( int x, int y ) { int a, b; for( int yy = -1; yy < 2; yy++ ) for( int xx = -1; xx < 2; xx++ ) { if( !xx && !yy ) continue; a = x + xx; b = y + yy; if( a < MAX_SIDE && b < MAX_SIDE && a > -1 && b > -1 ) if( _forest[a][b] == FIRE ) return true; } return false; } void simulate() { for( int y = 0; y < MAX_SIDE; y++ ) { for( int x = 0; x < MAX_SIDE; x++ ) { switch( _forest[x][y] ) { case FIRE: _forestT[x][y] = NONE; break; case NONE: if( probRand() < _p ) _forestT[x][y] = TREE; break; case TREE: if( getNeighbors( x, y ) || probRand() < _f ) _forestT[x][y] = FIRE; } } } for( int y = 0; y < MAX_SIDE; y++ ) for( int x = 0; x < MAX_SIDE; x++ ) _forest[x][y] = _forestT[x][y]; } myBitmap _bmp; HWND _hwnd; BYTE _forest[MAX_SIDE][MAX_SIDE], _forestT[MAX_SIDE][MAX_SIDE]; float _p, _f; }; //-------------------------------------------------------------------------------------------------- class wnd { public: int wnd::Run( HINSTANCE hInst ) { _hInst = hInst; _hwnd = InitAll(); _ff.setHWND( _hwnd ); _ff.initForest( 0.02f, 0.001f ); ShowWindow( _hwnd, SW_SHOW ); UpdateWindow( _hwnd ); MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { _ff.mainLoop(); } } return UnregisterClass( "_FOREST_FIRE_", _hInst ); } private: static int WINAPI wnd::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, msg, wParam, lParam ); } return 0; } HWND InitAll() { WNDCLASSEX wcex; ZeroMemory( &wcex, sizeof( wcex ) ); wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = ( WNDPROC )WndProc; wcex.hInstance = _hInst; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszClassName = "_FOREST_FIRE_"; RegisterClassEx( &wcex ); return CreateWindow( "_FOREST_FIRE_", ".: Forest Fire -- PJorente :.", WS_SYSMENU, CW_USEDEFAULT, 0, MAX_SIDE, MAX_SIDE, NULL, NULL, _hInst, NULL ); } HINSTANCE _hInst; HWND _hwnd; forest _ff; }; //-------------------------------------------------------------------------------------------------- int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { srand( GetTickCount() ); wnd myWnd; return myWnd.Run( hInstance ); } //--------------------------------------------------------------------------------------------------
Content is available under GNU Free Documentation License 1.2.