test/lpfklife.c

Wed, 03 Sep 2008 17:15:47 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 03 Sep 2008 17:15:47 +0100
changeset 10
f76c929f65e6
parent 9
1519a9a8d924
permissions
-rw-r--r--

added "naive" and "wraparound" algorithms to lpfklife

     1 // lpfklife: Conway's Game of Life for the LPFK
     3 #include <stdbool.h>
     4 #include <stdio.h>
     5 #include <string.h>
     6 #include "liblpfk.h"
     8 #define LIFE_ALGORITHM_NAIVE
    10 /************************
    11  * copied from http://linux-sxs.org/programming/kbhit.html
    12  */
    14 #include <termios.h>
    15 #include <unistd.h>   // for read()
    17 static struct termios initial_settings, new_settings;
    18 static int peek_character = -1;
    20 void init_keyboard()
    21 {
    22     tcgetattr(0,&initial_settings);
    23     new_settings = initial_settings;
    24     new_settings.c_lflag &= ~ICANON;
    25     new_settings.c_lflag &= ~ECHO;
    26     new_settings.c_lflag &= ~ISIG;
    27     new_settings.c_cc[VMIN] = 1;
    28     new_settings.c_cc[VTIME] = 0;
    29     tcsetattr(0, TCSANOW, &new_settings);
    30 }
    32 void close_keyboard()
    33 {
    34     tcsetattr(0, TCSANOW, &initial_settings);
    35 }
    37 int kbhit()
    38 {
    39 unsigned char ch;
    40 int nread;
    42     if (peek_character != -1) return 1;
    43     new_settings.c_cc[VMIN]=0;
    44     tcsetattr(0, TCSANOW, &new_settings);
    45     nread = read(0,&ch,1);
    46     new_settings.c_cc[VMIN]=1;
    47     tcsetattr(0, TCSANOW, &new_settings);
    48     if(nread == 1)
    49     {
    50         peek_character = ch;
    51         return 1;
    52     }
    53     return 0;
    54 }
    56 int readch()
    57 {
    58 char ch;
    60     if(peek_character != -1)
    61     {
    62         ch = peek_character;
    63         peek_character = -1;
    64         return ch;
    65     }
    66     read(0,&ch,1);
    67     return ch;
    68 }
    70 /***********************/
    72 int main(void)
    73 {
    74 	int i, nei, x, y;
    75 	bool old_gamegrid[6][6];
    76 	bool gamegrid[6][6];
    77 	bool steadyState = false;
    78 	unsigned long iteration = 0;
    79 	LPFK_CTX ctx;
    81 	// initialisation
    82 	memset(&gamegrid, 0, sizeof(gamegrid));
    84 	init_keyboard();
    85 	atexit(close_keyboard);
    87 	// open lpfk port
    88 	if ((i = lpfk_open(&ctx, "/dev/ttyUSB0")) != LPFK_E_OK) {
    89 		// error opening lpfk
    90 		printf("Error opening LPFK: code %d\n", i);
    91 		return -1;
    92 	}
    94 	lpfk_enable(&ctx, true);
    96 	// allow user to set up their game grid
    97 	printf("Press the keys on the LPFK to set up the game grid, then press Enter to start the simulation.\n");
    98 	while (!kbhit()) {
    99 		i = lpfk_read(&ctx);
   101 		if (i >= 0) {
   102 #ifdef DEBUG
   103 			printf("key %d\n", i);
   104 #endif
   105 			// Key down, toggle the LED
   106 			lpfk_set_led(&ctx, i, !lpfk_get_led(&ctx, i));
   108 			// update game grid
   109 			if ((i >= 0) && (i < 4)) {
   110 				gamegrid[0][i+1] = !gamegrid[0][i+1];		// +1 because 1st row is 4-column
   111 			} else if ((i >= 4) && (i < 10)) {
   112 				gamegrid[1][i-4] = !gamegrid[1][i-4];
   113 			} else if ((i >= 10) && (i < 16)) {
   114 				gamegrid[2][i-10] = !gamegrid[2][i-10];
   115 			} else if ((i >= 16) && (i < 22)) {
   116 				gamegrid[3][i-16] = !gamegrid[3][i-16];
   117 			} else if ((i >= 22) && (i < 28)) {
   118 				gamegrid[4][i-22] = !gamegrid[4][i-22];
   119 			} else {
   120 				gamegrid[5][(i-28)+1] = !gamegrid[5][(i-28)+1];	// +1 because last row is 4-column
   121 			}
   122 		}
   123 	}
   124 	// flush keyboard buffer
   125 	while (kbhit()) readch();
   127 	// disable LPFK keys
   128 	lpfk_enable(&ctx, false);
   130 #ifdef DEBUG
   131 	// print the game grid: debug only
   132 	printf("GAME GRID: [iter %lu]\n", iteration);
   133 	for (y=0; y<6; y++) {
   134 		for (x=0; x<6; x++) {
   135 			if (gamegrid[y][x]) printf("* "); else printf(". ");
   136 		}
   137 		printf("\n");
   138 	}
   139 	printf("\n");
   140 #endif
   142 	printf("Press ENTER to stop the simulation.\n");
   144 	// run game
   145 	while (!kbhit() && !steadyState) {
   146 		// increase iteration counter
   147 		iteration++;
   149 		// save current game grid
   150 		memcpy(&old_gamegrid, &gamegrid, sizeof(gamegrid));
   152 		// loop over game grid
   153 		for (y=0; y<6; y++) {
   154 			for (x=0; x<6; x++) {
   155 				nei = 0;
   157 				// count neighbours
   158 #ifdef LIFE_ALGORITHM_NAIVE
   159 				/// NAIVE ALGORITHM
   160 				// Assumes every cell outside the grid is dead.
   161 				if (y > 0) {
   162 					if (x > 0) { if (old_gamegrid[y-1][x-1]) nei++; }
   163 					if (old_gamegrid[y-1][x]) nei++;
   164 					if (x < 5) { if (old_gamegrid[y-1][x+1]) nei++; }
   165 				}
   167 				if (x > 0) { if (old_gamegrid[y][x-1]) nei++; }
   168 				// old_gamegrid[x][y] is us!
   169 				if (x < 5) { if (old_gamegrid[y][x+1]) nei++; }
   171 				if (y < 5) {
   172 					if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
   173 					if (old_gamegrid[y+1][x]) nei++;
   174 					if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
   175 				}
   176 #else
   177 				/// WRAPPING ALGORITHM
   178 				// Accesses off of one side of the grid are wrapped to the
   179 				// opposite side.
   180 				//
   181 				// WARNING: this algorithm has NOT been extensively tested,
   182 				// and completely screws up the glider test.
   183 				//
   184 				// TODO: test and debug:
   185 				if (y > 0) {
   186 					if (x > 0)	{ if (old_gamegrid[y-1][x-1]) nei++; }
   187 						else	{ if (old_gamegrid[y-1][5]) nei++; }
   189 					if (old_gamegrid[y-1][x]) nei++;
   191 					if (x < 5)	{ if (old_gamegrid[y-1][x+1]) nei++; }
   192 						else	{ if (old_gamegrid[y-1][0]) nei++; }
   193 				} else {
   194 					if (x > 0)	{ if (old_gamegrid[5][x-1]) nei++; }
   195 						else	{ if (old_gamegrid[5][5]) nei++; }
   197 					if (old_gamegrid[y-1][x]) nei++;
   199 					if (x < 5)	{ if (old_gamegrid[5][x+1]) nei++; }
   200 						else	{ if (old_gamegrid[5][0]) nei++; }
   201 				}
   204 				if (x > 0)	{ if (old_gamegrid[y][x-1]) nei++; }
   205 					else	{ if (old_gamegrid[y][5]) nei++; }
   207 				// old_gamegrid[x][y] is us!
   209 				if (x < 5)	{ if (old_gamegrid[y][x+1]) nei++; }
   210 					else	{ if (old_gamegrid[y][0]) nei++; }
   213 				if (y < 5) {
   214 					if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
   215 						else	{ if (old_gamegrid[y+1][5]) nei++; }	///
   217 					if (old_gamegrid[y+1][x]) nei++;
   219 					if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
   220 						else	{ if (old_gamegrid[y+1][0]) nei++; }	///
   221 				} else {
   222 					if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
   223 						else	{ if (old_gamegrid[y+1][5]) nei++; }	///
   225 					if (old_gamegrid[y+1][x]) nei++;
   227 					if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
   228 						else	{ if (old_gamegrid[y-1][0]) nei++; }	///
   229 				}
   230 #endif
   232 				// so what happens to our cell?
   233 				if (old_gamegrid[y][x]) {
   234 					// --- rules for live cells ---
   235 					if ((nei < 2) || (nei > 3)) {
   236 						// <2 neighbours, death due to loneliness.
   237 						// or >3 neighbours, death due to overcrowding.
   238 						gamegrid[y][x] = false;
   239 					}
   240 				} else {
   241 					// --- rules for dead cells ---
   242 					if (nei == 3) {
   243 						// any dead cell with three neighbours comes to life
   244 						gamegrid[y][x] = true;
   245 					}
   246 				}
   247 			}
   248 		}
   250 		if (memcmp(&gamegrid, &old_gamegrid, sizeof(gamegrid)) == 0) {
   251 			steadyState = true;
   252 		}
   254 #ifdef DEBUG
   255 		printf("GAME GRID: [iter %lu]\n", iteration);
   256 		for (y=0; y<6; y++) {
   257 			for (x=0; x<6; x++) {
   258 				if (gamegrid[y][x]) printf("* "); else printf(". ");
   259 			}
   260 			printf("\n");
   261 		}
   262 		printf("\n");
   263 #endif
   265 		// now update the LPFK from the game grid
   266 		for (i=0; i<32; i++) {
   267 			if (i < 4)			lpfk_set_led_cached(&ctx, i, gamegrid[0][i+1]);
   268 			else if (i < 10)	lpfk_set_led_cached(&ctx, i, gamegrid[1][i-4]);
   269 			else if (i < 16)	lpfk_set_led_cached(&ctx, i, gamegrid[2][i-10]);
   270 			else if (i < 22)	lpfk_set_led_cached(&ctx, i, gamegrid[3][i-16]);
   271 			else if (i < 28)	lpfk_set_led_cached(&ctx, i, gamegrid[4][i-22]);
   272 			else				lpfk_set_led_cached(&ctx, i, gamegrid[5][(i-28)+1]);
   273 		}
   275 		// flush updates to the LPFK
   276 		lpfk_update_leds(&ctx);
   278 		// make sure updates aren't too fast
   279 		sleep(1);
   280 	}
   282 	if (steadyState) {
   283 		printf("Steady state reached.\n");
   284 	}
   285 	printf("LPFK Life ran for %lu iterations.\n", iteration);
   287 	// close the LPFK
   288 	lpfk_close(&ctx);
   289 }