/*********************************************************************
 *  Game of Life Ver 1.0
 *
 *  Created by Arty Sandler for The Internet Life
 *
 *  http://www.theinternetlife.com/, info@theinternetlife.com
 *
 *********************************************************************/

var lifePatterns = new Array
(
    Array
    ('simple perpetual oscillator',
     '111'),

    Array
    ('"ten in a row" perpetual oscillator',
     '1111111111'),

    Array
    ('glider',
     '001',
     '101',
     '011'),

    Array
    ('large spaceship / fish',
     '01111',
     '10001',
     '00001',
     '10010'),

    Array
    ('r-pentomino',
     '110',
     '011',
     '010'),

    Array
    ('exploder',
     '10101',
     '10001',
     '10001',
     '10001',
     '10101'),

    Array
    ('Gosper glider gun',
     '000000000000000000000000100000000000',
     '000000000000000000000010100000000000',
     '000000000000110000001100000000000011',
     '000000000001000100001100000000000011',
     '110000000010000010001100000000000000',
     '110000000010001011000010100000000000',
     '000000000010000010000000100000000000',
     '000000000001000100000000000000000000',
     '000000000000110000000000000000000000'),

    Array
    ('infinite growth (10 cells)',
     '00000010',
     '00001011',
     '00001010',
     '00001000',
     '00100000',
     '10100000'),

    Array
    ('infinite growth (5x5 square)',
     '11101',
     '10000',
     '00011',
     '01101',
     '10101'),

    Array
    ('pump',
     '1100011',
     '1010101',
     '1010101',
     '0010100',
     '0110110',
     '0110110'),

    Array
    ('diehard',
     '00000010',
     '11000000',
     '01000111')
);

var maxX = 50;
var maxY = 50;
var lifeTimer     = 0;
var lifeMatrix    = new Array(maxX);
var lifeMatrixNew = new Array(maxX);
for (var x=0; x<maxX; x++)
{
    lifeMatrix    [x] = new Array(maxY);
    lifeMatrixNew [x] = new Array(maxY);
    for (var y=0; y<maxY; y++)
    {
        lifeMatrix    [x][y] = 0;
        lifeMatrixNew [x][y] = 0;
    }
}

var statGeneration,statBorn,statDied,statLive;

//---------------------------------------------------    
//---------------------------------------------------    
function showLifeStat()
{
    document.getElementById ('tabGeneration').innerHTML = statGeneration;
    document.getElementById ('tabLive').innerHTML = statLive;
    document.getElementById ('tabBorn').innerHTML = statBorn;
    document.getElementById ('tabDied').innerHTML = statDied;
}
//---------------------------------------------------    
//---------------------------------------------------    
function setCell(elTab,x,y)
{
    lifeMatrix[x][y] = !lifeMatrix[x][y];
    elTab.style.backgroundColor = lifeMatrix[x][y] ? '#3f3faa':'white';

    // reset statistics
    statGeneration  = 0;
    statBorn        = 0; 
    statDied        = 0;
    statLive        = 0;
    showLifeStat();
}
//---------------------------------------------------    
//---------------------------------------------------    
function getCell(x,y)
{
    if ( (x<0) || (x>=maxX) || (y<0) || (y>=maxY) )
        return 0;
    return lifeMatrix[x][y];
}
//---------------------------------------------------    
//---------------------------------------------------    
function doLife()
{
    var tabLife = document.getElementById ('tabLife'); 
    if (!tabLife)
        return;

    var x,y,xx,yy,num,numChanged;
    
    for (y=0; y < maxY; y++)
    {
        for (x=0; x < maxX; x++)
        {
            num  = (getCell(x-1,y-1) & 1) ? 1 : 0;
            num += (getCell(x  ,y-1) & 1) ? 1 : 0;
            num += (getCell(x+1,y-1) & 1) ? 1 : 0;
            num += (getCell(x-1,y  ) & 1) ? 1 : 0;
            num += (getCell(x+1,y  ) & 1) ? 1 : 0;
            num += (getCell(x-1,y+1) & 1) ? 1 : 0;
            num += (getCell(x  ,y+1) & 1) ? 1 : 0;
            num += (getCell(x+1,y+1) & 1) ? 1 : 0;
            
            if (getCell(x,y))
            {
                lifeMatrixNew[x][y] = ( (num >= 2) && (num <= 3) );
            }
            else
            {
                lifeMatrixNew[x][y] = (num == 3)
            }
        }
    }
            
    numChanged = 0;
    statLive   = 0;
    for (y=0; y<maxY; y++)
    {
        for (x=0; x<maxX; x++)
        {
            if (lifeMatrix[x][y] != lifeMatrixNew[x][y])
            {
                if (lifeMatrixNew[x][y])
                     statBorn++; 
                else statDied++;
                numChanged++;
                lifeMatrix[x][y] = lifeMatrixNew[x][y];
                tabLife.rows[y].cells[x].style.backgroundColor = lifeMatrix[x][y] ? '#3f3faa':'white';
            }
            if (lifeMatrixNew[x][y])
                statLive++;
        }
    }
    statGeneration++;
    showLifeStat();

    if (lifeTimer)
    {
        if (numChanged)
        {
            lifeTimer = setTimeout ('doLife()',200);
        }
        else
        {
            if (lifeTimer)
                clearTimeout (lifeTimer);
            lifeTimer = 0;
            butStart.value='Start';
            butStep.disabled = 0;
            butStep.style.color = 'white';
            butErase.disabled = 0;
            butErase.style.color = 'white';
            butLoad.disabled = 0;
            butLoad.style.color = 'white';
        }
    }
}
//---------------------------------------------------    
//---------------------------------------------------    
function startLife()
{
    var butStart = document.getElementById ('butStart'); 
    var butStep  = document.getElementById ('butStep'); 
    var butErase = document.getElementById ('butErase'); 
    var butLoad  = document.getElementById ('butLoad'); 

    if (lifeTimer)
        clearTimeout (lifeTimer);
    lifeTimer = 0;
        
    if (butStart.value=='Start')
    {
        butStart.value='Stop';
        butStep.disabled = 1;
        butStep.style.color = 'gray';
        butErase.disabled = 1;
        butErase.style.color = 'gray';
        butLoad.disabled = 1;
        butLoad.style.color = 'gray';
        lifeTimer = setTimeout ('doLife()',200);
    }
    else
    {
        butStart.value='Start';
        butStep.disabled = 0;
        butStep.style.color = 'white';
        butErase.disabled = 0;
        butErase.style.color = 'white';
        butLoad.disabled = 0;
        butLoad.style.color = 'white';
    }
}
//---------------------------------------------------    
//---------------------------------------------------    
function eraseLife()
{
    var x,y;
    
    for (y=0; y < maxY; y++)
    {
        for (x=0; x < maxX; x++)
        {
            if (lifeMatrix[x][y])
            {
                lifeMatrix[x][y] = 0;
                tabLife.rows[y].cells[x].style.backgroundColor = 'white';
            }
        }
    }
    
    //reset statistics
    statGeneration  = 0;
    statBorn        = 0; 
    statDied        = 0;
    statLive        = 0;
    showLifeStat();
}
//---------------------------------------------------    
//---------------------------------------------------    
function loadLife()
{
    var optPatternList = document.getElementById('optPatternList');
    if (!optPatternList)
        return;
        
    var lifeInd,x,y,ofsX,ofsY,patternW,patternH;
    lifeInd = optPatternList.value;
    
    // calculate width and height of the pattern
    patternH = lifePatterns[lifeInd].length-1;
    patternW = 0;
    for (y=0; y < patternH; y++)
    {
        if (patternW < lifePatterns[lifeInd][y+1].length)
            patternW = lifePatterns[lifeInd][y+1].length;
    }
    
    // calculate the offset of the pattern
    ofsX = parseInt ( (maxX-patternW) / 2);
    ofsY = parseInt ( (maxY-patternH) / 2);
    
    // erase life
    eraseLife();
    
    // set the pattern
    for (y=0; y < patternH; y++)
    {
        for (x=0; x < patternW; x++)
        {
            if (lifePatterns[lifeInd][y+1].substr(x,1) == 1)
            {
                lifeMatrix[x+ofsX][y+ofsY] = 1;
                tabLife.rows[y+ofsY].cells[x+ofsX].style.backgroundColor = '#3f3faa';
            }
        }
    }
    
}
//---------------------------------------------------    
//---------------------------------------------------    
function setPatternList()
{
    var optPatternList = document.getElementById('optPatternList');
    if (!optPatternList)
        return;

    for (var i=0; i < lifePatterns.length; i++)
    {
        var optPattern   = document.createElement("OPTION");
        optPattern.text  = lifePatterns[i][0];
        optPattern.value = i;
        optPatternList.options.add(optPattern);
    }
}
//---------------------------------------------------    
//---------------------------------------------------    
function showLifeBoard()
{
    document.writeln ('<table cellpadding="0" cellspacing="1" class="tabLife" id="tabLife">');
    for (y=0; y<maxY; y++)
    {
        document.writeln('<tr>');
        for (x=0; x<maxX; x++)
        {
            document.writeln('<td onclick="setCell(this,'+x+','+y+')"></td>');
        }
        document.writeln('</tr>');
    }
    document.writeln('</table>');
}
//---------------------------------------------------    
//---------------------------------------------------    

