#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define YSIZE 64
#define XSIZE (YSIZE/2)
#define MOVE 1 
#define VGA
#define DIAG

#define SPEED 1

#define ITER  65536
#define r()   (rand()>>4)

int board[2][YSIZE][XSIZE];
unsigned char dboard[YSIZE][XSIZE];
int t=0;

#define FADE 15

#define new(y,x) board[t][(x)][(y)]
#define old(y,x) board[1-t][(x)][(y)]
#define d(y,x)   dboard[(x)][(y)]

#ifdef VGA

#include <vga.h>

void init(void) {
	int r,g,b,x;
	vga_setmode(G320x200x256);
	r=g=b=0;
	for(x=0;x<256;x++) {
#if 0
		if (x<64) 
			r=x*x/64;
		else if (x<128)
			g=(x-64)*(x-64)/64;
		else if (x<192)
			b=(x-128)*(x-128)/64;
		else
			r=g=b=255-(x-192)*(x-192)/64;
#else
		if (x<64) 
			r=x;
		else if (x<128)
			g=(x-64);
		else 
			b=(x-128)/2;
#endif
		vga_setpalette(x,r,g,b);
	}
}

void done(void) {
	vga_setmode(TEXT);
}

void do_plot(int bx) {
#if 0
	static int xx=0,yy=0;
	static int dx=1,dy=1;
	int y;
	
	xx+=dx; if((xx==(320-XSIZE))||(xx==0)) dx=-dx;
	yy+=dy; if((yy==(200-YSIZE))||(yy==0)) dy=-dy;
	for(y=0;y<YSIZE;y++) 
		vga_drawscansegment(dboard[YSIZE-1-y],xx,y+yy,XSIZE);
#else
	int y;
	for(y=0;y<YSIZE;y++)
		vga_drawscansegment(dboard[YSIZE-1-y],bx,y+(200-YSIZE)/2,XSIZE);
#endif
}

#else /* None */
void do_plot(int bx) {}
void done(void) {}
void init(void) {}
#endif

void update(void){
	int x,y,bx;	
/* Most are average of neighbors */
	for(y=SPEED;y<(YSIZE-1);y++)
		for(x=1;x<(XSIZE-1);x++) 
			new(x,y+1)=((
#if defined(DIAG)
				old(x+1,y+1)+
				old(x+1,y  )+
				old(x+1,y-1)+
				old(x  ,y+1)+
				old(x  ,y-1)+
				old(x-1,y+1)+
				old(x-1,y  )+
				old(x-1,y-1)
			)/8)-FADE;
#elif defined(DOWN)
				old(x+1,y  )+
				old(x+1,y-1)+
				old(x  ,y-1)+
				old(x-1,y  )+
				old(x-1,y-1)
			)/5)-FADE;	
#else
				old(x+1,y  )+
				old(x-1,y  )+
				old(x  ,y+1)+
				old(x  ,y-1)
			)/4)-FADE;
#endif
	for(x=1;x<(XSIZE-1);x++)
			new(x,SPEED)=((
#if defined(DIAG)
				old(x+1,1)+
				old(x+1,0)+
				old(x  ,1)+
				old(x-1,1)+
				old(x-1,0)
			)/5)-FADE;
#elif defined(DOWN)
				old(x+1,0)+
				old(x-1,0)
			)/2)-FADE;
#else
				old(x+1,0)+
				old(x-1,0)+
				old(x  ,1)
			)/3)-FADE;
#endif
				
	for(x=1;x<(XSIZE-1);x++) 
		for(y=0;y<SPEED;y++) 
			new(x,y)=0;

/* Borders are all 0 */
	for(y=0;y<YSIZE;y++) new(0,y)=new(XSIZE-1,y)=0; 
				
/* Maybe make a hostspot */
	{
#ifdef 0
		int x0,x1,y0,temp=1024;
		x1=r()%(XSIZE/4)+XSIZE/8;
		x0=r()%(XSIZE-x1); x1+=x0;
#else
#define MINTEMP 512
#define MAXTEMP 1024
#define DTEMP   32
		static int x0=XSIZE/2,temp=(MINTEMP+MAXTEMP)/2; int x1,y0;
		x0+=r()%(MOVE+MOVE+1)-MOVE;
		if(x0<3) x0=3;
		if(x0>(XSIZE*3/4-3)) x0=XSIZE*3/4-3;

		x1=x0+XSIZE/4;
		temp+=r()%(2*DTEMP+1)-DTEMP;
		if(temp<MINTEMP)temp=MINTEMP;
		if(temp>MAXTEMP)temp=MAXTEMP;
#endif
		y0=r()%8; 

		for(x=x0;x<x1;x++)
			for(y=0;y<y0;y++)
				new(x,y)=temp;
		bx=(320-XSIZE)/2-x0;
	}

/* Make sure we're all positive */
	for(y=1;y<YSIZE;y++)
		for(x=1;x<XSIZE;x++) {
			if (new(x,y)<0) new(x,y)=d(x,y)=0;
/*			if (new(x,y)>2048) new(x,y)=2048; */
			if (new(x,y)>1023) d(x,y)=255;
			else d(x,y)=new(x,y)>>2;
		}
	do_plot(bx);
	t=1-t;
}

int main(int argc, char**argv) {
	long t=time(NULL);
	int count=ITER;
	argc==1?srand(t):srand(atoi(argv[1]));
	printf("%ld\n",t);

	init();
	t=time(NULL);
	for(;count--;)
		update();

	done();

	printf("%f frames/second\n",(double)ITER/(time(NULL)-t));
	printf("%f pixels/second\n",(double)XSIZE*YSIZE*ITER/(time(NULL)-t));

	return 0;
}
