/** * Conways Game of life * Author: Daniel Otte * License: GPLv3 * * */ #include <stdint.h> #ifdef AVR #include <util/delay.h> #include <avr/sfr_defs.h> /* for debugging */ #endif #include "../config.h" #include "../random/prng.h" #include "../pixel.h" #include "../util.h" /******************************************************************************/ #undef DEBUG #define XSIZE NUM_COLS #define YSIZE NUM_ROWS /* * last line is for debug information */ #ifdef DEBUG #undef YSIZE #define YSIZE (NUM_ROWS-1) #define DEBUG_ROW (NUM_ROWS-1) #define DEBUG_BIT(pos, val) \ setpixel((pixel){(pos)%XSIZE,DEBUG_ROW+(pos)/XSIZE},(val)?3:0) #define DEBUG_BYTE(s,v) \ DEBUG_BIT((s)*8+0, (v)&(1<<0)); \ DEBUG_BIT((s)*8+1, (v)&(1<<1)); \ DEBUG_BIT((s)*8+2, (v)&(1<<2)); \ DEBUG_BIT((s)*8+3, (v)&(1<<3)); \ DEBUG_BIT((s)*8+4, (v)&(1<<4)); \ DEBUG_BIT((s)*8+5, (v)&(1<<5)); \ DEBUG_BIT((s)*8+6, (v)&(1<<6)); \ DEBUG_BIT((s)*8+7, (v)&(1<<7)) #else #define DEBUG_BIT(s,v) #define DEBUG_BYTE(s,v) #endif //#define GLIDER_TEST #define BITSTUFFED #define LOOP_DETECT_BUFFER_SIZE 8 #ifndef GOL_DELAY #define GOL_DELAY 1 /* milliseconds */ #endif #ifndef GOL_CYCLES #define GOL_CYCLES (2*60*3) #endif /******************************************************************************/ /******************************************************************************/ typedef enum{dead=0, alive=1} cell_t; #ifndef BITSTUFFED #define FIELD_XSIZE XSIZE #define FIELD_YSIZE YSIZE typedef cell_t field_t[FIELD_XSIZE][FIELD_YSIZE]; /******************************************************************************/ void setcell(field_t pf, int x, int y, cell_t value){ pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE] = value; } /******************************************************************************/ cell_t getcell(field_t pf, int x, int y){ return pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE]; } #else /* BITSTUFFED */ #define FIELD_XSIZE ((XSIZE+7)/8) #define FIELD_YSIZE YSIZE typedef uint8_t field_t[FIELD_XSIZE][FIELD_YSIZE]; /******************************************************************************/ void setcell(field_t pf, int x, int y, cell_t value){ uint8_t t; x = (x+XSIZE) % XSIZE; y = (y+YSIZE) % YSIZE; t = pf[x/8][y]; if(value==alive){ t |= 1<<(x&7); } else { t &= ~(1<<(x&7)); } pf[x/8][y] = t; } /******************************************************************************/ cell_t getcell(field_t pf, int x, int y){ x = (x+XSIZE) % XSIZE; y = (y+YSIZE) % YSIZE; return ((pf[x/8][y])&(1<<(x&7)))?alive:dead; } #endif /******************************************************************************/ uint8_t countsurroundingalive(field_t pf, int x, int y){ uint8_t ret=0; ret += (getcell(pf, x-1, y-1)==alive)?1:0; ret += (getcell(pf, x , y-1)==alive)?1:0; ret += (getcell(pf, x+1, y-1)==alive)?1:0; ret += (getcell(pf, x-1, y )==alive)?1:0; ret += (getcell(pf, x+1, y )==alive)?1:0; ret += (getcell(pf, x-1, y+1)==alive)?1:0; ret += (getcell(pf, x , y+1)==alive)?1:0; ret += (getcell(pf, x+1, y+1)==alive)?1:0; return ret; } /******************************************************************************/ void nextiteration(field_t dest, field_t src){ int x,y; uint8_t tc; for(y=0; y<YSIZE; ++y){ for(x=0; x<XSIZE; ++x){ tc=countsurroundingalive(src,x,y); switch(tc){ // case 0: // case 1: // /* dead */ // setcell(dest, x,y, dead); case 2: /* keep */ setcell(dest, x,y, getcell(src,x,y)); break; case 3: /* alive */ setcell(dest, x,y, alive); break; default: /* dead */ setcell(dest, x,y, dead); break; } } } } /******************************************************************************/ void printpf(field_t pf){ int x,y; for(y=0; y<YSIZE; ++y){ for(x=0; x<XSIZE; ++x){ setpixel((pixel){x,y},(getcell(pf,x,y)==alive)?3:0); } } } /******************************************************************************/ void pfcopy(field_t dest, field_t src){ int x,y; for(y=0; y<YSIZE; ++y){ for(x=0; x<XSIZE; ++x){ setcell(dest,x,y,getcell(src,x,y)); } } } /******************************************************************************/ #ifndef BITSTUFFED uint8_t pfcmp(field_t dest, field_t src){ int x,y; for(y=0; y<YSIZE; ++y){ for(x=0; x<XSIZE; ++x){ if (getcell(src,x,y) != getcell(dest,x,y)) return 1; } } return 0; } /******************************************************************************/ uint8 pfempty(field_t src){ int x,y; for(y=0; y<YSIZE; ++y){ for(x=0; x<XSIZE; ++x){ if (getcell(src,x,y)==alive) return 0; } } return 1; } #else uint8_t pfcmp(field_t dest, field_t src){ int x,y; for(y=0; y<FIELD_YSIZE; ++y){ for(x=0; x<FIELD_XSIZE; ++x){ if (src[x][y] != dest[x][y]) return 1; } } return 0; } /******************************************************************************/ uint8_t pfempty(field_t src){ int x,y; for(y=0; y<FIELD_YSIZE; ++y){ for(x=0; x<FIELD_XSIZE; ++x){ if (src[x][y]!=0) return 0; } } return 1; } #endif /******************************************************************************/ void insertglider(field_t pf){ /* * # * # * ### */ setcell(pf, 1, 0, alive); setcell(pf, 2, 1, alive); setcell(pf, 0, 2, alive); setcell(pf, 1, 2, alive); setcell(pf, 2, 2, alive); } /******************************************************************************/ int gameoflife(){ DEBUG_BYTE(0,0); // set debug bytes to zero DEBUG_BYTE(1,0); field_t pf1,pf2; field_t ldbuf[LOOP_DETECT_BUFFER_SIZE]={{{0}}}; // loop detect buffer uint8_t ldbuf_idx=0; int x,y; uint16_t cycle; //start: /* initalise the field with random */ for(y=0;y<YSIZE;++y){ for(x=0;x<XSIZE; ++x){ setcell(pf1,x,y,(random8()&1)?alive:dead); } } #ifdef GLIDER_TEST /* initialise with glider */ for(y=0;y<YSIZE;++y){ for(x=0;x<XSIZE; ++x){ setcell(pf1,x,y,dead); } } insertglider(pf1); #endif /* the main part */ printpf(pf1); for(cycle=1; cycle<GOL_CYCLES; ++cycle){ DEBUG_BYTE(0,(uint8_t)(GOL_CYCLES-cycle)&0xff); DEBUG_BYTE(1, SREG); wait(GOL_DELAY); pfcopy(pf2,pf1); nextiteration(pf1,pf2); printpf(pf1); /* loop detection */ if(!pfcmp(pf1, pf2)){ insertglider(pf1); cycle=1; } if(pfempty(pf1)){ /* kill game */ return 0; } /* */ uint8_t i; for(i=0; i<LOOP_DETECT_BUFFER_SIZE; ++i){ if(!pfcmp(pf1, ldbuf[i])){ insertglider(pf1); cycle=1; } } pfcopy(ldbuf[ldbuf_idx], pf1); ldbuf_idx = (ldbuf_idx+1)%LOOP_DETECT_BUFFER_SIZE; } return 0; }