Tue, 26 Aug 2008 21:59:54 +0100
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.
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 /************************
9 * copied from http://linux-sxs.org/programming/kbhit.html
10 */
12 #include <termios.h>
13 #include <unistd.h> // for read()
15 static struct termios initial_settings, new_settings;
16 static int peek_character = -1;
18 void init_keyboard()
19 {
20 tcgetattr(0,&initial_settings);
21 new_settings = initial_settings;
22 new_settings.c_lflag &= ~ICANON;
23 new_settings.c_lflag &= ~ECHO;
24 new_settings.c_lflag &= ~ISIG;
25 new_settings.c_cc[VMIN] = 1;
26 new_settings.c_cc[VTIME] = 0;
27 tcsetattr(0, TCSANOW, &new_settings);
28 }
30 void close_keyboard()
31 {
32 tcsetattr(0, TCSANOW, &initial_settings);
33 }
35 int kbhit()
36 {
37 unsigned char ch;
38 int nread;
40 if (peek_character != -1) return 1;
41 new_settings.c_cc[VMIN]=0;
42 tcsetattr(0, TCSANOW, &new_settings);
43 nread = read(0,&ch,1);
44 new_settings.c_cc[VMIN]=1;
45 tcsetattr(0, TCSANOW, &new_settings);
46 if(nread == 1)
47 {
48 peek_character = ch;
49 return 1;
50 }
51 return 0;
52 }
54 int readch()
55 {
56 char ch;
58 if(peek_character != -1)
59 {
60 ch = peek_character;
61 peek_character = -1;
62 return ch;
63 }
64 read(0,&ch,1);
65 return ch;
66 }
68 /***********************/
70 int main(void)
71 {
72 int i, nei, x, y;
73 bool old_gamegrid[6][6];
74 bool gamegrid[6][6];
75 bool steadyState = false;
76 unsigned long iteration = 0;
77 LPFK_CTX ctx;
79 // initialisation
80 memset(&gamegrid, 0, sizeof(gamegrid));
82 init_keyboard();
83 atexit(close_keyboard);
85 // open lpfk port
86 if ((i = lpfk_open(&ctx, "/dev/ttyUSB0")) != LPFK_E_OK) {
87 // error opening lpfk
88 printf("Error opening LPFK: code %d\n", i);
89 return -1;
90 }
92 lpfk_enable(&ctx, true);
94 // allow user to set up their game grid
95 printf("Press the keys on the LPFK to set up the game grid, then press Enter to start the simulation.\n");
96 while (!kbhit()) {
97 i = lpfk_read(&ctx);
99 if (i >= 0) {
100 printf("key %d\n", i);
101 // Key down, toggle the LED
102 lpfk_set_led(&ctx, i, !lpfk_get_led(&ctx, i));
104 // update game grid
105 if ((i >= 0) && (i < 4)) {
106 gamegrid[0][i+1] = !gamegrid[0][i+1]; // +1 because 1st row is 4-column
107 } else if ((i >= 4) && (i < 10)) {
108 gamegrid[1][i-4] = !gamegrid[1][i-4];
109 } else if ((i >= 10) && (i < 16)) {
110 gamegrid[2][i-10] = !gamegrid[2][i-10];
111 } else if ((i >= 16) && (i < 22)) {
112 gamegrid[3][i-16] = !gamegrid[3][i-16];
113 } else if ((i >= 22) && (i < 28)) {
114 gamegrid[4][i-22] = !gamegrid[4][i-22];
115 } else {
116 gamegrid[5][(i-28)+1] = !gamegrid[5][(i-28)+1]; // +1 because last row is 4-column
117 }
118 }
119 }
120 // flush keyboard buffer
121 while (kbhit()) readch();
123 // disable LPFK keys
124 lpfk_enable(&ctx, false);
126 #ifdef DEBUG
127 // print the game grid: debug only
128 printf("GAME GRID: [iter %lu]\n", iteration);
129 for (y=0; y<6; y++) {
130 for (x=0; x<6; x++) {
131 if (gamegrid[y][x]) printf("* "); else printf(". ");
132 }
133 printf("\n");
134 }
135 printf("\n");
136 #endif
138 printf("Press ENTER to stop the simulation.\n");
140 // run game
141 while (!kbhit() && !steadyState) {
142 // increase iteration counter
143 iteration++;
145 // save current game grid
146 memcpy(&old_gamegrid, &gamegrid, sizeof(gamegrid));
148 // loop over game grid
149 for (y=0; y<6; y++) {
150 for (x=0; x<6; x++) {
151 nei = 0;
153 // count neighbours
154 if (y > 0) {
155 if (x > 0) { if (old_gamegrid[y-1][x-1]) nei++; }
156 if (old_gamegrid[y-1][x]) nei++;
157 if (x < 5) { if (old_gamegrid[y-1][x+1]) nei++; }
158 }
159 if (x > 0) { if (old_gamegrid[y][x-1]) nei++; }
160 // old_gamegrid[x][y] is us!
161 if (x < 5) { if (old_gamegrid[y][x+1]) nei++; }
162 if (y < 5) {
163 if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
164 if (old_gamegrid[y+1][x]) nei++;
165 if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
166 }
168 // so what happens to our cell?
169 if (old_gamegrid[y][x]) {
170 // --- rules for live cells ---
171 if ((nei < 2) || (nei > 3)) {
172 // <2 neighbours, death due to loneliness.
173 // or >3 neighbours, death due to overcrowding.
174 gamegrid[y][x] = false;
175 }
176 } else {
177 // --- rules for dead cells ---
178 if (nei == 3) {
179 // any dead cell with three neighbours comes to life
180 gamegrid[y][x] = true;
181 }
182 }
183 }
184 }
186 if (memcmp(&gamegrid, &old_gamegrid, sizeof(gamegrid)) == 0) {
187 steadyState = true;
188 }
190 #ifdef DEBUG
191 printf("GAME GRID: [iter %lu]\n", iteration);
192 for (y=0; y<6; y++) {
193 for (x=0; x<6; x++) {
194 if (gamegrid[y][x]) printf("* "); else printf(". ");
195 }
196 printf("\n");
197 }
198 printf("\n");
199 #endif
201 // now update the LPFK from the game grid
202 for (i=0; i<32; i++) {
203 if (i < 4) lpfk_set_led_cached(&ctx, i, gamegrid[0][i+1]);
204 else if (i < 10) lpfk_set_led_cached(&ctx, i, gamegrid[1][i-4]);
205 else if (i < 16) lpfk_set_led_cached(&ctx, i, gamegrid[2][i-10]);
206 else if (i < 22) lpfk_set_led_cached(&ctx, i, gamegrid[3][i-16]);
207 else if (i < 28) lpfk_set_led_cached(&ctx, i, gamegrid[4][i-22]);
208 else lpfk_set_led_cached(&ctx, i, gamegrid[5][(i-28)+1]);
209 }
211 // flush updates to the LPFK
212 lpfk_update_leds(&ctx);
214 // make sure updates aren't too fast
215 sleep(1);
216 }
218 if (steadyState) {
219 printf("Steady state reached.\n");
220 }
221 printf("LPFK Life ran for %lu iterations.\n", iteration);
223 // close the LPFK
224 lpfk_close(&ctx);
225 }