test/lpfklife.c

Tue, 26 Aug 2008 22:13:49 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 26 Aug 2008 22:13:49 +0100
changeset 9
1519a9a8d924
parent 5
2fc2b426ace9
child 10
f76c929f65e6
permissions
-rw-r--r--

added #ifdef DEBUG around "key down" debug printf

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