[comp.theory.cell-automata] wireworld simulator for IBM PC

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

Here is my wireworld simulator for the PC.  I compiled it using
Turbo-C 2.0, but any version of Turbo-C should do.  It uses text
characters for the display.

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 wireworld as described in "Computer Recreations",
 * Scientific American, Jan. 1990, p. 146
 *
 * A real dumb-o algorithm is used.
 *
 * use: wire wire-file
 *
 * A wire-file uses '=' for a wire cell, '.' or ' ' for a space cell,
 * '#' for an electron head and '-' for an electron tail.
 *
 * The program waits for a key after each generation and quits if it
 * gets a 'q' or ESC.
 */

#include <stdio.h>
#include <conio.h>

#define MX	(80)
#define MY	(24)

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

static char w1[MY][MX];
static char w2[MY][MX];

static char *pretty = " =#-";

static void print_world(void);
static void next_gen(void);

main(int argc, char* argv[])
{
	static char buf[256];
	char* p;
	int	x;
	int	y;
	FILE*	fp;
	int	ch;

	if (argc != 2) {
		fprintf(stderr, "usage: wire file\n");
		exit(1);
	}

	if ((fp = fopen(argv[1], "r")) == NULL) {
		fprintf(stderr, "wire: can't open %s\n", argv[1]);
		exit(1);
	}

	for (x = 0; x < MX; x++)
		for (y = 0; y < MY; y++) {
			w1[y][x] = SPACE;
			w2[y][x] = SPACE;
		}

	y = 1;
	while (fgets(buf, 256, fp) != NULL) {
		x = 1;
		for (p = buf; *p; p++, x++) {
			switch (*p) {
			case '.':
			case ' ':
				w2[y][x] = SPACE;
				break;
			case '=':
				w2[y][x] = WIRE;
				break;
			case '#':
				w2[y][x] = HEAD;
				break;
			case '-':
				w2[y][x] = TAIL;
				break;
			case '\n':
				break;
			default:
				fprintf(stderr, "bad character in input: %c\n", *p);
				exit(1);
			}
		}
		y++;
	}
	fclose(fp);

	clrscr();

	for (;;) {
		print_world();
		next_gen();
		ch = getch();
		if (ch == 'q' || ch == 'Q' || ch == 27)
			break;
	}

	exit(0);
}

static void print_world(void)
{
	int	x;
	int	y;

	for (y = 0; y < MY; y++)
		for (x = 0; x < MX; x++) {
			if (w2[y][x] != w1[y][x]) {
				gotoxy(x + 1, y + 1);
				putch(pretty[w2[y][x]]);
				w1[y][x] = w2[y][x];
			}
		}
}

static void next_gen(void)
{
	int	x;
	int	y;
	int count;

	for (y = 1; y < MY - 1; y++)
		for (x = 1; x < MX - 1; x++) {
			switch (w1[y][x]) {
			case SPACE:
				w2[y][x] = SPACE;
				break;
			case TAIL:
				w2[y][x] = WIRE;
				break;
			case HEAD:
				w2[y][x] = TAIL;
				break;
			case WIRE:
				count = 0;
				if (w1[y - 1][x - 1] == HEAD) count++;
				if (w1[y    ][x - 1] == HEAD) count++;
				if (w1[y + 1][x - 1] == HEAD) count++;
				if (w1[y - 1][x    ] == HEAD) count++;
				if (w1[y + 1][x    ] == HEAD) count++;
				if (w1[y - 1][x + 1] == HEAD) count++;
				if (w1[y    ][x + 1] == HEAD) count++;
				if (w1[y + 1][x + 1] == HEAD) count++;

				if (count == 1 || count == 2)
					w2[y][x] = HEAD;
				else
					w2[y][x] = WIRE;
				break;
			default:
				fprintf(stderr, "uh-oh...\n");
				exit(1);
			}
		}
}