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

Dependencies:   LifeRules mbed RA8875

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // game of life implementation inspired by this forum thread
00002 // http://mbed.org/forum/helloworld/topic/4822/
00003 // 
00004 #include "mbed.h"       // v122
00005 #include "RA8875.h"     // v126
00006 #include "LifeRules.h"  // v3
00007 
00008 // These two defines can be enabled, or commented out
00009 #define BIG_SCREEN
00010 #define CAP_TOUCH
00011 #define LCD_C 16         // color - bits per pixel
00012 
00013 #ifdef CAP_TOUCH
00014 RA8875 lcd(p5,p6,p7,p12,NC, p9,p10,p13, "tft"); // MOSI,MISO,SCK,/ChipSelect,/reset, SDA,SCL,/IRQ, name
00015 #else
00016 RA8875 lcd(p5,p6,p7,p12,NC, "tft");             //MOSI, MISO, SCK, /ChipSelect, /reset, name
00017 LocalFileSystem local("local");                     // access to calibration file for resistive touch.
00018 #endif
00019 
00020 #ifdef BIG_SCREEN
00021     #define LCD_W 800
00022     #define LCD_H 480
00023 #else
00024     #define LCD_W 480
00025     #define LCD_H 272
00026 #endif
00027 
00028 
00029 // Define the life-map size
00030 #define LIFE_W 150
00031 #define LIFE_H 100
00032 #define LIFE_C 2          /* 1 = monochrome, 2 = color */
00033 #define LIFE_Z 2          /* Zoom factor */
00034 
00035 // Try to check if there is enough memory (for LPC1768)
00036 #if LIFE_W * LIFE_H * LIFE_C * 2 / 8 > 0x8000
00037 #error "Sorry, but there isn't this much memory on an LPC1768"
00038 #endif
00039 
00040 extern "C" void mbed_reset();
00041 
00042 //#define DEBUG "main"
00043 // ...
00044 // INFO("Stuff to show %d", var); // new-line is automatically appended
00045 //
00046 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
00047 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00048 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00049 #define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00050 #else
00051 #define INFO(x, ...)
00052 #define WARN(x, ...)
00053 #define ERR(x, ...)
00054 #endif
00055 
00056 
00057 #if LIFE_C == 2
00058 #define LIFE_CLR Life::color
00059 #else
00060 #define LIFE_CLR Life::monochrome
00061 #endif
00062 
00063 Life life(LIFE_W, LIFE_H, LIFE_CLR);
00064 
00065 // Where on screen do we locate it?
00066 #if LIFE_W * LIFE_Z < LCD_W
00067 #define H_OFFSET -1
00068 #else
00069 #define H_OFFSET 0
00070 #endif
00071 
00072 #if LIFE_H * LIFE_Z < LCD_H
00073 #define V_OFFSET -1
00074 #else
00075 #define V_OFFSET 0
00076 #endif
00077 
00078 #define LIFE_OFFSET_X (LCD_W - (LIFE_W * LIFE_Z) + H_OFFSET)
00079 #define LIFE_OFFSET_Y (LCD_H - (LIFE_H * LIFE_Z) + V_OFFSET)
00080 
00081 unsigned char imgbuffer[3*LIFE_W]; // from forum thread...
00082 FILE *img;
00083 
00084 Serial pc(USBTX,USBRX); // for debugging
00085 
00086 int msDelay = 1000;     //delay between frames
00087 
00088 void CheckForUserInteraction(void);
00089 void genrand(); //random start
00090 void genglidergun(); //glider gun
00091 void genglider(); //glider
00092 void genship1(); //light weight ship
00093 void genBMP(); //from image
00094 void gentest();
00095 void genBlinker();
00096 
00097 void ScreenUpdate()
00098 {
00099     lcd.SetWindow(LIFE_OFFSET_X, LIFE_OFFSET_Y, LIFE_W * LIFE_Z, LIFE_H * LIFE_Z);
00100     lcd.SetGraphicsCursor(LIFE_OFFSET_X+1, LIFE_OFFSET_Y+1);
00101     pc.printf("window(%d,%d, %d,%d)\r\n", LIFE_OFFSET_X, LIFE_OFFSET_Y, LIFE_W * LIFE_Z, LIFE_H * LIFE_Z);
00102     lcd._StartGraphicsStream();
00103     for (int j = 0; j < LIFE_H; j++) {
00104         for (int Zx = 0; Zx < LIFE_Z; Zx++) {
00105             for (int i = 0; i < LIFE_W; i++) {
00106                 Life::ValueOfLife lifeState = life.getbit(i,j);
00107                 color_t p;
00108                 switch (lifeState) {
00109                     case Life::dead:
00110                         p = RGB(0,0,0);
00111                         break;
00112                     case Life::dying:
00113                         p = RGB(192,0,0);
00114                         break;
00115                     case Life::living:
00116                         p = RGB(64,255,64);
00117                         break;
00118                     case Life::birthing:
00119                         p = RGB(0,0,192);
00120                         break;
00121                     default:
00122                         p = RGB(192,192,0); // Should never see this one...
00123                         ERR(" lifeState = %d\r\n", lifeState);
00124                         break;
00125                 }
00126                 for (int Zy = 0; Zy < LIFE_Z; Zy++) {
00127                     lcd._putp(p);
00128                 }
00129             }
00130         }
00131     }
00132     lcd._EndGraphicsStream();
00133     lcd.SetWindow();
00134 }
00135 
00136 int GetScreenCapture(void)
00137 {
00138     char fqfn[50];
00139     int i = 0;
00140     
00141     pc.printf("Screen Capture... ");
00142     for (i=1; i< 100; i++) {
00143         snprintf(fqfn, sizeof(fqfn), "/local/Screen%02d.bmp", i);
00144         FILE * fh = fopen(fqfn, "rb");
00145         if (!fh) {
00146             lcd.PrintScreen(0,0,LCD_W,LCD_H,fqfn);
00147             pc.printf(" as /local/Screen%02d.bmp\r\n", i);
00148             return i;
00149         } else {
00150             fclose(fh);     // close this and try the next
00151         }
00152     }
00153     return 0;
00154 }
00155 
00156 
00157 int main()
00158 {
00159     pc.baud(460800);    // I like a snappy terminal, so crank it up!
00160     pc.printf("\r\nConway's Game of Life - Build " __DATE__ " " __TIME__ "\r\n");
00161 
00162     lcd.init(LCD_W, LCD_H, LCD_C);
00163     lcd.Backlight(0.5f);
00164 
00165     //lcd.frequency(5000000);
00166     lcd.puts("Welcome to Conway's Game of Life\r\n\r\n");
00167     INFO("Destroy all life");
00168     life.DestroyAllLife();
00169     INFO("Life destroyed");
00170 
00171     lcd.foreground(RGB(255,255,255));
00172     
00173     //pc.printf("choice value = %d\n\r",choice); //for debugging
00174     lcd.puts("Please Select Starting Configuration:\r\n");
00175     lcd.puts(" 0 = Glider     1 = Random\r\n"
00176              " 2 = Ship       3 = Glider Gun\r\n"
00177              " 4 = BMP image  5 = Blinker\r\n"
00178              " t = test       \r\n"
00179              " r = reset\r\n"
00180              );
00181     
00182     // Frame the life map
00183     lcd.rect(LIFE_OFFSET_X-1,LIFE_OFFSET_Y-1,LIFE_OFFSET_X+LIFE_W*LIFE_Z,LIFE_OFFSET_Y+LIFE_H*LIFE_Z,Red);
00184     lcd.foreground(Blue);
00185     int choice = pc.getc();
00186 
00187     switch ( choice ) {
00188         case '0':
00189             lcd.puts(">Glider!\r\n");
00190             genglider();
00191             break;
00192         case '1':
00193             lcd.puts(">Random!\r\n");
00194             genrand();
00195             break;
00196         case '2':
00197             lcd.puts(">Ship!\r\n");
00198             genship1();
00199             break;
00200         case '3':
00201             lcd.puts(">Glider Gun!\r\n");
00202             genglidergun();
00203             break;
00204         case '4':
00205             lcd.puts(">BMP image!\r\n");
00206             genBMP();
00207             break;
00208         case '5':
00209             lcd.puts(">Blinker!\r\n");
00210             genBlinker();
00211             break;
00212         case 't':
00213             lcd.puts(">test!\r\n");
00214             gentest();
00215             break;
00216     }
00217     lcd.puts("\r\nRuntime Menu:\r\n"
00218              " p   = PrintScreen\r\n"
00219              " +   = faster\r\n"
00220              " -   = slower\r\n"
00221              " 0-9 = updates/sec\r\n"
00222              );
00223 
00224     ScreenUpdate();
00225     wait(1);
00226     
00227     while(1) {
00228         CheckForUserInteraction();
00229         if (msDelay >= 0) {
00230             static uint16_t toggle = 0;
00231             
00232             if ((++toggle & 1) == 0) {
00233                 life.GenerationStep();
00234             } else {
00235                 life.UpdateLifeCycle();
00236             }
00237             ScreenUpdate();
00238             wait_ms(msDelay);
00239         }
00240     }
00241 }
00242 
00243 void CheckForUserInteraction(void)
00244 {
00245     while (pc.readable()) {
00246         int c = pc.getc();
00247         if (c == '+' && msDelay >= 0)
00248             msDelay -= 10;
00249         else if (c == '-' && msDelay < 1000)
00250             msDelay += 10;
00251         else if (c >= '0' && c <= '9') {
00252             if (c == '0')
00253                 msDelay = -1;
00254             else
00255                 msDelay = 10 * ((1000 / (c - '0'))/10);
00256         } else if (c == 'r')
00257             mbed_reset();
00258         else if (c == 'p')
00259             GetScreenCapture();
00260         lcd.locate(49, 0);
00261         if (msDelay < 0) {
00262             msDelay = -10;
00263             lcd.printf("Paused      ");
00264         } else {
00265             lcd.printf("Delay %4d", msDelay);
00266         }
00267     }
00268 }
00269 
00270 
00271 void genBlinker()
00272 {
00273     life.setbit(1,1, Life::living);
00274     life.setbit(1,2, Life::living);
00275     life.setbit(1,3, Life::living);
00276 }
00277 
00278 void gentest()
00279 {
00280     // Point
00281     life.setbit(6,3, Life::living);
00282     // Block
00283     life.setbit(1,1, Life::living);
00284     life.setbit(1,2, Life::living);
00285     life.setbit(2,1, Life::living);
00286     life.setbit(2,2, Life::living);
00287     // Beehive
00288     life.setbit(6,1, Life::living);
00289     life.setbit(7,1, Life::living);
00290     life.setbit(5,2, Life::living);
00291     life.setbit(8,2, Life::living);
00292     life.setbit(6,3, Life::living);
00293     life.setbit(7,3, Life::living);
00294     // Blinker
00295     life.setbit(11,2, Life::living);
00296     life.setbit(12,2, Life::living);
00297     life.setbit(13,2, Life::living);
00298     // Glider
00299     //  x
00300     //   x
00301     // xxx
00302     life.setbit(2,10, Life::living);
00303     life.setbit(3,11, Life::living);
00304     life.setbit(1,12, Life::living);
00305     life.setbit(2,12, Life::living);
00306     life.setbit(3,12, Life::living);    
00307 }
00308 
00309 
00310 void genrand()
00311 {
00312     for (int i = 0; i < LIFE_W; i++) { //loop through each cell
00313         for (int j = 0; j < LIFE_H; j++) {
00314             if (rand() & 1) { //50% chance
00315                 life.setbit(i,j, Life::living);
00316             }
00317         }
00318     }
00319 }
00320 
00321 void genBMP()
00322 {
00323     for (int i = 0; i < LIFE_W; i++) {
00324         img = fopen("/local/TESTIM~1.BMP", "rb");
00325         fseek (img , 54 + (LIFE_W*i*3) , SEEK_SET);
00326         fread(imgbuffer, (LIFE_W*3), 1, img);
00327         fclose(img);
00328         for (int j = 0; j < LIFE_H; j++) {
00329             int red = imgbuffer[j*3];
00330             if (red == 0) {
00331                 life.setbit(j, LIFE_H - 1 - i, Life::living);
00332             }
00333         }
00334     }
00335 }
00336 
00337 
00338 void genglider()   //set certain pixels
00339 {
00340     life.setbit(0,0, Life::living);
00341     life.setbit(1,1, Life::living);
00342     life.setbit(1,2, Life::living);
00343     life.setbit(2,0, Life::living);
00344     life.setbit(2,1, Life::living);    
00345 }
00346 
00347 void genglidergun()   //set certain pixels
00348 {
00349     life.setbit(0,7, Life::living); //gun
00350     life.setbit(0,8, Life::living);
00351     life.setbit(1,7, Life::living);
00352     life.setbit(1,8, Life::living);
00353     life.setbit(8,8, Life::living);
00354     life.setbit(8,9, Life::living);
00355     life.setbit(9,7, Life::living);
00356     life.setbit(9,9, Life::living);
00357     life.setbit(10,7, Life::living);
00358     life.setbit(10,8, Life::living);
00359     life.setbit(16,9, Life::living);
00360     life.setbit(16,10, Life::living);
00361     life.setbit(16,11, Life::living);
00362     life.setbit(17,9, Life::living);
00363     life.setbit(18,10, Life::living);
00364     life.setbit(22,6, Life::living);
00365     life.setbit(22,7, Life::living);
00366     life.setbit(23,5, Life::living);
00367     life.setbit(23,7, Life::living);
00368     life.setbit(24,5, Life::living);
00369     life.setbit(24,6, Life::living);
00370     life.setbit(24,17, Life::living);
00371     life.setbit(24,18, Life::living);
00372     life.setbit(25,17, Life::living);
00373     life.setbit(25,19, Life::living);
00374     life.setbit(26,17, Life::living);
00375     life.setbit(34,5, Life::living);
00376     life.setbit(34,6, Life::living);
00377     life.setbit(35,5, Life::living);
00378     life.setbit(35,6, Life::living);
00379     life.setbit(35,12, Life::living);
00380     life.setbit(35,13, Life::living);
00381     life.setbit(35,14, Life::living);
00382     life.setbit(36,12, Life::living);
00383     life.setbit(37,13, Life::living);
00384 
00385     life.setbit(50,38, Life::living); //eater
00386     life.setbit(51,38, Life::living);
00387     life.setbit(50,39, Life::living);
00388     life.setbit(52,39, Life::living);
00389     life.setbit(52,40, Life::living);
00390     life.setbit(52,41, Life::living);
00391     life.setbit(53,41, Life::living);
00392 }
00393 
00394 void genship1()   //set certain pixels
00395 {
00396     life.setbit(10,10, Life::living);
00397     life.setbit(13,10, Life::living);
00398     life.setbit(14,11, Life::living);
00399     life.setbit(10,12, Life::living);
00400     life.setbit(14,12, Life::living);
00401     life.setbit(11,13, Life::living);
00402     life.setbit(12,13, Life::living);
00403     life.setbit(13,13, Life::living);
00404     life.setbit(14,13, Life::living);
00405 }
00406 
00407 
00408