#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>


const int X=640, Y=480, XWIDTH=10, YHEIGHT=10, XCOLS=X/XWIDTH, YROWS=Y/YHEIGHT;

int oldgrid[YROWS][XCOLS], newgrid[YROWS][XCOLS];
void *cursor, *cell;

/* erases the two arrays */
void wipe(void)
{
	int i, j;
   for (i=0; i<XCOLS; i++)
	{
		for (j=0; j<YROWS; j++)
		{
			oldgrid[j][i]=0;
			newgrid[j][i]=0;
		}
	}
}

/* clears the screen, draws the grid on it */
void grid(void)
{
	int i, j;
	cleardevice();
   setcolor(1);
  	for (i=0; i<X; i+=XWIDTH)
		line(i,0,i,Y-1);
	for (j=0; j<Y; j+=YHEIGHT)
		line(0,j,X-1,j);
}

/* startup fucntions */
void init(void)
{
	int size;

	wipe();

	/* draw cursor */
	setfillstyle(SOLID_FILL,9);
	bar(0,0,XWIDTH-1,YHEIGHT-1);

	/* get cursor size, allocate memory for cursor */
	size=imagesize(0,0,XWIDTH-1,YHEIGHT-1);
	if ((cursor = malloc(size)) == NULL)
	{
		closegraph();
		printf("Error: not enough heap space in main().\n");
		exit(1);
   }

	/* get cursor image */
	getimage(0,0,XWIDTH-1,YHEIGHT-1,cursor);

	grid();

	/* draw cell */
	setfillstyle(SOLID_FILL,7);
	bar(1,1,XWIDTH-1,YHEIGHT-1);
	putpixel(1,1,0);
	putpixel(XWIDTH-1,1,0);
	putpixel(1,YHEIGHT-1,0);
	putpixel(XWIDTH-1,YHEIGHT-1,0);
	putpixel(XWIDTH/2+0,YHEIGHT/2+0,15);

	/* get cell size, allocate memory for cell */
	size=imagesize(1,1,XWIDTH-1,YHEIGHT-1);
	if ((cell = malloc(size)) == NULL)
	{
		closegraph();
		printf("Error: not enough heap space in main().\n");
		exit(1);
   }

	/* get cell image, remove it */
	getimage(1,1,XWIDTH-1,YHEIGHT-1,cell);
	getch();
	putimage(1,1,cell,XOR_PUT);
}

/* calculates the number of neighbours a cell has */
int getneighbours(const int x, const int y)
{
	int i, j, k=0, l, m;
	for (i=x-1; i<=x+1; i++)
	{
		m=i;
		if (i==-1) m=XCOLS-1;
		if (i==XCOLS) m=0;

		for (j=y-1; j<=y+1; j++)
		{
			if (i==x && j==y) continue;
			l=j;
			if (j==-1) l=YROWS-1;
			if (j==YROWS) l=0;
			k+=oldgrid[l][m];
		}
	}
	return(k);
}

/* increase the generation by one */
void update(void)
{
	/* determine if cell lives or dies */
	int i, j, k;
	for (i=0; i<XCOLS; i++)
	{
		for (j=0; j<YROWS; j++)
		{
			k=getneighbours(i,j);
			if (k==3) newgrid[j][i]=1;
			else if (k!=2) newgrid[j][i]=0;
			if (oldgrid[j][i]!=newgrid[j][i])
				putimage(i*XWIDTH+1,j*YHEIGHT+1,cell,XOR_PUT);

		}
	}

	/* oldgrid=newgrid */
	for (i=0; i<XCOLS; i++)
	{
		for (j=0; j<YROWS; j++)
			oldgrid[j][i]=newgrid[j][i];
	}
}

int main(void)
{
   /* request auto detection */
	int gdriver = DETECT, gmode = VGAHI, errorcode;

	/* initialize graphics and local variables */
	initgraph(&gdriver, &gmode, "");

   /* read result of initialization */
   errorcode = graphresult();
   if (errorcode != grOk)  /* an error occurred */
   {
      printf("Graphics error: %s\n", grapherrormsg(errorcode));
      printf("Press any key to halt:");
      getch();
      exit(1); /* terminate with an error code */
	}

	int i, x=XCOLS/2, y=YROWS/2, loop=0, user;

	init();

	/* main loop */
	do
	{
		do
		{
			user=0;
			i=0;

			/* flash cursor, test if input */
			do
			{
				delay(5);
				if (kbhit()) user=1;
			} while (user!=1 && i++<50);

			putimage(x*XWIDTH,y*YHEIGHT,cursor,XOR_PUT);

			i=0;
         do
			{
				delay(5);
				if (kbhit()) user=1;
			} while (user!=1 && i++<50);

			putimage(x*XWIDTH,y*YHEIGHT,cursor,XOR_PUT);
		} while (user !=1);

		/* handle input */
		switch (getch())
		{
			case 'k': loop=1; break;		// end
			case 13: update(); break;		// update
			case 'c': case 'C': wipe(); grid(); break;		// clear screen

			/* change cell contents */
			case ' ': oldgrid[y][x]=1-oldgrid[y][x];
				newgrid[y][x]=1-newgrid[y][x];
				putimage(x*XWIDTH+1,y*YHEIGHT+1,cell,XOR_PUT); break;

         /* cursor movement */
			case 0: switch (getch())
			{
				case 'H': y-=1; if (y==-1) y=YROWS-1; break;
				case 'P': y+=1; if (y==YROWS) y=0; break;
				case 'K': x-=1; if (x==-1) x=XCOLS-1; break;
				case 'M': x+=1; if (x==XCOLS) x=0; break;
			}
		}

	} while (loop==0);

	free(cursor);
	free(cell);
   closegraph();
   return 0;
}
