From: james@panix.com (James Britt)
Subject: Wolfram CA C source code
Date: Tue, 17 Nov 1992 06:12:08 GMT
Organization: PANIX Public Access Unix & Internet, NYC

/************************************************************************
					November 1992

This is a cellular automata that implements a line automata
described in Stephan Wolfram's book, Theory and Aplications of
Cellular Automata.  In this model, any cell in the array may have
one of two states, 1 or 0.  The next state is determined by taking
each cell, along with its immediate neighbors, and using the three
bits to create a binary number:

i.e.,	        |0|1|1|  -> 3
		|1|1|0|  -> 6

So, unlike many automatas, the order of the bits matters.

This number is used to index the state transition rule table.  Three
bits can create a number from 0 to 7, so each rule will be a string
of 8 bits.  Thus, you can have 256 different rules.

This program gives you three options:

You can run the automata in "standard" mode, and see the results
of any given rule table.  Or, you can "mesh" two almost-alike
automata, and see how a small difference in the initial array
propagates differences as time goes by.   This is something
Wolfram does in his book.  He ran two automatas, each with the
same rule, and same starting conditions, except that in the second
one, he flipped a middle bit in the starting array.  Then, for
each generation, he would compare the two arrays, and only display
those cells where the two differed.  Aside from producing some
interesting pictures, this allows you to see how the individual
cells are dependant on each other for information propagation.
This property is interesting to observe, and you may want to think
about what it tells us about a given rule.

The third option is to display the standard CA with the
difference pattern overlayed.

The code is written in Turbo C++, 3.0.  I've put the graphic routines
in functions to make it easier to convert to whatever C you might
have.  There a few features I would like to add at some point, such
as saving a screen to a GIF file, and automatically executing each rule
from 0 to 127, saving the results.

What I would really like to see is a project similar to Fractint, the
large, public domain fractal program.  Fractint consists of a wide range
of fractal routines, contributed by a numerous people.  The code and
executable are re-distributed regularly as the program is updated.

Why not have a large, multi-function cellular automata program?  One
that could produce Life; hodge-podge; multi-state line automata; "rug"
generators, etc...

Anyway, here it is.



	James Britt
	james@panix.com
	(Compu$erve 73417,2776)


***********************************************************************/


#include <dos.h>
#include <math.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>

#define		ARRAYSIZE	640

typedef        struct
		{
			int	rulenumber;
			int	choice;
		} menu_struct;


void    Menu( menu_struct *);
void	GraphicsOn();
void	GraphicsOff();
void	InitStart();
void	Update();
void	Generate();
void	Display( int *, int, int * );
void	OverDisplay( int *, int, int * );
void	ShowRule( int );
void	SaveRule( int);
void	ReadRule(int );
void	MakeTable( int, int * );
void	ClearScreen();
void	Mesh( int *, int *, int * );

main(void)
{
menu_struct	menuchoice;
int	YSIZE = 480;
int	x, y, z;
char	c, mesh, overlay;
int	array1[ARRAYSIZE], array2[ARRAYSIZE];
int	duplicate1[ARRAYSIZE], duplicate2[ARRAYSIZE], dub[ARRAYSIZE];
int	ruletable[8], colors[2], colors2[2];



	clrscr();
	y = 0;
	colors[0] = WHITE;
	colors[1] = CYAN;
	colors2[0] = CYAN;
	colors2[1] = RED;

	Menu( &menuchoice );

	MakeTable( menuchoice.rulenumber,  ruletable );
	InitStart( array1, duplicate1 );
	GraphicsOn();
	while( 1 )
	{
		Generate( array1,  array2,  ruletable );


		if( menuchoice.choice < 2 )
			Display( array1,  y, colors );

		if( menuchoice.choice == 2 )
		{
			Generate( duplicate1,  duplicate2,  ruletable );
			Mesh( array1,  duplicate1,  dub );
			Display( dub,  y, colors2 );
		}

		if( menuchoice.choice > 2 )
		{
			Generate( duplicate1,  duplicate2,  ruletable );
			Mesh( array1,  duplicate1,  dub );
			Display( array1,  y, colors );
			OverDisplay( dub, y, colors2 );
		}


		y++;

		y%=YSIZE;

		if( y == 0 )
			ClearScreen();

		Update( array1,  array2 );
		Update( duplicate1, duplicate2 );
		if( kbhit() )
		{
			c = getch();
			if( c == 'x')
			{
				GraphicsOff();
				return;
			}
			if( c == 's')
				ShowRule(  menuchoice.rulenumber  );
			if( c == 'n')
			{
				GraphicsOff();
				Menu( &menuchoice );
				MakeTable( menuchoice.rulenumber,  ruletable );
				InitStart( array1, duplicate1 );
				GraphicsOn();
				cleardevice();
				y = 1;
			}

		}



	}
//	GraphicsOff();

// return;

}	/* end main()  */

/**************************************************************************
*
* void	Menu( menu_struct *menuchoice )
*
* Displays the options for this automata, returning the user's choice.
*
****************************************************************************/


void	Menu( menu_struct	*menuchoice )
{

	clrscr();
	printf("\n	     	   The Wolfram CA Program\n");
	printf("\n   	     Please send comments to james@panix.com");
	printf("\n\n\n\n");
	printf("This automata has only two states: on and off.\n");
	printf("Each cell has only two neighbors, left and right.\n");
	printf("However, order matters.  |1|0|0| is different than |0|0|1|.\n");
	printf("This allows 2^3 different states, 0 to 7 as writen in binary.\n");
	printf("So, for each possible state, you must decide what the next \n");
	printf("state will be. 2^8 different state tables, 0 to 255 as writen in binary.\n");
	printf("\n\n\n");
	printf("Please enter a number from 0 to 255 for the state table:");
	scanf("%d", &menuchoice->rulenumber );
	printf("\nPlease select a display choice:\n\n");
	printf("1:	Show just the automata.\n");
	printf("2:	Show just the difference pattern.\n");
	printf("3:	Show the difference pattern overlayed on the automata.\n");
	printf("\n? ");
	scanf( "%d", &menuchoice->choice );
	return;
}

/**************************************************************************
*
* void	GraphicsOn()
*
* Initializes the graphics, TC++ style.
*
****************************************************************************/

void	GraphicsOn()
{

	int    ErrorCode;		/* Reports any graphics errors		*/
	int    GraphDriver;		/* The Graphics device driver		*/
	int    GraphMode;		/* The Graphics mode value		*/

	GraphDriver = DETECT; 		/* Request auto-detection	*/
	initgraph( &GraphDriver, &GraphMode, "" );
	ErrorCode = graphresult();		/* Read result of initialization*/
	if( ErrorCode != grOk ){		/* Error occured during init	*/
	printf(" Graphics System Error: %s\n", grapherrormsg( ErrorCode ) );
	exit( 1 );
}

return;
}
/**************************************************************************
*
*   void	GraphicsOff()
*
*   Turns off the graphics.
*
****************************************************************************/

void	GraphicsOff()
{
	closegraph();
	return;
}
/**************************************************************************
*
* void	InitStart( int array1[ARRAYSIZE], int	duplicate1[ARRAYSIZE] )
*
* Creates identical random starting arrays for the automatas, then
* flips the middle bit in the duplicate array.
*
****************************************************************************/

void	InitStart( int array1[ARRAYSIZE], int	duplicate1[ARRAYSIZE] )
{
	int	x, y, z;
	for( x = 0; x < ARRAYSIZE; x++ )
	{
		array1[x] = rand()%2;
		duplicate1[x] = array1[x];
	}

	if(duplicate1[(int)ARRAYSIZE/2] == 1)
		duplicate1[(int)ARRAYSIZE/2] = 0;
	else
		duplicate1[(int)ARRAYSIZE/2] = 1;
	/*	flip middle bit	*/

	return;
}

/**************************************************************************
*
* void	ShowRule( int rulenumber  )
*
* Displays the current rule, and allows you to save the rule, plus a
* brief description, to a file, by calling SaveRule().
*
****************************************************************************/

void	ShowRule( int rulenumber  )
{
	char	c;

	GraphicsOff();
	clrscr();
	printf("\n\n\n\n");
	printf("\The rule is %d", rulenumber );
	printf("\nEnter 's' to save the rule.  Press any other key to continue.");
	flushall();
	c = getch();
	if( c == 's')
		SaveRule(rulenumber);

	GraphicsOn();

	return;
}
/**************************************************************************
*
* void	MakeTable( int rulenumber, int ruletable[8] )
*
* Creates the state transistion rule table from the rule number given
* by the user.
*
****************************************************************************/

void	MakeTable( int rulenumber, int ruletable[8] )
{
	int	x, MASK = 01;

	printf("%d looks like this: ", rulenumber);

	for( x = 0; x < 8; x++)
	{
		ruletable[x] = rulenumber&MASK;
		rulenumber = rulenumber>>1;
		printf("%d ", ruletable[x]);

	}
	printf("\n");
	delay(1000);
	return;
}
/**************************************************************************
*
*  void	  Update(int array1[], int array2[] )
*
*  Copies one array to another.
*
****************************************************************************/

void	Update(int array1[], int array2[] )
{
	int	x;
	for( x = 0; x < ARRAYSIZE; x++ )
		array1[x] = array2[x];

	return;
}

/**************************************************************************
*
* void	Generate(int array1[ARRAYSIZE], int array2[ARRAYSIZE], int ruletable[8] )
*
*  Creates the next line in the automata.
*
****************************************************************************/

void	Generate(int array1[ARRAYSIZE], int array2[ARRAYSIZE], int ruletable[8] )
{
	int	x, number;
	for( x = 1; x < ARRAYSIZE-1; x++ )
	{
	 number = array1[x-1]*4 + array1[x]*2 + array1[x+1];
	 array2[x] = ruletable[number];
	}
										    //	number = array1[ARRAYSIZE-1]*4 + array1[0]*2 + array1[1];      screen wrap
	number =  array1[0]*2 + array1[1];
	array2[0] = ruletable[number];

										//	number = array1[ARRAYSIZE-2]*4 + array1[ARRAYSIZE-1]*2 + array1[0];    screen wrap
	number = array1[ARRAYSIZE-2]*4 + array1[ARRAYSIZE-1]*2;
	array2[ARRAYSIZE-1] = ruletable[number];

	return;
}
/**************************************************************************
*
*  void	SaveRule( int  rulenumber )
*
*  Saves the rule ( by appending) to a file called "wolfca.dat"
*
*  (There should be a GetRule(), but...)
****************************************************************************/


void	SaveRule( int  rulenumber )
{
	char	description[40];
	FILE	*fp;

	printf("\nPlease enter a short description of the rule:");
	gets( description );

	fp = fopen("wolfca.dat", "a" );
	fprintf	(fp,"%d %s\n", rulenumber, description );
	fclose(fp);

	return;
}
/**************************************************************************
*
* void	Display( int array1[ARRAYSIZE], int y, int colors[2] )
*
* Diplays the contents of the array to the screen.
*
****************************************************************************/

void	Display( int array1[ARRAYSIZE], int y, int colors[2] )
{
	int	x;

	for( x = 0; x < ARRAYSIZE; x++ )
		putpixel( x, y, colors[ array1[x] ]  );


return;

}

/**************************************************************************
*
* void	OverDisplay( int array1[ARRAYSIZE], int y, int colors[2] )
*
* Diplays the contents of the mesh array to the screen, only plotting 1's.
*
****************************************************************************/

void	OverDisplay( int array1[ARRAYSIZE], int y, int colors[2] )
{
	int	x;

	for( x = 0; x < ARRAYSIZE; x++ )
	if( array1[x] == 1 )
		putpixel( x, y, colors[ array1[x] ]  );


return;

}

/**************************************************************************
*
*  void	ClearScreen()
*
*  Makes a beep sound, then waits for a keypress, then clears the
*  graphics didplay.
*
****************************************************************************/

void	ClearScreen()
{
      int	x;

      for( x = 0; x < 20000; x++ )
      {
	     sound(2100);
	     sound(900);
      }

      nosound();
      getch();

      cleardevice();

return;

}

/**************************************************************************
*
* void	SaveScreen()
*
* Saves the contents of the screen to a file.
* Not fully implemented yet.  Play with it!
*
****************************************************************************/




void	SaveScreen()
{
	#define	XSIZE	640/8
	#define	YSIZE	480

	FILE		*fd;
	int		x, y, z;
	unsigned char	screen[XSIZE][YSIZE], bit;


	for( y = 0; y < 480; y++ )
		for( x = 0; x < 640; x+=8 )
		{
			for( z = 7; z > -1; z-- )
			{
				bit = getpixel(x+z, y);
				bit = bit<<z;
				screen[x][y] = screen[x][y] | bit;
			}

		 }

       fd = fopen( "screen.dat", "wt" );

       for( y = 0; y < YSIZE; y++ )
       {
		for( x = 0; x < XSIZE; x++ )
			fprintf( fd, "%c", screen[x][y] );

		fprintf( fd, "\n" );
       }

       return;
}	/*	end SaveScreen()	*/

/**************************************************************************
*
*   void	Mesh( int array1[ARRAYSIZE], int duplicate1[ARRAYSIZE],
*                     int dub[ARRAYSIZE] )
*
*   Compares the results of two arrays and puts the result in a third array.
*
****************************************************************************/

void Mesh(int array1[ARRAYSIZE],int duplicate1[ARRAYSIZE],int dub[ARRAYSIZE] )
{
	int	x;
	FILE    *fd;

	for( x = 0; x < ARRAYSIZE; x++)
	{
		if( array1[x] == duplicate1[x])
			dub[x] = 0;
		else
			dub[x] = 1;
	}

	return;
}

-- 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Just another speed-metal vegetarian anarchist cyberhippie Zen Socratic...
Diblo Rules!                                        Hack The Wetware!
james@panix.com  .............................................................
Newsgroups: comp.theory.cell-automata