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.
Revision 0:d43dc92ae767, committed 2014-04-16
- Comitter:
- WiredHome
- Date:
- Wed Apr 16 22:25:19 2014 +0000
- Child:
- 1:9e88d16ab21e
- Commit message:
- LifeRules apply the Conway game of life rules to a LifeMap defined in an array.
Changed in this revision
LifeRules.cpp | Show annotated file Show diff for this revision Revisions of this file |
LifeRules.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LifeRules.cpp Wed Apr 16 22:25:19 2014 +0000 @@ -0,0 +1,153 @@ + +#include "LifeRules.h" + + +//#define DEBUG "LIFE" +// ... +// INFO("Stuff to show %d", var); // new-line is automatically appended +// +#if (defined(DEBUG) && !defined(TARGET_LPC11U24)) +#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#else +#define INFO(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#endif + +Life::Life(int w, int h, Life::Animation animate) +{ + LIFE_W = w; + LIFE_H = h; + maxX = w - 1; + maxY = h - 1; + animation = animate; + pLifeMap = (uint8_t *)(0x2007C000); // not using either AHBSRAM0 or AHBSRAM1 + if ((w * h * (1 << animate) * FRAMES_PER_BIT / 8) > (BYTE_RSVD_RAM)) + error("ERROR, you've overallocated memory and are doomed!"); +} + +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; + //INFO("set(%d,%2d,%2d,%d) => by %3d, bi %1d, cur %02X of %02X mask %02X [Val: %02X]", x,y,b,frame,byteIndex,bitIndex, curCell, + // maskBitsOfInterest, mask, pLifeMap[byteIndex]); + } else { + ERR(" 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)); + //INFO("getbit(%d,%2d,%2d) => byteIndex: %2d, bitIndex: %2d, [Val: %02X]", + // frame,x,y, byteIndex,bitIndex, pLifeMap[byteIndex]); + + 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 { + ERR(" Out of Bounds value (%d, %d)\r\n", x, y); + return dead; + } +} + +void Life::DestroyAllLife(void) +{ + INFO("Destroying all life"); + for (int y = 0; y <= maxY; y++) { + for (int x = 0; x <= maxX; x++) { //loop through cells + for (int f = 0; f < 2; f++) { + setbit(x,y, dead, f); + } + } + } +} + +// Values: +// 0 = dead +// 1 = dying +// 2 = living +// 3 = birthing +int Life::CountNeighbors(int x, int y) +{ + int total = 0; + + for (int k = -1; k <= 1; k++) { //loop through neighbours + 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) { //if living neighbour is found increment total + total++; + } + } + } + if (getbit(x,y)) { // minus middle of 9 cells (current cell) if it is alive + total--; + } + return total; +} + +void Life::GenerationStep(void) +{ + INFO("Generation Step"); + for (int i = 0; i <= maxX; i++) { //loop through cells + for (int j = 0; j <= maxY; j++) { + int total = CountNeighbors(i, j); + INFO("(%d,%d) has %d", i, j, total); + CycleOfLife(i, j, total); //check neighbors + } + } + frame = (frame + 1) & 1; +} + +// If dying, kill it. If birthing, give it life. +void Life::UpdateLifeCycle(void) +{ + INFO("Update Life Cycle"); + for (int x = 0; x <= maxX; x++) { //loop through cells + for (int y = 0; y <= maxY; y++) { + ValueOfLife currently = getbit(x,y); + INFO(" (%d,%d) = %d", x,y, currently); + 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); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LifeRules.h Wed Apr 16 22:25:19 2014 +0000 @@ -0,0 +1,101 @@ + +#include "mbed.h" + +// Defined and Derived values to check if it exceeds available memory +//#define BITS_PER_LIFE 2 /* 0, 1, 2, 3 provides a more colorful view of life */ +#define FRAMES_PER_BIT 2 /* current and next life cycle */ +#define BYTE_RSVD_RAM 0x8000 + +//#if (LIFE_W * LIFE_H * BITS_PER_LIFE * FRAMES_PER_BIT / 8) > (BYTE_RSVD_RAM) +//#error Bummer, can't make the lifemap that big +//#endif + + +class Life { +public: + typedef enum { + monochrome, ///< life cycle is dead or living + color ///< life cycle is dying to dead and birthing to living + } Animation; + + typedef enum { + dead, + living, + dying, + birthing + } ValueOfLife; + + /// constructor for the life + /// + /// @param w is the width of the life map + /// @param h is the height of the life map + /// + Life(int w, int h, Animation animate = color); + + /// sets a life value in the frame at location x,y. + /// + /// @param x is the x location in the life-map + /// @param y is the y location in the life-map + /// @param otherframe selects the next life-cycle of interest + /// @param b is the value of life to assign to that location + /// + void setbit(int x, int y, ValueOfLife b, int otherframe = 0); + + /// gets the life value from the specified location. + /// + /// @param x is the x location in the life-map + /// @param y is the y location in the life-map + /// @param otherframe selects the next life-cycle of interest + /// @returns the value of life at that location. + /// + ValueOfLife getbit(int x, int y, int otherframe = 0); + + /// Count and return the number of living neighbors. + /// + /// @param x is the x location in the life-map + /// @param y is the y location in the life-map + /// @returns the number of neighbors + /// + int CountNeighbors(int x, int y); + + /// Destroy all life - typically at startup. + /// + void DestroyAllLife(void); + + /// Step life forward by one generation + /// + void GenerationStep(void); + + /// Update the life-cycle. + /// + /// This method applies partial step to a life cycle. + /// It does this when the Life is set up for color mode + /// where you can then see birthing and dying cells as + /// a result of this method. + /// + void UpdateLifeCycle(void); + + /// Apply the cycle of life to a cell. + /// + /// Based on the number of neighbors, and the current + /// state of a cell, this determines whether the cell + /// is born, lives, or dies. + /// + /// @param x is the x offset into the life map. + /// @param y is the y offset into the life map. + /// @param neighbors is the count of neighbors. + /// + void CycleOfLife(int x, int y, int neighbors); + +private: + int LIFE_W; + int LIFE_H; + int maxX; // set max element + int maxY; + int frame; // the current life cycle + int animation; + + // CAUTION: This gives a pointer to a 32K byte range which is all being used! + uint8_t * pLifeMap; +}; + \ No newline at end of file