Tue, 26 Aug 2008 22:13:49 +0100
added #ifdef DEBUG around "key down" debug printf
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 #ifdef DEBUG
101 printf("key %d\n", i);
102 #endif
103 // Key down, toggle the LED
104 lpfk_set_led(&ctx, i, !lpfk_get_led(&ctx, i));
106 // update game grid
107 if ((i >= 0) && (i < 4)) {
108 gamegrid[0][i+1] = !gamegrid[0][i+1]; // +1 because 1st row is 4-column
109 } else if ((i >= 4) && (i < 10)) {
110 gamegrid[1][i-4] = !gamegrid[1][i-4];
111 } else if ((i >= 10) && (i < 16)) {
112 gamegrid[2][i-10] = !gamegrid[2][i-10];
113 } else if ((i >= 16) && (i < 22)) {
114 gamegrid[3][i-16] = !gamegrid[3][i-16];
115 } else if ((i >= 22) && (i < 28)) {
116 gamegrid[4][i-22] = !gamegrid[4][i-22];
117 } else {
118 gamegrid[5][(i-28)+1] = !gamegrid[5][(i-28)+1]; // +1 because last row is 4-column
119 }
120 }
121 }
122 // flush keyboard buffer
123 while (kbhit()) readch();
125 // disable LPFK keys
126 lpfk_enable(&ctx, false);
128 #ifdef DEBUG
129 // print the game grid: debug only
130 printf("GAME GRID: [iter %lu]\n", iteration);
131 for (y=0; y<6; y++) {
132 for (x=0; x<6; x++) {
133 if (gamegrid[y][x]) printf("* "); else printf(". ");
134 }
135 printf("\n");
136 }
137 printf("\n");
138 #endif
140 printf("Press ENTER to stop the simulation.\n");
142 // run game
143 while (!kbhit() && !steadyState) {
144 // increase iteration counter
145 iteration++;
147 // save current game grid
148 memcpy(&old_gamegrid, &gamegrid, sizeof(gamegrid));
150 // loop over game grid
151 for (y=0; y<6; y++) {
152 for (x=0; x<6; x++) {
153 nei = 0;
155 // count neighbours
156 if (y > 0) {
157 if (x > 0) { if (old_gamegrid[y-1][x-1]) nei++; }
158 if (old_gamegrid[y-1][x]) nei++;
159 if (x < 5) { if (old_gamegrid[y-1][x+1]) nei++; }
160 }
161 if (x > 0) { if (old_gamegrid[y][x-1]) nei++; }
162 // old_gamegrid[x][y] is us!
163 if (x < 5) { if (old_gamegrid[y][x+1]) nei++; }
164 if (y < 5) {
165 if (x > 0) { if (old_gamegrid[y+1][x-1]) nei++; }
166 if (old_gamegrid[y+1][x]) nei++;
167 if (x < 5) { if (old_gamegrid[y+1][x+1]) nei++; }
168 }
170 // so what happens to our cell?
171 if (old_gamegrid[y][x]) {
172 // --- rules for live cells ---
173 if ((nei < 2) || (nei > 3)) {
174 // <2 neighbours, death due to loneliness.
175 // or >3 neighbours, death due to overcrowding.
176 gamegrid[y][x] = false;
177 }
178 } else {
179 // --- rules for dead cells ---
180 if (nei == 3) {
181 // any dead cell with three neighbours comes to life
182 gamegrid[y][x] = true;
183 }
184 }
185 }
186 }
188 if (memcmp(&gamegrid, &old_gamegrid, sizeof(gamegrid)) == 0) {
189 steadyState = true;
190 }
192 #ifdef DEBUG
193 printf("GAME GRID: [iter %lu]\n", iteration);
194 for (y=0; y<6; y++) {
195 for (x=0; x<6; x++) {
196 if (gamegrid[y][x]) printf("* "); else printf(". ");
197 }
198 printf("\n");
199 }
200 printf("\n");
201 #endif
203 // now update the LPFK from the game grid
204 for (i=0; i<32; i++) {
205 if (i < 4) lpfk_set_led_cached(&ctx, i, gamegrid[0][i+1]);
206 else if (i < 10) lpfk_set_led_cached(&ctx, i, gamegrid[1][i-4]);
207 else if (i < 16) lpfk_set_led_cached(&ctx, i, gamegrid[2][i-10]);
208 else if (i < 22) lpfk_set_led_cached(&ctx, i, gamegrid[3][i-16]);
209 else if (i < 28) lpfk_set_led_cached(&ctx, i, gamegrid[4][i-22]);
210 else lpfk_set_led_cached(&ctx, i, gamegrid[5][(i-28)+1]);
211 }
213 // flush updates to the LPFK
214 lpfk_update_leds(&ctx);
216 // make sure updates aren't too fast
217 sleep(1);
218 }
220 if (steadyState) {
221 printf("Steady state reached.\n");
222 }
223 printf("LPFK Life ran for %lu iterations.\n", iteration);
225 // close the LPFK
226 lpfk_close(&ctx);
227 }