Added "Conway's Life" demo to LPFK test suite. This is a good test for

Tue, 26 Aug 2008 21:59:54 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 26 Aug 2008 21:59:54 +0100
changeset 5
2fc2b426ace9
parent 4
81d49d42ad6a
child 6
aed399ff850b

Added "Conway's Life" demo to LPFK test suite. This is a good test for
cached LED status setting, and a decent base for other LPFK games.

Makefile file | annotate | diff | revisions
test/lpfklife.c file | annotate | diff | revisions
     1.1 --- a/Makefile	Tue Aug 26 19:14:23 2008 +0100
     1.2 +++ b/Makefile	Tue Aug 26 21:59:54 2008 +0100
     1.3 @@ -3,17 +3,20 @@
     1.4  
     1.5  .PHONY:	all clean
     1.6  
     1.7 -all:	liblpfk.so lpfktest
     1.8 +all:	liblpfk.so lpfktest lpfklife
     1.9  	ldconfig -n .
    1.10  
    1.11  clean:
    1.12 -	-rm -f lpfktest
    1.13 -	-rm -f liblpfk.so*
    1.14 -	-rm -f src/*.o
    1.15 -	-rm -f test/*.o
    1.16 +	-rm -f lpfktest liblpfk.so*
    1.17 +	-rm -f src/*.o test/*.o
    1.18 +	-rf -f src/*~ test/*~ *~
    1.19  
    1.20  liblpfk.so:	src/liblpfk.o
    1.21  	$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $<
    1.22  
    1.23  lpfktest:	test/lpfktest.o
    1.24  	$(CC) -o $@ $< -L. -llpfk
    1.25 +
    1.26 +lpfklife:	test/lpfklife.o
    1.27 +	$(CC) -o $@ $< -L. -llpfk
    1.28 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/lpfklife.c	Tue Aug 26 21:59:54 2008 +0100
     2.3 @@ -0,0 +1,225 @@
     2.4 +// lpfklife: Conway's Game of Life for the LPFK
     2.5 +
     2.6 +#include <stdbool.h>
     2.7 +#include <stdio.h>
     2.8 +#include <string.h>
     2.9 +#include "liblpfk.h"
    2.10 +
    2.11 +/************************
    2.12 + * copied from http://linux-sxs.org/programming/kbhit.html
    2.13 + */
    2.14 +
    2.15 +#include <termios.h>
    2.16 +#include <unistd.h>   // for read()
    2.17 +
    2.18 +static struct termios initial_settings, new_settings;
    2.19 +static int peek_character = -1;
    2.20 +
    2.21 +void init_keyboard()
    2.22 +{
    2.23 +    tcgetattr(0,&initial_settings);
    2.24 +    new_settings = initial_settings;
    2.25 +    new_settings.c_lflag &= ~ICANON;
    2.26 +    new_settings.c_lflag &= ~ECHO;
    2.27 +    new_settings.c_lflag &= ~ISIG;
    2.28 +    new_settings.c_cc[VMIN] = 1;
    2.29 +    new_settings.c_cc[VTIME] = 0;
    2.30 +    tcsetattr(0, TCSANOW, &new_settings);
    2.31 +}
    2.32 +
    2.33 +void close_keyboard()
    2.34 +{
    2.35 +    tcsetattr(0, TCSANOW, &initial_settings);
    2.36 +}
    2.37 +
    2.38 +int kbhit()
    2.39 +{
    2.40 +unsigned char ch;
    2.41 +int nread;
    2.42 +
    2.43 +    if (peek_character != -1) return 1;
    2.44 +    new_settings.c_cc[VMIN]=0;
    2.45 +    tcsetattr(0, TCSANOW, &new_settings);
    2.46 +    nread = read(0,&ch,1);
    2.47 +    new_settings.c_cc[VMIN]=1;
    2.48 +    tcsetattr(0, TCSANOW, &new_settings);
    2.49 +    if(nread == 1)
    2.50 +    {
    2.51 +        peek_character = ch;
    2.52 +        return 1;
    2.53 +    }
    2.54 +    return 0;
    2.55 +}
    2.56 +
    2.57 +int readch()
    2.58 +{
    2.59 +char ch;
    2.60 +
    2.61 +    if(peek_character != -1)
    2.62 +    {
    2.63 +        ch = peek_character;
    2.64 +        peek_character = -1;
    2.65 +        return ch;
    2.66 +    }
    2.67 +    read(0,&ch,1);
    2.68 +    return ch;
    2.69 +}
    2.70 +
    2.71 +/***********************/
    2.72 +
    2.73 +int main(void)
    2.74 +{
    2.75 +	int i, nei, x, y;
    2.76 +	bool old_gamegrid[6][6];
    2.77 +	bool gamegrid[6][6];
    2.78 +	bool steadyState = false;
    2.79 +	unsigned long iteration = 0;
    2.80 +	LPFK_CTX ctx;
    2.81 +
    2.82 +	// initialisation
    2.83 +	memset(&gamegrid, 0, sizeof(gamegrid));
    2.84 +
    2.85 +	init_keyboard();
    2.86 +	atexit(close_keyboard);
    2.87 +
    2.88 +	// open lpfk port
    2.89 +	if ((i = lpfk_open(&ctx, "/dev/ttyUSB0")) != LPFK_E_OK) {
    2.90 +		// error opening lpfk
    2.91 +		printf("Error opening LPFK: code %d\n", i);
    2.92 +		return -1;
    2.93 +	}
    2.94 +
    2.95 +	lpfk_enable(&ctx, true);
    2.96 +
    2.97 +	// allow user to set up their game grid
    2.98 +	printf("Press the keys on the LPFK to set up the game grid, then press Enter to start the simulation.\n");
    2.99 +	while (!kbhit()) {
   2.100 +		i = lpfk_read(&ctx);
   2.101 +
   2.102 +		if (i >= 0) {
   2.103 +			printf("key %d\n", i);
   2.104 +			// Key down, toggle the LED
   2.105 +			lpfk_set_led(&ctx, i, !lpfk_get_led(&ctx, i));
   2.106 +
   2.107 +			// update game grid
   2.108 +			if ((i >= 0) && (i < 4)) {
   2.109 +				gamegrid[0][i+1] = !gamegrid[0][i+1];		// +1 because 1st row is 4-column
   2.110 +			} else if ((i >= 4) && (i < 10)) {
   2.111 +				gamegrid[1][i-4] = !gamegrid[1][i-4];
   2.112 +			} else if ((i >= 10) && (i < 16)) {
   2.113 +				gamegrid[2][i-10] = !gamegrid[2][i-10];
   2.114 +			} else if ((i >= 16) && (i < 22)) {
   2.115 +				gamegrid[3][i-16] = !gamegrid[3][i-16];
   2.116 +			} else if ((i >= 22) && (i < 28)) {
   2.117 +				gamegrid[4][i-22] = !gamegrid[4][i-22];
   2.118 +			} else {
   2.119 +				gamegrid[5][(i-28)+1] = !gamegrid[5][(i-28)+1];	// +1 because last row is 4-column
   2.120 +			}
   2.121 +		}
   2.122 +	}
   2.123 +	// flush keyboard buffer
   2.124 +	while (kbhit()) readch();
   2.125 +
   2.126 +	// disable LPFK keys
   2.127 +	lpfk_enable(&ctx, false);
   2.128 +
   2.129 +#ifdef DEBUG
   2.130 +	// print the game grid: debug only
   2.131 +	printf("GAME GRID: [iter %lu]\n", iteration);
   2.132 +	for (y=0; y<6; y++) {
   2.133 +		for (x=0; x<6; x++) {
   2.134 +			if (gamegrid[y][x]) printf("* "); else printf(". ");
   2.135 +		}
   2.136 +		printf("\n");
   2.137 +	}
   2.138 +	printf("\n");
   2.139 +#endif
   2.140 +
   2.141 +	printf("Press ENTER to stop the simulation.\n");
   2.142 +
   2.143 +	// run game
   2.144 +	while (!kbhit() && !steadyState) {
   2.145 +		// increase iteration counter
   2.146 +		iteration++;
   2.147 +
   2.148 +		// save current game grid
   2.149 +		memcpy(&old_gamegrid, &gamegrid, sizeof(gamegrid));
   2.150 +
   2.151 +		// loop over game grid
   2.152 +		for (y=0; y<6; y++) {
   2.153 +			for (x=0; x<6; x++) {
   2.154 +				nei = 0;
   2.155 +
   2.156 +				// count neighbours
   2.157 +				if (y > 0) {
   2.158 +					if (x > 0) { if (old_gamegrid[y-1][x-1]) nei++; }
   2.159 +					if (old_gamegrid[y-1][x]) nei++;
   2.160 +					if (x < 5) { if (old_gamegrid[y-1][x+1]) nei++; }
   2.161 +				}
   2.162 +				if (x > 0) { if (old_gamegrid[y][x-1]) nei++; }
   2.163 +				// old_gamegrid[x][y] is us!
   2.164 +				if (x < 5) { if (old_gamegrid[y][x+1]) nei++; }
   2.165 +				if (y < 5) {
   2.166 +					if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
   2.167 +					if (old_gamegrid[y+1][x]) nei++;
   2.168 +					if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
   2.169 +				}
   2.170 +
   2.171 +				// so what happens to our cell?
   2.172 +				if (old_gamegrid[y][x]) {
   2.173 +					// --- rules for live cells ---
   2.174 +					if ((nei < 2) || (nei > 3)) {
   2.175 +						// <2 neighbours, death due to loneliness.
   2.176 +						// or >3 neighbours, death due to overcrowding.
   2.177 +						gamegrid[y][x] = false;
   2.178 +					}
   2.179 +				} else {
   2.180 +					// --- rules for dead cells ---
   2.181 +					if (nei == 3) {
   2.182 +						// any dead cell with three neighbours comes to life
   2.183 +						gamegrid[y][x] = true;
   2.184 +					}
   2.185 +				}
   2.186 +			}
   2.187 +		}
   2.188 +
   2.189 +		if (memcmp(&gamegrid, &old_gamegrid, sizeof(gamegrid)) == 0) {
   2.190 +			steadyState = true;
   2.191 +		}
   2.192 +
   2.193 +#ifdef DEBUG
   2.194 +		printf("GAME GRID: [iter %lu]\n", iteration);
   2.195 +		for (y=0; y<6; y++) {
   2.196 +			for (x=0; x<6; x++) {
   2.197 +				if (gamegrid[y][x]) printf("* "); else printf(". ");
   2.198 +			}
   2.199 +			printf("\n");
   2.200 +		}
   2.201 +		printf("\n");
   2.202 +#endif
   2.203 +
   2.204 +		// now update the LPFK from the game grid
   2.205 +		for (i=0; i<32; i++) {
   2.206 +			if (i < 4)			lpfk_set_led_cached(&ctx, i, gamegrid[0][i+1]);
   2.207 +			else if (i < 10)	lpfk_set_led_cached(&ctx, i, gamegrid[1][i-4]);
   2.208 +			else if (i < 16)	lpfk_set_led_cached(&ctx, i, gamegrid[2][i-10]);
   2.209 +			else if (i < 22)	lpfk_set_led_cached(&ctx, i, gamegrid[3][i-16]);
   2.210 +			else if (i < 28)	lpfk_set_led_cached(&ctx, i, gamegrid[4][i-22]);
   2.211 +			else				lpfk_set_led_cached(&ctx, i, gamegrid[5][(i-28)+1]);
   2.212 +		}
   2.213 +
   2.214 +		// flush updates to the LPFK
   2.215 +		lpfk_update_leds(&ctx);
   2.216 +
   2.217 +		// make sure updates aren't too fast
   2.218 +		sleep(1);
   2.219 +	}
   2.220 +
   2.221 +	if (steadyState) {
   2.222 +		printf("Steady state reached.\n");
   2.223 +	}
   2.224 +	printf("LPFK Life ran for %lu iterations.\n", iteration);
   2.225 +
   2.226 +	// close the LPFK
   2.227 +	lpfk_close(&ctx);
   2.228 +}