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.

Committer:
WiredHome
Date:
Wed Apr 23 22:57:50 2014 +0000
Revision:
2:f4aece10ba62
Parent:
0:d268818ad088
Child:
3:1139b132f983
Cleaned up the code, permit either monochrome or color display, and compile time defined resolution for the display.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 2:f4aece10ba62 1 // game of life implementation inspired by this forum thread
WiredHome 2:f4aece10ba62 2 // http://mbed.org/forum/helloworld/topic/4822/
WiredHome 2:f4aece10ba62 3 //
WiredHome 0:d268818ad088 4 #include "mbed.h"
WiredHome 0:d268818ad088 5 #include "RA8875.h"
WiredHome 0:d268818ad088 6 #include "LifeRules.h"
WiredHome 0:d268818ad088 7
WiredHome 0:d268818ad088 8 // Define the life-map size
WiredHome 2:f4aece10ba62 9 #define LIFE_W 300
WiredHome 2:f4aece10ba62 10 #define LIFE_H 200
WiredHome 2:f4aece10ba62 11 #define LIFE_C Life::color
WiredHome 0:d268818ad088 12
WiredHome 0:d268818ad088 13 // Define the screen size
WiredHome 0:d268818ad088 14 #define SCREEN_W 480
WiredHome 0:d268818ad088 15 #define SCREEN_H 272
WiredHome 0:d268818ad088 16
WiredHome 0:d268818ad088 17 extern "C" void mbed_reset();
WiredHome 0:d268818ad088 18
WiredHome 0:d268818ad088 19 //#define DEBUG "main"
WiredHome 0:d268818ad088 20 // ...
WiredHome 0:d268818ad088 21 // INFO("Stuff to show %d", var); // new-line is automatically appended
WiredHome 0:d268818ad088 22 //
WiredHome 0:d268818ad088 23 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 0:d268818ad088 24 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:d268818ad088 25 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:d268818ad088 26 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:d268818ad088 27 #else
WiredHome 0:d268818ad088 28 #define INFO(x, ...)
WiredHome 0:d268818ad088 29 #define WARN(x, ...)
WiredHome 0:d268818ad088 30 #define ERR(x, ...)
WiredHome 0:d268818ad088 31 #endif
WiredHome 0:d268818ad088 32
WiredHome 0:d268818ad088 33
WiredHome 2:f4aece10ba62 34 Life life(LIFE_W, LIFE_H, LIFE_C);
WiredHome 0:d268818ad088 35
WiredHome 2:f4aece10ba62 36 // NOT USING p21, but the mbed lib v82 does not work if NC is part
WiredHome 2:f4aece10ba62 37 // of a constructor. See thread http://mbed.org/forum/bugs-suggestions/topic/4859/
WiredHome 2:f4aece10ba62 38 RA8875 lcd(p5, p6, p7, p12, p21, "tft");
WiredHome 0:d268818ad088 39
WiredHome 0:d268818ad088 40 // Where on screen do we locate it?
WiredHome 0:d268818ad088 41 #define LIFE_OFFSET_X (SCREEN_W - LIFE_W)
WiredHome 0:d268818ad088 42 #define LIFE_OFFSET_Y (SCREEN_H - LIFE_H)
WiredHome 0:d268818ad088 43
WiredHome 0:d268818ad088 44
WiredHome 0:d268818ad088 45
WiredHome 0:d268818ad088 46 unsigned char imgbuffer[3*LIFE_W];
WiredHome 0:d268818ad088 47 FILE *img;
WiredHome 0:d268818ad088 48
WiredHome 0:d268818ad088 49 LocalFileSystem local("local"); //file system
WiredHome 0:d268818ad088 50 Serial pc(USBTX,USBRX); // for debugging
WiredHome 0:d268818ad088 51
WiredHome 0:d268818ad088 52
WiredHome 0:d268818ad088 53 int msDelay = 1000; //delay between frames
WiredHome 0:d268818ad088 54
WiredHome 0:d268818ad088 55 void CheckForUserInteraction(void);
WiredHome 0:d268818ad088 56 void genrand(); //random start
WiredHome 0:d268818ad088 57 void genglidergun(); //glider gun
WiredHome 0:d268818ad088 58 void genglider(); //glider
WiredHome 0:d268818ad088 59 void genship1(); //light weight ship
WiredHome 0:d268818ad088 60 void genBMP(); //from image
WiredHome 0:d268818ad088 61 void gentest();
WiredHome 0:d268818ad088 62 void genBlinker();
WiredHome 0:d268818ad088 63
WiredHome 2:f4aece10ba62 64 void ScreenUpdate()
WiredHome 0:d268818ad088 65 {
WiredHome 0:d268818ad088 66 lcd.window(LIFE_OFFSET_X, LIFE_OFFSET_Y, LIFE_W, LIFE_H);
WiredHome 0:d268818ad088 67 lcd._StartGraphicsStream();
WiredHome 0:d268818ad088 68 for (int j = 0; j < LIFE_H; j++) {
WiredHome 0:d268818ad088 69 for (int i = 0; i < LIFE_W; i++) {
WiredHome 0:d268818ad088 70 Life::ValueOfLife lifeState = life.getbit(i,j);
WiredHome 0:d268818ad088 71 switch (lifeState) {
WiredHome 0:d268818ad088 72 case Life::dead:
WiredHome 0:d268818ad088 73 lcd._putp(Black);
WiredHome 0:d268818ad088 74 break;
WiredHome 0:d268818ad088 75 case Life::dying:
WiredHome 0:d268818ad088 76 lcd._putp(RGB(64,0,0));
WiredHome 0:d268818ad088 77 break;
WiredHome 0:d268818ad088 78 case Life::living:
WiredHome 0:d268818ad088 79 lcd._putp(Charcoal);
WiredHome 0:d268818ad088 80 break;
WiredHome 0:d268818ad088 81 case Life::birthing:
WiredHome 0:d268818ad088 82 lcd._putp(Blue);
WiredHome 0:d268818ad088 83 break;
WiredHome 0:d268818ad088 84 default:
WiredHome 0:d268818ad088 85 lcd._putp(Orange);
WiredHome 0:d268818ad088 86 ERR(" lifeState = %d\r\n", lifeState);
WiredHome 0:d268818ad088 87 break;
WiredHome 0:d268818ad088 88 }
WiredHome 0:d268818ad088 89 }
WiredHome 0:d268818ad088 90 }
WiredHome 0:d268818ad088 91 lcd._EndGraphicsStream();
WiredHome 0:d268818ad088 92 lcd.WindowMax();
WiredHome 0:d268818ad088 93 }
WiredHome 0:d268818ad088 94
WiredHome 0:d268818ad088 95 int main()
WiredHome 0:d268818ad088 96 {
WiredHome 0:d268818ad088 97 pc.baud(460800); // I like a snappy terminal, so crank it up!
WiredHome 0:d268818ad088 98 pc.printf("\r\nConway's Game of Life - Build " __DATE__ " " __TIME__ "\r\n");
WiredHome 0:d268818ad088 99
WiredHome 0:d268818ad088 100 lcd.frequency(5000000);
WiredHome 0:d268818ad088 101 lcd.puts("Welcome to Conway's Game of Life\r\n\r\n");
WiredHome 0:d268818ad088 102 INFO("Destroy all life");
WiredHome 0:d268818ad088 103 life.DestroyAllLife();
WiredHome 0:d268818ad088 104 INFO("Life destroyed");
WiredHome 0:d268818ad088 105
WiredHome 0:d268818ad088 106 //pc.printf("choice value = %d\n\r",choice); //for debugging
WiredHome 0:d268818ad088 107 lcd.puts("Please Select Starting Configuration:\r\n");
WiredHome 0:d268818ad088 108 lcd.puts(" 0 = Glider 1 = Random\r\n"
WiredHome 0:d268818ad088 109 " 2 = Ship 3 = Glider Gun\r\n"
WiredHome 0:d268818ad088 110 " 4 = BMP image 5 = Blinker\r\n"
WiredHome 0:d268818ad088 111 " t = test\r\n"
WiredHome 0:d268818ad088 112 " r = reset\r\n"
WiredHome 0:d268818ad088 113 );
WiredHome 0:d268818ad088 114
WiredHome 0:d268818ad088 115 // Frame the life map
WiredHome 0:d268818ad088 116 lcd.rect(LIFE_OFFSET_X-1,LIFE_OFFSET_Y-1,LIFE_OFFSET_X+LIFE_W,LIFE_OFFSET_Y+LIFE_H,Red);
WiredHome 0:d268818ad088 117 lcd.foreground(Blue);
WiredHome 0:d268818ad088 118 int choice = pc.getc();
WiredHome 0:d268818ad088 119
WiredHome 0:d268818ad088 120 switch ( choice ) {
WiredHome 0:d268818ad088 121 case '0':
WiredHome 0:d268818ad088 122 lcd.puts(">Glider!\r\n");
WiredHome 0:d268818ad088 123 genglider();
WiredHome 0:d268818ad088 124 break;
WiredHome 0:d268818ad088 125 case '1':
WiredHome 0:d268818ad088 126 lcd.puts(">Random!\r\n");
WiredHome 0:d268818ad088 127 genrand();
WiredHome 0:d268818ad088 128 break;
WiredHome 0:d268818ad088 129 case '2':
WiredHome 0:d268818ad088 130 lcd.puts(">Ship!\r\n");
WiredHome 0:d268818ad088 131 genship1();
WiredHome 0:d268818ad088 132 break;
WiredHome 0:d268818ad088 133 case '3':
WiredHome 0:d268818ad088 134 lcd.puts(">Glider Gun!\r\n");
WiredHome 0:d268818ad088 135 genglidergun();
WiredHome 0:d268818ad088 136 break;
WiredHome 0:d268818ad088 137 case '4':
WiredHome 0:d268818ad088 138 lcd.puts(">BMP image!\r\n");
WiredHome 0:d268818ad088 139 genBMP();
WiredHome 0:d268818ad088 140 break;
WiredHome 0:d268818ad088 141 case '5':
WiredHome 0:d268818ad088 142 lcd.puts(">Blinker!\r\n");
WiredHome 0:d268818ad088 143 genBlinker();
WiredHome 0:d268818ad088 144 break;
WiredHome 0:d268818ad088 145 case 't':
WiredHome 0:d268818ad088 146 lcd.puts(">test!\r\n");
WiredHome 0:d268818ad088 147 gentest();
WiredHome 0:d268818ad088 148 break;
WiredHome 0:d268818ad088 149 }
WiredHome 0:d268818ad088 150 lcd.puts("\r\nChange Speed:\r\n"
WiredHome 0:d268818ad088 151 " + = faster\r\n"
WiredHome 0:d268818ad088 152 " - = slower\r\n"
WiredHome 0:d268818ad088 153 " 0-9 = updates/sec\r\n"
WiredHome 0:d268818ad088 154 );
WiredHome 0:d268818ad088 155
WiredHome 0:d268818ad088 156 ScreenUpdate();
WiredHome 2:f4aece10ba62 157 wait(1);
WiredHome 0:d268818ad088 158
WiredHome 0:d268818ad088 159 while(1) {
WiredHome 0:d268818ad088 160 CheckForUserInteraction();
WiredHome 0:d268818ad088 161 if (msDelay >= 0) {
WiredHome 0:d268818ad088 162 static uint16_t toggle = 0;
WiredHome 0:d268818ad088 163
WiredHome 0:d268818ad088 164 if ((++toggle & 1) == 0) {
WiredHome 0:d268818ad088 165 life.GenerationStep();
WiredHome 0:d268818ad088 166 } else {
WiredHome 0:d268818ad088 167 life.UpdateLifeCycle();
WiredHome 0:d268818ad088 168 }
WiredHome 0:d268818ad088 169 ScreenUpdate();
WiredHome 0:d268818ad088 170 wait_ms(msDelay);
WiredHome 0:d268818ad088 171 }
WiredHome 0:d268818ad088 172 }
WiredHome 0:d268818ad088 173 }
WiredHome 0:d268818ad088 174
WiredHome 0:d268818ad088 175 void CheckForUserInteraction(void)
WiredHome 0:d268818ad088 176 {
WiredHome 0:d268818ad088 177 while (pc.readable()) {
WiredHome 0:d268818ad088 178 int c = pc.getc();
WiredHome 0:d268818ad088 179 if (c == '+' && msDelay >= 0)
WiredHome 0:d268818ad088 180 msDelay -= 10;
WiredHome 0:d268818ad088 181 else if (c == '-' && msDelay < 1000)
WiredHome 0:d268818ad088 182 msDelay += 10;
WiredHome 0:d268818ad088 183 else if (c >= '0' && c <= '9') {
WiredHome 0:d268818ad088 184 if (c == '0')
WiredHome 0:d268818ad088 185 msDelay = -1;
WiredHome 0:d268818ad088 186 else
WiredHome 0:d268818ad088 187 msDelay = 10 * ((1000 / (c - '0'))/10);
WiredHome 0:d268818ad088 188 } else if (c == 'r')
WiredHome 0:d268818ad088 189 mbed_reset();
WiredHome 0:d268818ad088 190 lcd.locate(49, 0);
WiredHome 0:d268818ad088 191 if (msDelay < 0) {
WiredHome 0:d268818ad088 192 msDelay = -10;
WiredHome 0:d268818ad088 193 lcd.printf("Paused ");
WiredHome 0:d268818ad088 194 } else {
WiredHome 0:d268818ad088 195 lcd.printf("Delay %4d", msDelay);
WiredHome 0:d268818ad088 196 }
WiredHome 0:d268818ad088 197 }
WiredHome 0:d268818ad088 198 }
WiredHome 0:d268818ad088 199
WiredHome 0:d268818ad088 200
WiredHome 0:d268818ad088 201 void genBlinker()
WiredHome 0:d268818ad088 202 {
WiredHome 0:d268818ad088 203 life.setbit(1,1, Life::living);
WiredHome 0:d268818ad088 204 life.setbit(1,2, Life::living);
WiredHome 0:d268818ad088 205 life.setbit(1,3, Life::living);
WiredHome 0:d268818ad088 206 }
WiredHome 0:d268818ad088 207
WiredHome 0:d268818ad088 208 void gentest()
WiredHome 0:d268818ad088 209 {
WiredHome 0:d268818ad088 210 // Point
WiredHome 0:d268818ad088 211 life.setbit(6,3, Life::living);
WiredHome 0:d268818ad088 212 // Block
WiredHome 0:d268818ad088 213 life.setbit(1,1, Life::living);
WiredHome 0:d268818ad088 214 life.setbit(1,2, Life::living);
WiredHome 0:d268818ad088 215 life.setbit(2,1, Life::living);
WiredHome 0:d268818ad088 216 life.setbit(2,2, Life::living);
WiredHome 0:d268818ad088 217 // Beehive
WiredHome 0:d268818ad088 218 life.setbit(6,1, Life::living);
WiredHome 0:d268818ad088 219 life.setbit(7,1, Life::living);
WiredHome 0:d268818ad088 220 life.setbit(5,2, Life::living);
WiredHome 0:d268818ad088 221 life.setbit(8,2, Life::living);
WiredHome 0:d268818ad088 222 life.setbit(6,3, Life::living);
WiredHome 0:d268818ad088 223 life.setbit(7,3, Life::living);
WiredHome 0:d268818ad088 224 // Blinker
WiredHome 0:d268818ad088 225 life.setbit(11,2, Life::living);
WiredHome 0:d268818ad088 226 life.setbit(12,2, Life::living);
WiredHome 0:d268818ad088 227 life.setbit(13,2, Life::living);
WiredHome 0:d268818ad088 228 // Glider
WiredHome 0:d268818ad088 229 // x
WiredHome 0:d268818ad088 230 // x
WiredHome 0:d268818ad088 231 // xxx
WiredHome 0:d268818ad088 232 life.setbit(2,10, Life::living);
WiredHome 0:d268818ad088 233 life.setbit(3,11, Life::living);
WiredHome 0:d268818ad088 234 life.setbit(1,12, Life::living);
WiredHome 0:d268818ad088 235 life.setbit(2,12, Life::living);
WiredHome 0:d268818ad088 236 life.setbit(3,12, Life::living);
WiredHome 0:d268818ad088 237 }
WiredHome 0:d268818ad088 238
WiredHome 0:d268818ad088 239
WiredHome 0:d268818ad088 240 void genrand()
WiredHome 0:d268818ad088 241 {
WiredHome 0:d268818ad088 242 for (int i = 0; i < LIFE_W; i++) { //loop through each cell
WiredHome 0:d268818ad088 243 for (int j = 0; j < LIFE_H; j++) {
WiredHome 0:d268818ad088 244 if (rand() & 1) { //50% chance
WiredHome 0:d268818ad088 245 life.setbit(i,j, Life::living);
WiredHome 0:d268818ad088 246 }
WiredHome 0:d268818ad088 247 }
WiredHome 0:d268818ad088 248 }
WiredHome 0:d268818ad088 249 }
WiredHome 0:d268818ad088 250
WiredHome 0:d268818ad088 251 void genBMP()
WiredHome 0:d268818ad088 252 {
WiredHome 0:d268818ad088 253 for (int i = 0; i < LIFE_W; i++) {
WiredHome 0:d268818ad088 254 img = fopen("/local/TESTIM~1.BMP", "rb");
WiredHome 0:d268818ad088 255 fseek (img , 54 + (LIFE_W*i*3) , SEEK_SET);
WiredHome 0:d268818ad088 256 fread(imgbuffer, (LIFE_W*3), 1, img);
WiredHome 0:d268818ad088 257 fclose(img);
WiredHome 0:d268818ad088 258 for (int j = 0; j < LIFE_H; j++) {
WiredHome 0:d268818ad088 259 int red = imgbuffer[j*3];
WiredHome 0:d268818ad088 260 if (red == 0) {
WiredHome 0:d268818ad088 261 life.setbit(j, LIFE_H - 1 - i, Life::living);
WiredHome 0:d268818ad088 262 }
WiredHome 0:d268818ad088 263 }
WiredHome 0:d268818ad088 264 }
WiredHome 0:d268818ad088 265 }
WiredHome 0:d268818ad088 266
WiredHome 0:d268818ad088 267
WiredHome 0:d268818ad088 268 void genglider() //set certain pixels
WiredHome 0:d268818ad088 269 {
WiredHome 0:d268818ad088 270 life.setbit(0,0, Life::living);
WiredHome 0:d268818ad088 271 life.setbit(1,1, Life::living);
WiredHome 0:d268818ad088 272 life.setbit(1,2, Life::living);
WiredHome 0:d268818ad088 273 life.setbit(2,0, Life::living);
WiredHome 0:d268818ad088 274 life.setbit(2,1, Life::living);
WiredHome 0:d268818ad088 275 }
WiredHome 0:d268818ad088 276
WiredHome 0:d268818ad088 277 void genglidergun() //set certain pixels
WiredHome 0:d268818ad088 278 {
WiredHome 0:d268818ad088 279 life.setbit(0,7, Life::living); //gun
WiredHome 0:d268818ad088 280 life.setbit(0,8, Life::living);
WiredHome 0:d268818ad088 281 life.setbit(1,7, Life::living);
WiredHome 0:d268818ad088 282 life.setbit(1,8, Life::living);
WiredHome 0:d268818ad088 283 life.setbit(8,8, Life::living);
WiredHome 0:d268818ad088 284 life.setbit(8,9, Life::living);
WiredHome 0:d268818ad088 285 life.setbit(9,7, Life::living);
WiredHome 0:d268818ad088 286 life.setbit(9,9, Life::living);
WiredHome 0:d268818ad088 287 life.setbit(10,7, Life::living);
WiredHome 0:d268818ad088 288 life.setbit(10,8, Life::living);
WiredHome 0:d268818ad088 289 life.setbit(16,9, Life::living);
WiredHome 0:d268818ad088 290 life.setbit(16,10, Life::living);
WiredHome 0:d268818ad088 291 life.setbit(16,11, Life::living);
WiredHome 0:d268818ad088 292 life.setbit(17,9, Life::living);
WiredHome 0:d268818ad088 293 life.setbit(18,10, Life::living);
WiredHome 0:d268818ad088 294 life.setbit(22,6, Life::living);
WiredHome 0:d268818ad088 295 life.setbit(22,7, Life::living);
WiredHome 0:d268818ad088 296 life.setbit(23,5, Life::living);
WiredHome 0:d268818ad088 297 life.setbit(23,7, Life::living);
WiredHome 0:d268818ad088 298 life.setbit(24,5, Life::living);
WiredHome 0:d268818ad088 299 life.setbit(24,6, Life::living);
WiredHome 0:d268818ad088 300 life.setbit(24,17, Life::living);
WiredHome 0:d268818ad088 301 life.setbit(24,18, Life::living);
WiredHome 0:d268818ad088 302 life.setbit(25,17, Life::living);
WiredHome 0:d268818ad088 303 life.setbit(25,19, Life::living);
WiredHome 0:d268818ad088 304 life.setbit(26,17, Life::living);
WiredHome 0:d268818ad088 305 life.setbit(34,5, Life::living);
WiredHome 0:d268818ad088 306 life.setbit(34,6, Life::living);
WiredHome 0:d268818ad088 307 life.setbit(35,5, Life::living);
WiredHome 0:d268818ad088 308 life.setbit(35,6, Life::living);
WiredHome 0:d268818ad088 309 life.setbit(35,12, Life::living);
WiredHome 0:d268818ad088 310 life.setbit(35,13, Life::living);
WiredHome 0:d268818ad088 311 life.setbit(35,14, Life::living);
WiredHome 0:d268818ad088 312 life.setbit(36,12, Life::living);
WiredHome 0:d268818ad088 313 life.setbit(37,13, Life::living);
WiredHome 0:d268818ad088 314
WiredHome 0:d268818ad088 315 life.setbit(50,38, Life::living); //eater
WiredHome 0:d268818ad088 316 life.setbit(51,38, Life::living);
WiredHome 0:d268818ad088 317 life.setbit(50,39, Life::living);
WiredHome 0:d268818ad088 318 life.setbit(52,39, Life::living);
WiredHome 0:d268818ad088 319 life.setbit(52,40, Life::living);
WiredHome 0:d268818ad088 320 life.setbit(52,41, Life::living);
WiredHome 0:d268818ad088 321 life.setbit(53,41, Life::living);
WiredHome 0:d268818ad088 322 }
WiredHome 0:d268818ad088 323
WiredHome 0:d268818ad088 324 void genship1() //set certain pixels
WiredHome 0:d268818ad088 325 {
WiredHome 0:d268818ad088 326 life.setbit(10,10, Life::living);
WiredHome 0:d268818ad088 327 life.setbit(13,10, Life::living);
WiredHome 0:d268818ad088 328 life.setbit(14,11, Life::living);
WiredHome 0:d268818ad088 329 life.setbit(10,12, Life::living);
WiredHome 0:d268818ad088 330 life.setbit(14,12, Life::living);
WiredHome 0:d268818ad088 331 life.setbit(11,13, Life::living);
WiredHome 0:d268818ad088 332 life.setbit(12,13, Life::living);
WiredHome 0:d268818ad088 333 life.setbit(13,13, Life::living);
WiredHome 0:d268818ad088 334 life.setbit(14,13, Life::living);
WiredHome 0:d268818ad088 335 }
WiredHome 0:d268818ad088 336
WiredHome 0:d268818ad088 337
WiredHome 0:d268818ad088 338