Conway's game of life - derived from another project, turned into a c++ class, and scaled to support up to a 480x272 display, or a lower resolution color display.

Dependents:   GameOfLife

LifeRules.cpp

Committer:
WiredHome
Date:
2014-04-23
Revision:
3:860ae49fedb7
Parent:
1:9e88d16ab21e

File content as of revision 3:860ae49fedb7:

// Conway's game of life
//
// http://en.wikipedia.org/wiki/Conway's_Game_of_Life
//
// A simple cellular automation where pixels are born, live, and die
// following a simple set of rules. The oddest of the rules is that
// it takes 3 to create birth of a new life...
//
// Early on (back in the 70's), computers were not accessible to
// most, and yet somehow this simulation flourished. I was one of
// many that used pencil and graph paper, chalk on a board and
// even pennies on paper to simulate each cell. It was so much 
// more animated when I had access to an 8008 micro and a "TV 
// typewriter" interface.
//
#include "LifeRules.h"

// Hopefully, the least obvious thing in this code, once you understand
// the basic rules of "life" is that access to the pLifeMap, which 
// takes the 32K Ethernet buffer on the LPC1768. Of course, your 
// application must not be using either AHBSRAM0 or AHBSRAM1 for this
// to succeed.
Life::Life(int w, int h, Life::Animation animate, uint8_t * pMap)
{
    LIFE_W = w;
    LIFE_H = h;
    maxX = w - 1;
    maxY = h - 1;
    animation = animate;
    pLifeMap = pMap;
}

void Life::setbit(int x, int y, Life::ValueOfLife b, int otherframe)
{
    unsigned long byteIndex = ((x + LIFE_W * y) * (1 << animation) * FRAMES_PER_BIT) / 8;
    unsigned long  bitIndex = (((x + LIFE_W * y) * (1 << animation) * FRAMES_PER_BIT) % 8) + (((frame + otherframe) & 1) * (1 << animation));
    
    if (animation == monochrome)
        b = (ValueOfLife)(b & 1);
    if (x >= 0 && x <= maxX && y >= 0 && y <= maxY) {
        uint8_t maskBitsOfInterest = ((1 << (1 << animation)) -1) << (bitIndex);
        uint8_t curCell = pLifeMap[byteIndex] & ~maskBitsOfInterest;
        uint8_t mask = b << (bitIndex);
        pLifeMap[byteIndex] = curCell | mask;
    } else {
        error(" Out of bounds value (%d, %d)\r\n", x, y);
    }
}

Life::ValueOfLife Life::getbit(int x, int y, int otherframe)
{
    unsigned long byteIndex = ((x + LIFE_W * y) * (1 << animation) * FRAMES_PER_BIT) / 8;
    unsigned long  bitIndex = (((x + LIFE_W * y) * (1 << animation) * FRAMES_PER_BIT) % 8) + (((frame + otherframe) & 1) * (1 << animation));
   
    if (x >= 0 && x <= maxX && y >= 0 && y <= maxY) {   
        uint8_t maskBitsOfInterest = ((1 << (1 << animation)) -1) << (bitIndex);
        uint8_t curCell = pLifeMap[byteIndex] & maskBitsOfInterest;
        ValueOfLife b = (ValueOfLife)(curCell >> (bitIndex));
        if (animation == monochrome)
            b = (ValueOfLife)(b & 1);
        return b;
    } else {
        error(" Out of Bounds value (%d, %d)\r\n", x, y);
        return dead;
    }
}

void Life::DestroyAllLife(void)
{
    for (int y = 0; y <= maxY; y++) {
        for (int x = 0; x <= maxX; x++) {
            for (int f = 0; f < 2; f++) {
                setbit(x,y, dead, f);
            }
        }
    }
}

int Life::CountNeighbors(int x, int y)
{
    int total = 0;
    
    for (int k = -1; k <= 1; k++) {
        for (int l = -1; l <= 1; l++) {
            ValueOfLife lifeState = getbit((x+LIFE_W+k)%LIFE_W,(y+LIFE_H+l)%LIFE_H);
            if (lifeState == living) {
                total++;
            }
        }
    }
    if (getbit(x,y)) { // minus the cell of interest if it is alive
        total--;
    }
    return total;
}

void Life::GenerationStep(void)
{
    for (int i = 0; i <= maxX; i++) {
        for (int j = 0; j <= maxY; j++) {
            int total = CountNeighbors(i, j);
            CycleOfLife(i, j, total);
        }
    }
    frame = (frame + 1) & 1;
}

void Life::UpdateLifeCycle(void)
{
    for (int x = 0; x <= maxX; x++) { //loop through cells
        for (int y = 0; y <= maxY; y++) {
            ValueOfLife currently = getbit(x,y);
            if (currently == dying)
                setbit(x,y, dead);
            else if (currently == birthing)
                setbit(x,y, living);
        }
    }
}

void Life::CycleOfLife(int x, int y, int neighbors)
{
    ValueOfLife currently = getbit(x,y);
    
    if ((neighbors < 2) || (neighbors > 3)) {
        if (currently == living)
            setbit(x,y, dying, 1);
        else
            setbit(x,y, dead, 1);
    }
    if (neighbors == 3) {
        if (currently == living)
            setbit(x,y, living, 1);
        else
            setbit(x,y, birthing, 1);
    }
    if (neighbors == 2) {
        setbit(x,y, currently, 1);
    }
}