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