Conway's game of life applied to the mbed and an RA8875 LCD.

Dependencies:   LifeRules mbed RA8875

Inspired by a forum discussion on the mbed site, this version was scaled to support up to a 480x272 display - in a monochrome mode, or at a lower resolution in color (the color shows simple animation for birthing and dying cells).

Leveraging the LifeRules class, the game can be easily adapted to other displays - whether monochrome or color.

By default, this version allocates memory from the Ethernet ram banks, so avoids the memory limitations of some designs.

It should be simple to adapt it to any display - color or b&w, high or low resolution.

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Wed Apr 16 22:26:14 2014 +0000
Child:
1:f3f2d31f0226
Commit message:
Applies the Conway Game of Life in the mbed, and with a graphics display. Easily it can be configured for a b&w or color display. Inspired, and leveraged from, another project on the mbed site.

Changed in this revision

LifeRules.lib Show annotated file Show diff for this revision Revisions of this file
RA8875.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LifeRules.lib	Wed Apr 16 22:26:14 2014 +0000
@@ -0,0 +1,1 @@
+LifeRules#d43dc92ae767
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875.lib	Wed Apr 16 22:26:14 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/RA8875/#bd53a9e165a1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Apr 16 22:26:14 2014 +0000
@@ -0,0 +1,337 @@
+#include "mbed.h"
+#include "RA8875.h"
+#include "LifeRules.h"
+
+// Define the life-map size
+#define LIFE_W 480
+#define LIFE_H 272
+
+// Define the screen size
+#define SCREEN_W 480
+#define SCREEN_H 272
+
+extern "C" void mbed_reset();
+
+//#define DEBUG "main"
+// ...
+// 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(LIFE_W, LIFE_H, Life::monochrome);
+
+RA8875 lcd(p5, p6, p7, p12, NC, "tft");
+
+// Where on screen do we locate it?
+#define LIFE_OFFSET_X (SCREEN_W - LIFE_W)
+#define LIFE_OFFSET_Y (SCREEN_H - LIFE_H)
+
+
+
+unsigned char imgbuffer[3*LIFE_W];
+FILE *img;
+
+LocalFileSystem local("local"); //file system
+Serial pc(USBTX,USBRX); // for debugging
+
+
+int msDelay = 1000;     //delay between frames
+
+void CheckForUserInteraction(void);
+void genrand(); //random start
+void genglidergun(); //glider gun
+void genglider(); //glider
+void genship1(); //light weight ship
+void genBMP(); //from image
+void gentest();
+void genBlinker();
+
+void ScreenUpdate()   //print the results from the new array
+{
+    lcd.window(LIFE_OFFSET_X, LIFE_OFFSET_Y, LIFE_W, LIFE_H);
+    lcd._StartGraphicsStream();
+    //pc.printf("ScreenUpdate\r\n");
+    for (int j = 0; j < LIFE_H; j++) {
+        for (int i = 0; i < LIFE_W; i++) {
+            Life::ValueOfLife lifeState = life.getbit(i,j);
+            //Life::ValueOfLife nextState = life.getbit(i,j,1);
+            //pc.printf("%d%d ", lifeState, nextState);
+            switch (lifeState) {
+                case Life::dead:
+                    lcd._putp(Black);
+                    break;
+                case Life::dying:
+                    lcd._putp(RGB(64,0,0));
+                    break;
+                case Life::living:
+                    lcd._putp(Charcoal);
+                    break;
+                case Life::birthing:
+                    lcd._putp(Blue);
+                    break;
+                default:
+                    lcd._putp(Orange);
+                    ERR(" lifeState = %d\r\n", lifeState);
+                    break;
+            }
+        }
+        //pc.printf("\r\n");
+    }
+    //pc.printf("\r\n");
+    lcd._EndGraphicsStream();
+    lcd.WindowMax();
+}
+
+int main()
+{
+    pc.baud(460800);    // I like a snappy terminal, so crank it up!
+    pc.printf("\r\nConway's Game of Life - Build " __DATE__ " " __TIME__ "\r\n");
+
+    lcd.frequency(5000000);
+    lcd.puts("Welcome to Conway's Game of Life\r\n\r\n");
+    INFO("Destroy all life");
+    life.DestroyAllLife();
+    INFO("Life destroyed");
+
+    //pc.printf("choice value = %d\n\r",choice); //for debugging
+    lcd.puts("Please Select Starting Configuration:\r\n");
+    lcd.puts(" 0 = Glider     1 = Random\r\n"
+             " 2 = Ship       3 = Glider Gun\r\n"
+             " 4 = BMP image  5 = Blinker\r\n"
+             " t = test\r\n"
+             " r = reset\r\n"
+             );
+    
+    // Frame the life map
+    lcd.rect(LIFE_OFFSET_X-1,LIFE_OFFSET_Y-1,LIFE_OFFSET_X+LIFE_W,LIFE_OFFSET_Y+LIFE_H,Red);
+    lcd.foreground(Blue);
+    int choice = pc.getc();
+
+    switch ( choice ) {
+        case '0':
+            lcd.puts(">Glider!\r\n");
+            genglider();
+            break;
+        case '1':
+            lcd.puts(">Random!\r\n");
+            genrand();
+            break;
+        case '2':
+            lcd.puts(">Ship!\r\n");
+            genship1();
+            break;
+        case '3':
+            lcd.puts(">Glider Gun!\r\n");
+            genglidergun();
+            break;
+        case '4':
+            lcd.puts(">BMP image!\r\n");
+            genBMP();
+            break;
+        case '5':
+            lcd.puts(">Blinker!\r\n");
+            genBlinker();
+            break;
+        case 't':
+            lcd.puts(">test!\r\n");
+            gentest();
+            break;
+    }
+    lcd.puts("\r\nChange Speed:\r\n"
+             " +   = faster\r\n"
+             " -   = slower\r\n"
+             " 0-9 = updates/sec\r\n"
+             );
+
+    ScreenUpdate();
+    wait(1); //See the initial configuration
+    
+    while(1) {
+        CheckForUserInteraction();
+        if (msDelay >= 0) {
+            static uint16_t toggle = 0;
+            
+            if ((++toggle & 1) == 0) {
+                life.GenerationStep();
+            } else {
+                life.UpdateLifeCycle();
+            }
+            ScreenUpdate();
+            wait_ms(msDelay);
+        }
+    }
+}
+
+void CheckForUserInteraction(void)
+{
+    while (pc.readable()) {
+        int c = pc.getc();
+        if (c == '+' && msDelay >= 0)
+            msDelay -= 10;
+        else if (c == '-' && msDelay < 1000)
+            msDelay += 10;
+        else if (c >= '0' && c <= '9') {
+            if (c == '0')
+                msDelay = -1;
+            else
+                msDelay = 10 * ((1000 / (c - '0'))/10);
+        } else if (c == 'r')
+            mbed_reset();
+        lcd.locate(49, 0);
+        if (msDelay < 0) {
+            msDelay = -10;
+            lcd.printf("Paused      ");
+        } else {
+            lcd.printf("Delay %4d", msDelay);
+        }
+    }
+}
+
+
+void genBlinker()
+{
+    life.setbit(1,1, Life::living);
+    life.setbit(1,2, Life::living);
+    life.setbit(1,3, Life::living);
+}
+
+void gentest()
+{
+    // Point
+    life.setbit(6,3, Life::living);
+    // Block
+    life.setbit(1,1, Life::living);
+    life.setbit(1,2, Life::living);
+    life.setbit(2,1, Life::living);
+    life.setbit(2,2, Life::living);
+    // Beehive
+    life.setbit(6,1, Life::living);
+    life.setbit(7,1, Life::living);
+    life.setbit(5,2, Life::living);
+    life.setbit(8,2, Life::living);
+    life.setbit(6,3, Life::living);
+    life.setbit(7,3, Life::living);
+    // Blinker
+    life.setbit(11,2, Life::living);
+    life.setbit(12,2, Life::living);
+    life.setbit(13,2, Life::living);
+    // Glider
+    //  x
+    //   x
+    // xxx
+    life.setbit(2,10, Life::living);
+    life.setbit(3,11, Life::living);
+    life.setbit(1,12, Life::living);
+    life.setbit(2,12, Life::living);
+    life.setbit(3,12, Life::living);    
+}
+
+
+void genrand()
+{
+    for (int i = 0; i < LIFE_W; i++) { //loop through each cell
+        for (int j = 0; j < LIFE_H; j++) {
+            if (rand() & 1) { //50% chance
+                life.setbit(i,j, Life::living);
+            }
+        }
+    }
+}
+
+void genBMP()
+{
+    for (int i = 0; i < LIFE_W; i++) {
+        img = fopen("/local/TESTIM~1.BMP", "rb");
+        fseek (img , 54 + (LIFE_W*i*3) , SEEK_SET);
+        fread(imgbuffer, (LIFE_W*3), 1, img);
+        fclose(img);
+        for (int j = 0; j < LIFE_H; j++) {
+            int red = imgbuffer[j*3];
+            if (red == 0) {
+                life.setbit(j, LIFE_H - 1 - i, Life::living);
+            }
+        }
+    }
+}
+
+
+void genglider()   //set certain pixels
+{
+    life.setbit(0,0, Life::living);
+    life.setbit(1,1, Life::living);
+    life.setbit(1,2, Life::living);
+    life.setbit(2,0, Life::living);
+    life.setbit(2,1, Life::living);    
+}
+
+void genglidergun()   //set certain pixels
+{
+    life.setbit(0,7, Life::living); //gun
+    life.setbit(0,8, Life::living);
+    life.setbit(1,7, Life::living);
+    life.setbit(1,8, Life::living);
+    life.setbit(8,8, Life::living);
+    life.setbit(8,9, Life::living);
+    life.setbit(9,7, Life::living);
+    life.setbit(9,9, Life::living);
+    life.setbit(10,7, Life::living);
+    life.setbit(10,8, Life::living);
+    life.setbit(16,9, Life::living);
+    life.setbit(16,10, Life::living);
+    life.setbit(16,11, Life::living);
+    life.setbit(17,9, Life::living);
+    life.setbit(18,10, Life::living);
+    life.setbit(22,6, Life::living);
+    life.setbit(22,7, Life::living);
+    life.setbit(23,5, Life::living);
+    life.setbit(23,7, Life::living);
+    life.setbit(24,5, Life::living);
+    life.setbit(24,6, Life::living);
+    life.setbit(24,17, Life::living);
+    life.setbit(24,18, Life::living);
+    life.setbit(25,17, Life::living);
+    life.setbit(25,19, Life::living);
+    life.setbit(26,17, Life::living);
+    life.setbit(34,5, Life::living);
+    life.setbit(34,6, Life::living);
+    life.setbit(35,5, Life::living);
+    life.setbit(35,6, Life::living);
+    life.setbit(35,12, Life::living);
+    life.setbit(35,13, Life::living);
+    life.setbit(35,14, Life::living);
+    life.setbit(36,12, Life::living);
+    life.setbit(37,13, Life::living);
+
+    life.setbit(50,38, Life::living); //eater
+    life.setbit(51,38, Life::living);
+    life.setbit(50,39, Life::living);
+    life.setbit(52,39, Life::living);
+    life.setbit(52,40, Life::living);
+    life.setbit(52,41, Life::living);
+    life.setbit(53,41, Life::living);
+}
+
+void genship1()   //set certain pixels
+{
+    life.setbit(10,10, Life::living);
+    life.setbit(13,10, Life::living);
+    life.setbit(14,11, Life::living);
+    life.setbit(10,12, Life::living);
+    life.setbit(14,12, Life::living);
+    life.setbit(11,13, Life::living);
+    life.setbit(12,13, Life::living);
+    life.setbit(13,13, Life::living);
+    life.setbit(14,13, Life::living);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Apr 16 22:26:14 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/8e73be2a2ac1
\ No newline at end of file