
/* define this for debugging */
/* #define NOGRAPHICS */



/**
*	blobs -	by Russell Wallace
*		Linux port by Gil Nardo (gil@netcom.com)
**/
#include <stdlib.h>
#include <stdio.h>
#include "vga.h"

#define drawblob(_i_,_j_)	drawtheblob(_i_,_j_,(_i_)+1)
#define eraseblob(_i_,_j_)	drawtheblob(_i_,_j_,0)

const MAXSPEED = 6;

extern void msleep(unsigned long msecs);

typedef struct tagBLOB {
	int x, y, dx, dy;
} BLOB;

int minx,miny,maxx,maxy;
BLOB **v;
unsigned long iterations;

#ifndef MIN
# define MIN(_x_,_y_) ( ( (_x_) < (_y_) ) ? (_x_) : (_y_) )
#endif

int nowpen = 2;

void
open_scene()
{
	int mode = 4;
#ifndef NOGRAPHICS
	vga_setmode(mode);
#endif
	return;
}

void
close_scene()
{
#ifndef NOGRAPHICS
	vga_setmode(TEXT);
#endif
	return;
}

void
getdims(int *max_x, int *max_y)
{
#ifndef NOGRAPHICS
	*max_x = vga_getxdim() - 1;
	*max_y = vga_getydim() - 1;
#else
	*max_x = 639;
	*max_y = 479;
#endif
}

void
plotpen(int whichcolor)
{
	nowpen = whichcolor;
#ifndef NOGRAPHICS
	vga_setcolor(whichcolor);
#endif
	return;
}


void
drawtheblob (int i,int j, int thiscol)
{
	int x = v[i][j].x;
	int y = v[i][j].y;
#ifndef NOGRAPHICS
	plotpen(thiscol);
	vga_drawpixel(x, y);
	vga_drawpixel(x+1, y);
	vga_drawpixel(x, y+1);
	vga_drawpixel(x+1, y+1);
#endif
}

void
zapblob(int i, int j, int x1, int y1, int x2, int y2)
{
#ifndef NOGRAPHICS
	plotpen(15);
	vga_drawline(x1,y1,x2,y2);
	msleep (50);
	eraseblob (i,j);
	plotpen(0);
	vga_drawline(x1,y1,x2,y2);
#endif
}

char *mess[] = {
	"blobs by Russell Wallace  \n",
	"Linux port by Gil Nardo (gil@netcom.com) \n",
	"Simulates activity of different colored blobs using\n",
 	"available graphics capability.\n\n",
	"Usage: blobs n i r f [seed]\n\n",
	"n = number of different colors of blobs\n",
	"i = initial number of blobs of each color\n",
	"r = rate of reproduction of blobs\n",
	"f = range at which one blob can fire at another\n",
	"seed = optional random seed\n\n",
	"e.g. blobs 15 10 20 50\n",
	"Press control-c to stop.\n",
	0
};

void
showiters(void)
{
	printf ("%lu iterations.\n",iterations);
	return;
}

main (int argc,char **argv)
{
	int n,init,r,f,dx,dy,i,j,vsize,t;
	int *nb;
	long lvsize,totmem;
	char **tptr;

	if (argc < 5)
	{
		for(tptr = mess; *tptr; tptr++)
			fprintf(stderr, "%s", *tptr);
		exit(0);
	}
	atexit(showiters);
	open_scene();
	getdims(&maxx, &maxy); /* assumes minx and miny are 0 */
	minx = 0;
	miny = 0;
	dx = maxx - minx + 1;
	dy = maxy - miny + 1;
	n = MIN(atoi(argv[1]), 15);
	init = atoi (argv[2]);
	r = atoi (argv[3]);
	f = atoi (argv[4]);
	if (argc > 5)
		srand(atoi(argv[5]));
	totmem = dx * dy - 0x1000;
	lvsize = (totmem / n) / sizeof (BLOB);
	if (lvsize > 0xffe0 / sizeof (BLOB))
		lvsize = 0xffe0 / sizeof (BLOB);
	vsize = lvsize;
	v = (BLOB **)malloc(sizeof(BLOB *) * n);
	nb = (int *)malloc(sizeof(int) * n);
	for (i=n; i--;)
	{
		v[i] = (BLOB *)malloc(sizeof(BLOB) * vsize);
		nb[i] = init;
	}
	for (i=n; i--;)
		for (j=init; j--;)
		{
			v[i][j].x = minx + rand () % dx;
			v[i][j].y = miny + rand () % dy;
			v[i][j].dx = rand () % (MAXSPEED*2+1) - MAXSPEED;
			v[i][j].dy = rand () % (MAXSPEED*2+1) - MAXSPEED;
			drawblob (i,j);
		}
	t = r;
	for (;;)
	{
		iterations++;
		if (--t < 0)
		{
			for (i=n; i--;)
			{
				j = nb[i];
				t = 0;
				while (j != vsize && j != nb[i]*2)
				{
					v[i][j].x = v[i][t].x;
					v[i][j].y = v[i][t].y;
					v[i][j].dx = rand () % (MAXSPEED*2+1) - MAXSPEED;
					v[i][j].dy = rand () % (MAXSPEED*2+1) - MAXSPEED;
					j++;
					t++;
				}
				nb[i] = j;
			}
			t = r;
		}
		for (i=n; i--;)
		{
			for (j=nb[i]; j--;)
			{
				eraseblob (i,j);
				v[i][j].dx += rand () % 3 - 1;
				if (v[i][j].dx > MAXSPEED)
					v[i][j].dx = MAXSPEED;
				if (v[i][j].dx < -MAXSPEED)
					v[i][j].dx = -MAXSPEED;
				v[i][j].x += v[i][j].dx;
				if (v[i][j].x < minx || v[i][j].x > maxx)
				{
					v[i][j].dx = -v[i][j].dx;
					v[i][j].x += v[i][j].dx;
				}
				v[i][j].dy += rand () % 3 - 1;
				if (v[i][j].dy > MAXSPEED)
					v[i][j].dy = MAXSPEED;
				if (v[i][j].dy < -MAXSPEED)
					v[i][j].dy = -MAXSPEED;
				v[i][j].y += v[i][j].dy;
				if (v[i][j].y < miny || v[i][j].y > maxy)
				{
					v[i][j].dy = -v[i][j].dy;
					v[i][j].y += v[i][j].dy;
				}
				drawblob (i,j);
			}
			for (j=nb[i]; j--;)
			{
				int i2,j2,x1,y1,x2,y2,xx,yy;
				for (i2=n; i2--;)
					if (i2 != i)
					{
						for (j2=nb[i2]; j2--;)
						{
							x1 = v[i][j].x;
							x2 = v[i2][j2].x;
							xx = x1 - x2;
							if (xx < 0)
								xx = -xx;
							y1 = v[i][j].y;
							y2 = v[i2][j2].y;
							yy = y1 - y2;
							if (yy < 0)
								yy = -yy;
							if (xx + yy <= f)
							{
								zapblob(i2,j2, x1, y1, x2, y2);
								memmove (&v[i2][j2],&v[i2][j2+1],(nb[i2]-j2) * sizeof (BLOB));
								nb[i2]--;
								j2 = i2 = 0;
							}
						}
					}
			}
		}
	}
}
