|
|
@ -16,41 +16,41 @@ |
|
|
|
#include "../pixel.h" |
|
|
|
#include "../util.h" |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
#undef DEBUG |
|
|
|
|
|
|
|
|
|
|
|
#define XSIZE UNUM_COLS |
|
|
|
#define YSIZE UNUM_ROWS |
|
|
|
|
|
|
|
// optimizing for 8 bit archs while retaining compatibility with dimensions >255
|
|
|
|
// optimizing for 8 bit archs while retaining compatibility with dimensions >127
|
|
|
|
#if UNUM_COLS < 128 && UNUM_ROWS < 128 |
|
|
|
typedef uint8_t coord_t; |
|
|
|
typedef uint8_t coord_t; |
|
|
|
#else |
|
|
|
typedef unsigned int coord_t; |
|
|
|
typedef unsigned int coord_t; |
|
|
|
#endif |
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* last line is for debug information |
|
|
|
*/ |
|
|
|
#ifdef DEBUG |
|
|
|
#undef YSIZE |
|
|
|
#define YSIZE (UNUM_ROWS-1) |
|
|
|
#define DEBUG_ROW (UNUM_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)) |
|
|
|
#undef YSIZE |
|
|
|
#define YSIZE (UNUM_ROWS-1) |
|
|
|
#define DEBUG_ROW (UNUM_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) |
|
|
|
#define DEBUG_BIT(s,v) |
|
|
|
#define DEBUG_BYTE(s,v) |
|
|
|
#endif |
|
|
|
|
|
|
|
//#define GLIDER_TEST
|
|
|
@ -59,17 +59,19 @@ typedef unsigned int coord_t; |
|
|
|
#define LOOP_DETECT_BUFFER_SIZE 8U |
|
|
|
|
|
|
|
#ifndef GOL_DELAY |
|
|
|
#define GOL_DELAY 1 /* milliseconds */ |
|
|
|
#define GOL_DELAY 1 /* milliseconds */ |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef GOL_CYCLES |
|
|
|
#define GOL_CYCLES (2*60*3) |
|
|
|
#define GOL_CYCLES (2*60*3) |
|
|
|
#endif |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
enum cell_e {dead=0, alive=1}; |
|
|
|
enum cell_e { |
|
|
|
dead = 0, alive = 1 |
|
|
|
}; |
|
|
|
#ifdef NDEBUG |
|
|
|
typedef uint8_t cell_t; |
|
|
|
#else |
|
|
@ -81,60 +83,55 @@ enum cell_e {dead=0, alive=1}; |
|
|
|
#define FIELD_XSIZE XSIZE |
|
|
|
#define FIELD_YSIZE YSIZE |
|
|
|
|
|
|
|
typedef cell_t field_t[FIELD_XSIZE][FIELD_YSIZE]; |
|
|
|
typedef cell_t field_t[FIELD_YSIZE][FIELD_XSIZE]; |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
void setcell(field_t pf, coord_t x, coord_t y, cell_t value){ |
|
|
|
pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE] = value; |
|
|
|
void setcell(field_t pf, coord_t x, coord_t y, cell_t value) { |
|
|
|
pf[(y+FIELD_YSIZE) % FIELD_YSIZE][(x+FIELD_XSIZE) % FIELD_XSIZE] = value; |
|
|
|
} |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
cell_t getcell(field_t pf, coord_t x, coord_t y){ |
|
|
|
return pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE]; |
|
|
|
cell_t getcell(field_t pf, coord_t x, coord_t y) { |
|
|
|
return pf[(y+FIELD_YSIZE) % FIELD_YSIZE][(x+FIELD_XSIZE) % FIELD_XSIZE]; |
|
|
|
} |
|
|
|
|
|
|
|
#else /* BITSTUFFED */ |
|
|
|
|
|
|
|
#define FIELD_XSIZE ((XSIZE+7)/8) |
|
|
|
#define FIELD_XSIZE LINEBYTES |
|
|
|
#define FIELD_YSIZE YSIZE |
|
|
|
|
|
|
|
typedef uint8_t field_t[FIELD_XSIZE][FIELD_YSIZE]; |
|
|
|
typedef uint8_t field_t[FIELD_YSIZE][FIELD_XSIZE]; |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
void setcell(field_t pf, coord_t x, coord_t y, cell_t value){ |
|
|
|
uint8_t t; |
|
|
|
|
|
|
|
t = pf[x/8][y]; |
|
|
|
if(value==alive){ |
|
|
|
t |= 1<<(x&7); |
|
|
|
void setcell(field_t pf, coord_t x, coord_t y, cell_t value) { |
|
|
|
if (value != dead) { |
|
|
|
pf[y][x / 8] |= shl_table[x & 7]; |
|
|
|
} else { |
|
|
|
t &= ~(1<<(x&7)); |
|
|
|
pf[y][x / 8] &= ~shl_table[x & 7]; |
|
|
|
} |
|
|
|
pf[x/8][y] = t; |
|
|
|
} |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
static cell_t getcell(field_t pf, coord_t x, coord_t y){ |
|
|
|
return ((pf[x/8][y])&(1<<(x&7)))?alive:dead; |
|
|
|
static cell_t getcell(field_t pf, coord_t x, coord_t y) { |
|
|
|
return ((pf[y][x / 8]) & (shl_table[x & 7])) ? alive : dead; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
uint8_t countsurroundingalive(field_t pf, coord_t x, coord_t y){ |
|
|
|
uint8_t countsurroundingalive(field_t pf, coord_t x, coord_t y) { |
|
|
|
|
|
|
|
static int8_t const offset[] = {-1, -1, 0, +1, +1, +1, 0, -1, -1, -1}; |
|
|
|
x += XSIZE; |
|
|
|
y += YSIZE; |
|
|
|
uint8_t i, ret=0; |
|
|
|
for (i = 8; i--;) |
|
|
|
{ |
|
|
|
uint8_t i, ret = 0; |
|
|
|
for (i = 8; i--;) { |
|
|
|
// getcell(...) returns either 0 or 1
|
|
|
|
ret += getcell(pf,(x+offset[i+2])%XSIZE, (y+offset[i])%YSIZE); |
|
|
|
ret += getcell(pf, (x + offset[i+2]) % XSIZE, (y + offset[i]) % YSIZE); |
|
|
|
} |
|
|
|
|
|
|
|
return ret; |
|
|
@ -142,181 +139,175 @@ uint8_t countsurroundingalive(field_t pf, coord_t x, coord_t y){ |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
void nextiteration(field_t dest, field_t src){ |
|
|
|
coord_t x,y; |
|
|
|
void nextiteration(field_t dest, field_t src) { |
|
|
|
coord_t 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; |
|
|
|
for (y = YSIZE; y--;) { |
|
|
|
for (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){ |
|
|
|
#ifdef BITSTUFFED |
|
|
|
static void pfprint(field_t pf) { |
|
|
|
memcpy(pixmap[NUMPLANE - 1], pf, sizeof(field_t)); |
|
|
|
} |
|
|
|
#else |
|
|
|
void pfprint(field_t pf) { |
|
|
|
coord_t x,y; |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
for(y=YSIZE; y--;) { |
|
|
|
for(x=XSIZE; x--;) { |
|
|
|
setpixel((pixel){x,y},getcell(pf,x,y)*3); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
void pfcopy(field_t dest, field_t src){ |
|
|
|
coord_t x,y; |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
setcell(dest,x,y,getcell(src,x,y)); |
|
|
|
} |
|
|
|
} |
|
|
|
static void pfcopy(field_t dest, field_t src) { |
|
|
|
memcpy(dest, src, sizeof(field_t)); |
|
|
|
} |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
#ifndef BITSTUFFED |
|
|
|
uint8_t pfcmp(field_t dest, field_t src){ |
|
|
|
coord_t x,y; |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
if (getcell(src,x,y) != getcell(dest,x,y)) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
static int pfcmp(field_t dest, field_t src) { |
|
|
|
return memcmp(dest, src, sizeof(field_t)); |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef BITSTUFFED |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
uint8_t pfempty(field_t src){ |
|
|
|
uint8_t pfempty(field_t src) { |
|
|
|
coord_t x,y; |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
if (getcell(src,x,y)==alive) |
|
|
|
return 0; |
|
|
|
for(y=YSIZE; y--;) { |
|
|
|
for(x=XSIZE; x--;) { |
|
|
|
if (getcell(src, x, y)==alive) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
uint8_t pfcmp(field_t dest, field_t src){ |
|
|
|
coord_t 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){ |
|
|
|
coord_t x,y; |
|
|
|
for(y=0; y<FIELD_YSIZE; ++y){ |
|
|
|
for(x=0; x<FIELD_XSIZE; ++x){ |
|
|
|
if (src[x][y]!=0) |
|
|
|
uint8_t pfempty(field_t src) { |
|
|
|
coord_t x, y; |
|
|
|
for (y = 0; y < FIELD_YSIZE; ++y) { |
|
|
|
for (x = 0; x < FIELD_XSIZE; ++x) { |
|
|
|
if (src[y][x] != 0) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
void insertglider(field_t pf){ |
|
|
|
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); |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
static void pfinit(field_t pf) |
|
|
|
{ |
|
|
|
coord_t x, y; |
|
|
|
#ifndef BITSTUFFED |
|
|
|
for (y = YSIZE; y--;) { |
|
|
|
for (x = XSIZE; x--;) { |
|
|
|
setcell(pf, x, y, (random8() & 1) ? alive : dead); |
|
|
|
} |
|
|
|
} |
|
|
|
#else |
|
|
|
for (y = 0; y < FIELD_YSIZE; ++y) { |
|
|
|
for (x = 0; x < FIELD_XSIZE; ++x) { |
|
|
|
pf[y][x] = random8(); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
int gameoflife(){ |
|
|
|
void 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; |
|
|
|
coord_t x,y; |
|
|
|
field_t pf1, pf2; |
|
|
|
field_t ldbuf[LOOP_DETECT_BUFFER_SIZE] = {{{0}}}; // loop detect buffer
|
|
|
|
uint8_t ldbuf_idx = 0; |
|
|
|
uint16_t cycle; |
|
|
|
|
|
|
|
//start:
|
|
|
|
/* initalise the field with random */ |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
setcell(pf1,x,y,(random8()&1)?alive:dead); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* initialize the field with random */ |
|
|
|
pfinit(pf1); |
|
|
|
|
|
|
|
#ifdef GLIDER_TEST |
|
|
|
/* initialise with glider */ |
|
|
|
for(y=YSIZE; y--;){ |
|
|
|
for(x=XSIZE; x--;){ |
|
|
|
setcell(pf1,x,y,dead); |
|
|
|
/* initialize with glider */ |
|
|
|
for(y=YSIZE; y--;) { |
|
|
|
for(x=XSIZE; x--;) { |
|
|
|
setcell(pf1, x, y, dead); |
|
|
|
} |
|
|
|
} |
|
|
|
insertglider(pf1); |
|
|
|
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); |
|
|
|
pfprint(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)){ |
|
|
|
pfcopy(pf2, pf1); |
|
|
|
nextiteration(pf1, pf2); |
|
|
|
pfprint(pf1); |
|
|
|
/* loop detection */ |
|
|
|
if (!pfcmp(pf1, pf2)) { |
|
|
|
insertglider(pf1); |
|
|
|
cycle=1; |
|
|
|
cycle = 1; |
|
|
|
} |
|
|
|
if(pfempty(pf1)){ |
|
|
|
if (pfempty(pf1)) { |
|
|
|
/* kill game */ |
|
|
|
return 0; |
|
|
|
return; |
|
|
|
} |
|
|
|
/* */ |
|
|
|
/* */ |
|
|
|
uint8_t i; |
|
|
|
for(i=0; i<LOOP_DETECT_BUFFER_SIZE; ++i){ |
|
|
|
if(!pfcmp(pf1, ldbuf[i])){ |
|
|
|
for (i = 0; i < LOOP_DETECT_BUFFER_SIZE; ++i) { |
|
|
|
if (!pfcmp(pf1, ldbuf[i])) { |
|
|
|
insertglider(pf1); |
|
|
|
cycle=1; |
|
|
|
cycle = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
pfcopy(ldbuf[ldbuf_idx], pf1); |
|
|
|
ldbuf_idx = (ldbuf_idx+1)%LOOP_DETECT_BUFFER_SIZE; |
|
|
|
|
|
|
|
ldbuf_idx = (ldbuf_idx + 1) % LOOP_DETECT_BUFFER_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|