Task: Forest fire


C++: #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 );
}






PHP: <?php

define('WIDTH',      10);
define('HEIGHT',     10);

define('GEN_CNT',    10);
define('PAUSE',  250000);

define('TREE_PROB',  50);
define('GROW_PROB',   5);
define('FIRE_PROB',   1);

define('BARE',      ' ');
define('TREE',      'A');
define('BURN',      '/');


$forest = makeNewForest();

for ($i = 0; $i < GEN_CNT; $i++) {
    displayForest($forest, $i);
    $forest = getNextForest($forest);
}

displayForest($forest, 'done');
exit;


function makeNewForest() {
    return mapForest([
        'func' => function(){
            return isProb(TREE_PROB) ? TREE : BARE;
        }
    ]);
}


function displayForest($forest, $generationNum) {
    system("clear");
    echo PHP_EOL . "Generation: $generationNum" . PHP_EOL;
    mapForest(['forest' => $forest, 'func' => function($f, $x, $y){
            echo $f[$y][$x] . ($x == WIDTH - 1 ? PHP_EOL : '');
        }
    ]);
    echo PHP_EOL;
    usleep(PAUSE);
}


function getNextForest($oldForest) {
    return mapForest(['forest' => $oldForest, 'func' => function($f, $x, $y){
            switch ($f[$y][$x]) {
                case BURN:
                    return BARE;
                case BARE:
                    return isProb(GROW_PROB) ? TREE : BARE;
                case TREE:
                    $caughtFire = isProb(FIRE_PROB);
                    $ablaze = $caughtFire ? true : getNumBurningNeighbors($f, $x, $y) > 0;
                return $ablaze ? BURN : TREE;
            }
        }
    ]);
}


function getNumBurningNeighbors($forest, $x, $y) {
    $burningNeighbors = mapForest([
        'forest' => $forest, 
        'x1' => $x - 1, 'x2' => $x + 2,
        'y1' => $y - 1, 'y2' => $y + 2,
        'default' => 0,
        'func' => function($f, $x, $y){
            return $f[$y][$x] == BURN ? 1 : 0;
        }
    ]);
    
    $numOnFire = 0;
    foreach ($burningNeighbors as $row) {
        $numOnFire += array_sum($row);
    }
    return $numOnFire;
}


function mapForest($params) {
    $p = array_merge([
        'forest' => [], 
        'func' => function(){echo "default\n";},
        'x1' => 0,
        'x2' => WIDTH,
        'y1' => 0,
        'y2' => HEIGHT,
        'default' => BARE
    ], $params);
    
    $newForest = [];
    for ($y = $p['y1']; $y < $p['y2']; $y++) {
        $newRow = [];
        for ($x = $p['x1']; $x < $p['x2']; $x++) {
            $inBounds = ($x >= 0 && $x < WIDTH && $y >= 0 && $y < HEIGHT);
            $newRow[] = ($inBounds ? $p['func']($p['forest'], $x, $y) : $p['default']);
        }
        $newForest[] = $newRow;
    }
    return $newForest;
}


function isProb($prob) {
    return rand(0, 100) < $prob;
}