/******	Placed into the public domain May '89 - if I wait until I have this
tidied up and properly documented you'll never see it .
		K. McClary	*************/
#include <tos.h>	/*	TURBO C		*/
#include <stdlib.h>	/*	TURBO C	( for atol() )	*/
/*	#include <osbind.h>,OR APPROPRIATE FILE FOR YOUR COMPILER	*/
#define		LORES	0
#define		MEDRES	1
#define		HIRES	2
#define		NATOMS		40000L	/*	max no. of atoms	*/
#define		SCRNINTS	16000L /* screen size = 32000 bytes (NOT 32K!)*/
long natoms;				/*	no. of atoms	*/
int wpos[NATOMS + 1];			/*	word and ...	*/
unsigned int bitpos[NATOMS + 1];	/*  bit position of atoms on screen */
unsigned int fixed[ SCRNINTS ];		/*	fixed atoms and neighbors  */
long nact;				/*	# of Atoms still moving	*/
long val = 0XF314L;			/*	SEE rndize()		*/
int * screenbase;
char buf[100];
int	PLANES;		/*	# OF COLOUR PLANES	*/
int	COLOURS;	/*	# OF COLOURS		*/
int	INTS_LINE;	/*	16 BIT WORDS PER SCREEN LINE*/
int	FUDGE;	
long 	CENTRESCREEN;
main()
{	int res = savescreen();
	screenbase = Physbase();	/*	FIND BASE OF SCREEN	*/
	Cconws( "\033e" );	/*	turn on blinking cursor	*/
	do{
		Cconws( "\"Atoms\" wander randomly around the\r\n" );
		Cconws( "screen until they stick at the center\r\n" );
		Cconws( "or to an atom that is already stuck.\r\n" );
		Cconws( "This takes a while.\r\n" );
		Cconws( "You may wish to save the resulting\r\n" );
		Cconws( "picture with a \"snapshot\" program.\r\n\n" );
		Cconws( "Enter the number of atoms \r\n" );
		Cconws( "( 1 to 40000, 3000 is nice).\r\n\n" );
		Cconws( "Then press ESCAPE to quit.\r\n" );
		buf[ 0 ] = 99;
		Cconrs( buf );
		buf[ buf[ 1 ] + 2 ] = '\0';
		natoms = nact = atol( buf + 2 );
	}while( nact < 1 || nact > NATOMS );
	Cconws( "\033f" );	/*	turn off blinking cursor	*/
	Cconws( "\033E" );	/*	clear screen	*/
	if( res == LORES )
	{	PLANES		=4;
		COLOURS		=16;
		INTS_LINE	=80;
		FUDGE		=0XFFF;
		CENTRESCREEN	=8040L;
	}
	else
	{	PLANES		=1;
		COLOURS		=1;
		INTS_LINE	=40;
		FUDGE		=0X3FFF;
		CENTRESCREEN	=8020L;
	}
	put_atoms();
	fixed[ CENTRESCREEN ] = (unsigned int) 0X8000;	/*  FIX A SPOT    */
	if( res == LORES )
		screenbase[ CENTRESCREEN +3 ] |= 0X8000U;/*  AND COLOUR IT */
	else
		screenbase[ CENTRESCREEN  ] |= 0X8000U;/*   OR WHITE */
	do
	{while( nact > 0 && !Cconis() )
		move( nact - 1, screenbase, wpos, bitpos, PLANES, INTS_LINE );
	}while( Cnecin() != 0X1001BL );		/*****	ESC	*********/
	Cconws( "\033e" );	/*	turn on blinking cursor	*/
	restorescreen();
}
put_atoms()			/* PUT IN ATOMS AT RND POSITIONS */
{	long i;
	int w;
	int r16;
	for(i = 0; i < nact; i++)
	{	while( (w = wpos[i] =( Random() & FUDGE )*PLANES) >= SCRNINTS );
			/*	FUDGE * PLANES ~= 32K; DISCARD ANY >= 32000 */
		r16 = Random() & 0XF;
		bitpos[i] =  0X1 << r16;
		screenbase[ w ] |= bitpos[i];
	}
}
	/*  MOVE EACH ATOM RANDOM STEP  */
move( i, screenbase, wpos, bitpos, planes, ints_line )
register long i;
register int *screenbase;
register int * wpos;
register unsigned int * bitpos;
register int planes;
register int ints_line;
{	register int w;
	register unsigned int btpos;
	register long rnd24;
	register long bmask;
/*	DO THESE ALL GET INTO REGISTERS?			*/
/*	MAYBE FASTER IF planes, ints_line WERE #defines		*/
/*	(I made them variables to run in both HIRES & LORES)	*/
	while( 1 )
	{   rnd24 =	Random();		/*	RANDOM STEP	*/
	    if( rnd24 < val )
		rndize();
/*	Random() is slow so use all 24 bits	*/
	    bmask = 0X1L;
	    while( bmask != 0X400000L )	
	    {   w = wpos[i];
		btpos = bitpos[i];
	        screenbase[ w ] &= ~btpos;
		if( rnd24 & ( bmask <<= 1) )		  /**	VERTICAL  **/
		{	if( rnd24 & (bmask <<= 1) ) 
			{	w += ints_line;
				if( w >= SCRNINTS )
					w -= SCRNINTS;
			}else
			{	w -= ints_line;
				if( w < 0 )
					w += SCRNINTS;
			}wpos[ i ] = w;
		}else				/**	HORIZONTAL	**/
		{	if( rnd24 & ( bmask <<= 1 ))	/**	LEFT	**/
			{	btpos <<= 1;
				if( !btpos )
				{	w -= planes;
					if( w < 0 )
						w += SCRNINTS;
					btpos = 1;
					wpos[ i ] = w;
				}
			}else			/**	RIGHT		**/
			{	btpos >>= 1;
				if( !btpos )
				{	w += planes;
					if( w >= SCRNINTS )
						w -= SCRNINTS;
					btpos = (unsigned int)0X8000;
					wpos[ i ] = w;
				}
			}bitpos[ i ] = btpos;
		}
		screenbase[ w ] |= btpos;
		if( btpos & fixed[ w ] )
			fix( w, btpos, i );
		if( !i-- )
			return;
	   }
	}
}
fix( w, btpos, i, res )
int w;
long i;
unsigned int btpos;
{	int wt, wtt;
	int j;
	int colour = ( nact * (COLOURS - 1) ) / natoms + 1;
	if( res == HIRES )
		colour = 1;
	for( j = 0; j < PLANES; j++ )/** STICK NEW ATOM ONTO SNOWFLAKE	****/
		if( colour & ( 0X1 << j ) )
			screenbase[ w + j ] |= btpos;
	for( wtt = w - INTS_LINE; wtt <= w + INTS_LINE; wtt += INTS_LINE )
	{	wt = wtt;     				/* FIX 8 NEIGHBORS  */
		if( wt < 0 )
			wt += SCRNINTS;
		if( wt >= SCRNINTS )
			wt -= SCRNINTS;
		fixed[ wt ] |= btpos;
		if( btpos & 0X8000 )/* LEFTMOST BIT-FIX RIGHTMOST OF w-PLANES */
		{	if( wt - PLANES < 0 )
				fixed[ wt + SCRNINTS - PLANES] |= 1;
			else
				fixed[ wt - PLANES ] |= 1;
		}else
			fixed[ wt ] |= ( btpos << 1 );
		if( btpos == 1 )		/* RIGHTMOST BIT	*/
		{	if( wt + PLANES >= SCRNINTS )
				fixed[ wt - SCRNINTS - PLANES ] |= 0X8000; 
			else
				fixed[ wt + PLANES ] |= 0X8000; 
		}else
			fixed[ wt ] |= ( btpos >> 1 );
	}
	nact--;
	bitpos[ i ] = bitpos[ nact ];	/*	ATOM # nact BECOMES # i	*/
	wpos[ i ] = wpos[ nact ];
	if(nact < 100 )
		val = 0X2F2747L;  /***	Mix Random() up more often   ***/
}
/*Random() is quite periodic so make a few extra calls to mix things up a bit */
rndize()
{	int i;
	int x = Random() & 0XF;
	for(i = 0; i < x; i++)
		Random();
}

/* STANDARD STUFF TO SAVE & RESTORE RES, COLOURS	*/

int savepalette[16];		/* save original colours	     */
int saveres = 0;				/* save resolution	*/
int gpix_pal[] = {0,0X700,0X730,0X750,0X770,0X570,0X070,0X074,0X077,0X057,
	0X037,0X007,0X507,0X707,0X704,0X777};   /***GRAF-PIX default colours**/
/********************************** savescreen *******************************/
int
savescreen()
{	saveres = Getrez();
	if( saveres == HIRES )
		return( HIRES );
	save_pal();
	if(saveres != LORES)
		Setscreen( -1L, -1L, LORES);
	Setpalette( gpix_pal );
		return( LORES );
}
/************************save colour palette *****************************/
save_pal()
{	int i, x;
	if(saveres == LORES)
		x = 16;
	else
		x = 4;
	for(i = 0; i < x; i++)
		savepalette[i] = Setcolor(i, -1);
}
/******************************** restorescreen *******************************/
restorescreen()
{	if( saveres == HIRES )
		return;
	Setscreen( -1L, -1L, saveres);
	Setpalette( savepalette);
}
/****************************************************** EOF *******/
