[comp.theory.cell-automata] wireworld simulator for UNIX

phillips@cs.ubc.ca (George Phillips) (02/12/90)

Here is my wireworld simulator for UNIX.  It uses curses for the display
so it should work on any reasonable terminal.  I've run it on Sun 3's and
Sun 4's under SunOS 4.0.

WARNING:  This program is almost everything a good program shouldn't be:
inefficient, fragile and inflexible.  It does, however, simulate
wireworld.  It is in the public domain and if you want to claim you
wrote it, please do.

--
George Phillips phillips@cs.ubc.ca {alberta,uw-beaver,uunet}!ubc-cs!phillips

/*
 * wire - simulate the wirewold cellular automaton as described in the
 * Jan. 1990 issue of Scientific American (Computer Recreations, p. 146).
 *
 * The algorithm used is about as stupid as they get.  Big files will
 * almost certainly cause core dumps.  The input file format is rigid.
 *
 *	'='  is a wire
 *  '#'  is an electron head
 *  '-'  is an electron tail
 *  ' '  space
 *  '.'  space, too
 *
 * (watch out for tabs!)
 *
 * Just interrupt the program to quit (^C probably)
 *
 * To compile, use:
 *   cc -o wire wire.c -lcurses -ltermcap
 *
 * (And without the -ltermcap for System V Unix, I think)
 */

#include <stdio.h>
#include <curses.h>
#include <string.h>

char* w1;
char* w2;
char* aworld();

#define SPACE	(0)
#define WIRE	(1)
#define HEAD	(2)
#define TAIL	(3)

main(argc, argv)
int		argc;
char*	argv[];
{
	char	buf[256];
	char*	p;
	char*	q;
	int		line;

	initscr();

	w1 = aworld();
	w2 = aworld();

	line = 1;
	while (fgets(buf, 256, stdin) != NULL) {
		p = w1 + line * COLS + 1;
		for (q = buf; *q; q++) {
			switch (*q) {
			case '=':	*p++ = WIRE; break;
			case '-':	*p++ = TAIL; break;
			case '#':	*p++ = HEAD; break;
			case ' ':
			case '.':	*p++ = SPACE; break;
			case '\n':	break;
			default:
				fprintf(stderr, "bad char (%c) in file\n", *q);
				bye(1);
			}
		}
		line++;
	}

	for (;;) {
		do_gen();
		display();
	}

	bye(0);
}

do_gen()
{
	int	x;
	int	y;
	char* z;
	int count;

#define loc(x, y) (*(w1 + (x) + (y) * COLS))
#define add(x, y) if (loc(x, y) == HEAD) count++

	for (x = 1; x < COLS - 1; x++) {
		for (y = 1; y < LINES - 1; y++) {
			z = w2 + x + y * COLS;
			switch (*(w1 + x + y * COLS)) {
			case SPACE:
				*z = SPACE;
				break;
			case TAIL:
				*z = WIRE;
				break;
			case HEAD:
				*z = TAIL;
				break;
			case WIRE:
				count = 0;
				add(x - 1, y);
				add(x + 1, y);
				add(x - 1, y - 1);
				add(x, y - 1);
				add(x + 1, y - 1);
				add(x - 1, y + 1);
				add(x, y + 1);
				add(x + 1, y + 1);
				if (count == 1 || count == 2)
					*z = HEAD;
				else
					*z = WIRE;
				break;
			default:
				fprintf(stderr, "oops, bad internal character (%d) %c at %d,%d\n",
					*(w1 + x + y * COLS),
					*(w1 + x + y * COLS), x, y);
				sleep(2);
				bye(1);
			}
		}
	}
}

char ch[] = " =#-";

display()
{
	int	x;
	int	y;
	char c;

	for (x = 0; x < COLS; x++)
		for (y = 0; y < LINES; y++) {
			c = *(w2 + x + y * COLS);
			mvaddch(y, x, ch[c]);
			*(w1 + x + y * COLS) = c;
		}
	
	refresh();
}

char* aworld()
{
	char* w;
	int	i;

	w = (char*)malloc(LINES * COLS);
	if (w == NULL) {
		fprintf(stderr, "out of memory!\n");
		bye(1);
	}
	for (i = 0; i < LINES * COLS; i++)
		w[i] = SPACE;

	return(w);
}

bye(ecode)
int	ecode;
{
	mvaddch(LINES - 1, COLS - 1, '\r');
	refresh();
	endwin();
	exit(ecode);
}