test/lpfklife.c

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
child 9
1519a9a8d924
permissions
-rw-r--r--

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.

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