crashtest-r0ket/firmware/l0dable/nick_life.c

270 lines
7.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <sysinit.h>
#include "basic/basic.h"
#include "lcd/print.h"
#include "lcd/render.h"
#include "lcd/display.h"
#include "basic/config.h"
#include "usetable.h"
#define BITSET_X (RESX+2)
#define BITSET_Y (RESY+2)
#define BITSET_SIZE (BITSET_X*BITSET_Y)
#define BITSETCHUNKSIZE 32
#define one ((uint32_t)1)
struct bitset {
uint16_t size;
uint32_t bits[BITSET_SIZE/BITSETCHUNKSIZE+1];
};
typedef uint8_t uchar;
int pattern=0;
#define PATTERNCOUNT 3
uchar stepmode=0;
uchar randdensity=0;
static unsigned long iter=0;
struct bitset _life;
#define life (&_life)
static void draw_area();
static void calc_area();
static void random_area(struct bitset *area, uchar x0, uchar y0, uchar x1, uchar y1,uchar value);
static void reset_area();
void ram(void) {
getInputWaitRelease();
reset_area();
random_area(life,1,1,RESX,RESY,40);
static int nickx=2,nicky=10;
signed char movy=1;
static int nickwidth,nickheight;
static int nickoff=10;
static char delay=10;
static char speedmode=0;
static char LCDSHIFTX_EVERY_N=2;
static char LCDSHIFTY_EVERY_N=2;
static char ITER_EVERY_N=1;
lcdClear();
setExtFont(GLOBAL(nickfont));
nickwidth=DoString(nickx,nicky,GLOBAL(nickname));
if(nickwidth<50)nickoff=30;
nickheight=getFontHeight();
char stepmode=0;
while (1) {
draw_area(); // xor life pattern over display content
lcdDisplay();
lcdClear();
// draw_area(); // xor life pattern again to restore original display content
// Old shift code. Can't handle longer Nicks...
// if(iter%LCDSHIFT_EVERY_N==0) lcdShift(1,-2,1);
// if(iter%LCDSHIFT_EVERY_N==0) { nickx=(nickx+1)%100-nickwidth; nicky=(nicky+1)%50;}
if(iter%LCDSHIFTX_EVERY_N==0) { nickx--;
if(nickx<(-1*nickwidth-nickoff))nickx=0; }
if(iter%LCDSHIFTY_EVERY_N==0) { nicky+=movy;
if(nicky<1 || nicky>RESY-nickheight) movy*=-1; }
DoString(nickx,nicky,GLOBAL(nickname));
DoString(nickx+nickwidth+nickoff,nicky,GLOBAL(nickname));
if(nickwidth<RESX) DoString(nickx+2*(nickwidth+nickoff),nicky,GLOBAL(nickname));
char key=stepmode?getInputWait():getInputRaw();
stepmode=0;
switch(key) {
case BTN_ENTER:
return;
case BTN_RIGHT:
getInputWaitRelease();
speedmode=(speedmode+1)%7;
delay=15;
switch(speedmode) {
case 0:
ITER_EVERY_N=1; LCDSHIFTX_EVERY_N=1; LCDSHIFTY_EVERY_N=1; break;
case 1:
ITER_EVERY_N=1; LCDSHIFTX_EVERY_N=2; LCDSHIFTY_EVERY_N=2; break;
case 2:
ITER_EVERY_N=1; LCDSHIFTX_EVERY_N=4; LCDSHIFTY_EVERY_N=4; break;
case 3:
ITER_EVERY_N=2; LCDSHIFTX_EVERY_N=1; LCDSHIFTY_EVERY_N=1; break;
case 4:
ITER_EVERY_N=4; LCDSHIFTX_EVERY_N=1; LCDSHIFTY_EVERY_N=1; break;
case 5:
ITER_EVERY_N=8; LCDSHIFTX_EVERY_N=1; LCDSHIFTY_EVERY_N=1; break;
case 6:
delay=5; ITER_EVERY_N=8; LCDSHIFTX_EVERY_N=1; LCDSHIFTY_EVERY_N=1; break;
}
break;
case BTN_DOWN:
stepmode=1;
getInputWaitRelease();
break;
case BTN_LEFT:
pattern=(pattern+1)%PATTERNCOUNT;
case BTN_UP:
stepmode=1;
reset_area();
getInputWaitRelease();
break;
}
delayms_queue_plus(delay,0);
#ifdef SIMULATOR
fprintf(stderr,"Iteration %d - x %d, y %d \n",iter,nickx,nicky);
#endif
if(iter%ITER_EVERY_N==0) calc_area(); else ++iter;
}
return;
}
static inline void bitset_set(struct bitset *bs,uint16_t index, uint8_t value) {
uint16_t base=index/BITSETCHUNKSIZE;
uint16_t offset=index%BITSETCHUNKSIZE;
if(value) {
bs->bits[base]|=(one<<offset);
} else {
bs->bits[base]&=~(one<<offset);
}
}
static inline void bitset_xor(struct bitset *bs,uint16_t index, uint8_t value) {
uint16_t base=index/BITSETCHUNKSIZE;
uint16_t offset=index%BITSETCHUNKSIZE;
if(value) {
bs->bits[base]^=(one<<offset);
}
}
static inline uint8_t bitset_get(struct bitset *bs,uint16_t index) {
uint16_t base=index/BITSETCHUNKSIZE;
uint16_t offset=index%BITSETCHUNKSIZE;
return (bs->bits[base]&(one<<offset))==(one<<offset);;
}
static inline uint16_t bitset_offset2(uint8_t x, uint8_t y) {
return ((uint16_t)x)+((uint16_t)y)*BITSET_X;
}
static inline void bitset_set2(struct bitset *bs, uint8_t x, uint8_t y, uint8_t value) {
bitset_set(bs,bitset_offset2(x,y),value);
}
static inline void bitset_xor2(struct bitset *bs, uint8_t x, uint8_t y, uint8_t value) {
bitset_xor(bs,bitset_offset2(x,y),value);
}
static inline uint8_t bitset_get2(struct bitset *bs,uint8_t x,uint8_t y) {
return bitset_get(bs,bitset_offset2(x,y));
}
static void fill_area(struct bitset *area, uchar x0, uchar y0, uchar x1, uchar y1,uchar value) {
for(uchar x=x0; x<=x1; ++x) {
for(uchar y=y0; y<=y1; ++y) {
bitset_set2(area,x,y,value);
}
}
}
static void draw_area() {
for(uchar x=0; x<RESX; ++x) {
for(uchar y=0; y<RESY; ++y) {
lcdSetPixel(x,y,lcdGetPixel(x,y)^bitset_get2(life,x+1,y+1));
}
}
}
static void copy_col(uint8_t columnindex, uint8_t *columnbuffer) {
for(uchar y=0; y<=RESY+1; ++y) {
columnbuffer[y]=bitset_get2(life,columnindex,y);
}
}
static void calc_area() {
++iter;
// sweeping mutation point
static uint8_t xiter=0;
static uint8_t yiter=0;
xiter=(xiter+1)%RESX;
if(xiter==0) yiter=(yiter+1)%RESY;
bitset_set2(life,xiter+1,yiter+1,1);
// remember just two columns
// these don´t have to be static, so if the stack is big enoguh put them there and save another 200 bytes?
static uint8_t _a[RESY+2],*left=_a;
static uint8_t _b[RESY+2],*middle=_b;
copy_col(0,left);
copy_col(1,middle);
for(uchar x=1; x<=RESX; ++x) {
for(uchar y=1; y<=RESY; ++y) {
uchar sum=bitset_get2(life,x+1,y-1)+bitset_get2(life,x+1,y)+bitset_get2(life,x+1,y+1)+
left[y-1]+left[y]+left[y+1]+middle[y-1]+middle[y+1];
bitset_set2(life,x,y,sum==3||(sum==2&&bitset_get2(life,x,y)));
}
// temp-less swap of buffer pointers
left+=(uint32_t)middle;
middle=left-(uint32_t)middle;
left=left-(uint32_t)middle;
copy_col(x+1,middle);
}
}
static void reset_area() {
fill_area(life,0,0,RESX+1,RESY+1,0);
switch(pattern) {
case 0: // R pentomino
bitset_set2(life,41,40,1);
bitset_set2(life,42,40,1);
bitset_set2(life,41,41,1);
bitset_set2(life,40,41,1);
bitset_set2(life,41,42,1);
break;
case 1: // block in the center, continuous generators at the edges
for(int i=0; i<RESX/2+3; ++i) bitset_set2(life,i,0,1);
// for(int i=0; i<RESY; ++i) bitset_set2(life,0,i,1);
// for(int i=0; i<RESY/2-20; ++i) bitset_set2(life,RESX+1,RESY-i,1);
// for(int i=0; i<RESX/2; ++i) bitset_set2(life,RESX-i,RESY+1,1);
bitset_set2(life,40,40,1);
bitset_set2(life,41,40,1);
bitset_set2(life,42,40,1);
bitset_set2(life,42,41,1);
bitset_set2(life,42,42,1);
bitset_set2(life,40,41,1);
bitset_set2(life,40,42,1);
break;
#if 0
case 2: // _|^|_
bitset_set2(life,40,40,1);
bitset_set2(life,41,40,1);
bitset_set2(life,42,40,1);
bitset_set2(life,42,41,1);
bitset_set2(life,42,42,1);
bitset_set2(life,40,41,1);
bitset_set2(life,40,42,1);
break;
#endif
}
}
#ifdef SIMULATOR
extern uint32_t getRandom(void);
#endif
static void random_area(struct bitset *area, uchar x0, uchar y0, uchar x1, uchar y1,uchar value) {
for(uchar x=x0; x<=x1; ++x) {
for(uchar y=y0; y<=y1; ++y) {
bitset_set2(area,x,y,(getRandom()>>24)<value);
}
}
}