[net.sources.games] CoreWars source

davidk@dartvax.UUCP (David C. Kovar) (10/29/85)

Due to the flood of messages requesting CoreWars, I am posting it.
CoreWars is not my creation and I take no credit for it, I am
just passing it down the line. Enjoy ....

------------------------- cut here -------------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting backz'
sed 's/^X//' <<'//go.sysin dd *' >backz
dat		-1
mov	1	@-1
djz	0	-2
jmp	-2
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 backz
	/bin/echo -n '	'; /bin/ls -ld backz
fi
/bin/echo 'Extracting bigfoot'
sed 's/^X//' <<'//go.sysin dd *' >bigfoot
dat		0		/pointer to source address
dat		1752		/pointer to destination address
mov	@-2	@-1		/copy source to destination
cmp	-3	#9		/if all 10 lines have been copied...
jmp	4			/...then leave the loop
add	#1	-5		/otherwise, increment the source address
add	#1	-5		/...and the destination address
jmp 	-5			/...and return to the loop
mov	#1752	1746		/restore the starting destination address
jmp	1746			/jump to the new copy
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 bigfoot
	/bin/echo -n '	'; /bin/ls -ld bigfoot
fi
/bin/echo 'Extracting corewar.6'
sed 's/^X//' <<'//go.sysin dd *' >corewar.6
X.TH COREWAR 6 
X.UC 4
X.SH NAME
corewar \- battling programs
X.SH SYNOPSIS
X.B corewar
[
X.B \-l
] [
X.B \-t
] [
X.B \-d
]
prog1 prog2
X.br
X.SH DESCRIPTION
X.I Corewar
loads 
X.I file1
and
X.I file2
into the simulated memory arena and executes instructions for 
each in turn until one encounters an illegal instruction, at which
point the other is declared the winner.
If neither has won in two minutes, the match is declared a draw.
X.PP
X.I Corewar
is based on A.K Dewdeney's May 1984 column in Scientific American.
X.PP
The
X.B \-l
option causes a listing of the generated code to be written on the
standard output while each file is loaded.
X.PP
The option
X.B \-t
causes an instruction execution trace to be written on the standard output.
X.PP
The option
X.B \-d
causes a post mortem memory dump to be written on the standard output.
X.PP
More files may be given for simultaneous execution, and other options
exist (call
X.I Corewar
with a nonexistent option to get a description of the existing ones).
The option
X.B \-x
causes
X.I Corewar
to accept one additional instruction: `fork'. Its syntax is like that
of `jmp', and it creates two processes, one continuing at the next
instruction, one at the (relative) address given as argument. There
exist restrictions to prevent proliferation of processes: there is
a maximum number of processes (e.g. 20), a minimum distance for a new
process from existing processes (e.g. 1), and a minimum age
(`maturity', e.g. 0) before which a process cannot spawn new processes.
X.SH AUTHORS
Berry Kercheval (ihnp4!zehntel!berry)
X.br
Andries Brouwer (mcvax!play)
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 corewar.6
	/bin/echo -n '	'; /bin/ls -ld corewar.6
fi
/bin/echo 'Extracting corewar.c'
sed 's/^X//' <<'//go.sysin dd *' >corewar.c
X/*
 *	CoreWar
 *
 *	Programs battle for supremacy in a simulated arena!  Based on A.K
 *	Dewdeney's May 1984 column in Scientific American.
 *
 *	Usage:
 *		corewar [options] progs
 *			progs must be ascii redcode files (at least two).
 *		    -l: print listing while loading the redcode programs.
 *		    -t: print verbose execution trace.
 *		    -d: print post-mortem memory dump.
 *		    -s: print statistics.
 *		    -f: print memory dump locally at final pc's.
 *		    -x: extended redcode: allow fork. [AEB]
 *		    -o: stop when no more memory owned.
 *		    -i: stop when not_own instruction executed.
 *		    -m20: set maturity limit to 20 (default 0).
 *		    -n20: set max number of processes to 20 (default 20).
 *		    -d20: set minimum distance from other processes for a
 *				newly spawned process.
 *
 *	This program assumes your C compiler supports structure assignment.
 *
 *	Copyright 1984, Berry Kercheval.  All rights reserved.  Permission
 *	for distribution is granted provided no direct commercial
 *	advantage is gained, and that this copyright notice appears 
 *	on all copies.
 *	Extensively changed by mcvax!play . You get the changes for free!
 */

#include <stdio.h>
#include <signal.h>
#include "corewar.h"

memword	mem[MEMSIZE];		/* the simulated memory 'arena' */
int	nr_of_own_locs[MAXPROCNUM+1];	/* and how many each of us controls */

char	*pr_inst();		/* returns formatted string representation of a
				 * redcode instruction suitable for %s */
char	letter();		/* returns " ABCD..."[arg] */
int (*oldintrup)();

int	dumpflag = 0;		/* TRUE --> print post-mortem dump */
int	traceflag = 0;		/* TRUE --> print execution trace */
int	listflag = 0;		/* TRUE --> print listing of loaded program */
int	statflag = 0;		/* TRUE --> print various statistics */
int	localdumpflag = 0;	/* TRUE --> print local dump at termination */
int	forkflag = 0;		/* TRUE --> allow forks */
int	opto;			/* stop when no more own locs */
int	opti;			/* stop when not_own instruction executed */
int	min_fork_dist = 1;
int	max_no_of_procs = 20;	/* Note: not the same as MAXPROCNUM ! */
int	mature_at = 0;		/* Age at which fork is allowed */

long int cyclect = 0;		/* global time */
int	procct;			/* total nr of processes alive */
int	procno = 1;		/* 1 + total nr of procs without ancestor */
int	running = 1;
struct proc *head_procs, *procs[MAXPROCNUM+1];
char 	*file[MAXPROCNUM+1];

main (argc, argv)
int argc;
char **argv;
{
	address	pc;		/* address of program starting point.
				 * filled in by load() */
	address load();		/* loads a file */
	int	draw();		/* what happens if we time out */
	int	intrup();	/* or are interrupted */

	/* allow both "corewar -f -s" and "corewar -fs" style options */
	while (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
		argc--;
		argv++;
		while(*++*argv) switch (**argv) {
		/* first look at the options that may have a numerical arg */
		case 'm':	/* maturity threshold */
			mature_at = atoi(*argv + 1);
			printf("Set maturity age to %d.\n", mature_at);
		skipdigits:
			while(digit(argv[0][1])) ++*argv;
			break;
		case 'n':	/* num of procs */
			max_no_of_procs = atoi(*argv + 1);
			printf("Max number of processes: %d\n",
				max_no_of_procs);
			goto skipdigits;
		case 'd':
			if(digit(argv[0][1])) {	/* min fork dist */
				min_fork_dist = atoi(*argv + 1);
				printf("Min dist to others when forking: %d\n",
					min_fork_dist);
				goto skipdigits;
			}
			dumpflag = 1;	/* print memory dump at end */
			break;
		case 'f':	/* print local memory dump at termination */
			localdumpflag = 1;
			break;
		case 'l':	/* print listing at load-time */
			listflag = 1;
			break;
		case 't':	/* print execution trace */
			traceflag = 1;
			break;
		case 's':	/* print statistics */
			statflag = 1;
			break;
		case 'x':	/* allow forks */
			forkflag = 1;
			break;
		case 'o':
			opto = 1;
			break;
		case 'i':
			opti = 1;
			break;
		default:
		    printf("Unknown flag '%s'\n", *argv);
		    printf("Flags are:\n");
		    printf("\t-l\tprint listing at load time\n");
		    printf("\t-d\tprint memory dump at termination\n");
		    printf("\t-f\tprint local memory dump at termination\n");
		    printf("\t-t\tprint execution trace\n");
		    printf("\t-s\tprint statistics\n");
		    printf("\t-x\textend redcode with FORK instruction\n");
		    printf("\t-o\tstop process that owns no more memory\n");
		    printf("\t-i\tstop process that executes foreign instr\n");
		    printf("\t-m20\tset maturity age to 20\n");
		    printf("\t-n25\tset max number of processes to 25\n");
		  printf("\t-d1\tset min dist to others while forking to 1\n");
		    exit(1);
		}
	}

	/* now the last two arguments should be names of two redcode files */
	if (argc < 3) {
		printf("Usage: corewar [options] file1 file2 ...\n");
		exit(1);
	}

	(void) srand(getpid());
	clear_mem();			/* Clear the arena! Clear the arena! */

	while(argc > 1) {
		argc--;
		argv++;
		if ( access (*argv, 4) != 0) { /* check read access */
			perror(*argv);
			exit (-1);
		}
		if(procno > MAXPROCNUM) {
			printf("We cannot run more than %d", MAXPROCNUM);
			printf(" processes simultaneously.\n");
			printf("Subsequent ones are ignored.\n");
			break;
		}
		file[procno] = *argv;
		pc = load(*argv, procno);
		printf("Executing %s at %d.\n\n", *argv, pc);
		procs[procno] = makeproc((struct proc *) 0, pc);
		procno++;
	}

	outmemcontrol();

	(void) signal (SIGALRM, draw);	/* set up for timeout */
	(void) alarm (TIMEOUT);		/* give up after TIMEOUT seconds */

	/* if we are not ignoring interrupts then catch them */
	oldintrup = signal (SIGINT, SIG_IGN);
	if (oldintrup == SIG_DFL)
		(void) signal (SIGINT, intrup);

	if(traceflag && procno > 3)
		traceflag = 0;		/* I am lazy */
	if(traceflag)
	{
		printf ("       %10s                                 %10s\n",
			file[2], file[1]);
		printf ("-----------------------------------------------------------\n");
	}
	while (running) {
		cyclect++;
		xeq_all();
		if(opto) {
			register int j, ct = 0;

			for(j = 1; j < procno; j++)
				if(nr_of_own_locs[j] > 0) ct++;
			if(ct < 2)
				running = 0;
		}
	}
	done();
}

done()
{
	(void) alarm (0);			/* turn off the alarm */
	(void) signal(SIGINT, oldintrup);	/* reset intrup handling */
	if(forkflag) {
		register struct proc *p;

		for(p = head_procs; p; p = p->next_proc)
			if(p->ancestor) {
				p->ancestor->no_of_alive_offspring +=
					p->no_of_alive_offspring;
				p->ancestor->no_of_dead_offspring +=
					p->no_of_dead_offspring;
			}
	}
	{ long int omax, ohere;
	  register int j, oct;
	  int bestj[MAXPROCNUM+1];
		omax = 0;
		for(j = 1; j < procno; j++) {
			ohere = procs[j]->no_of_alive_offspring;
			if(procs[j]->status) ohere++;
			if(ohere > omax) {
				omax = ohere;
				oct = 0;
				bestj[oct++] = j;
			} else if(omax == ohere) {
				bestj[oct++] = j;
			}
		}
		if(!omax) {
			printf("Draw - all died.\n");
		} else if(oct == 1) {
			j = bestj[0];
			printf("%s(%d) wins.\n",
				file[j], j);
		} else if(procno == oct+1)
			printf("DRAW!\n");
		else {
			printf("Tie between: ");
			for(j=0; j<oct; j++)
			    printf("%s%s(%d)", j ? " and " : "",
				file[bestj[j]], bestj[j]);
			printf("\n");
		}
	}
	if (statflag)			/* statistics if requested */
		statistics();
	if (dumpflag || localdumpflag)	/* post-mortem dump if requested */
		dump();
	exit(0);			/* Th-th-that's all folks */
}

X/*
 *	clear_mem:	clear the simulated memory
 */

clear_mem()
{
	address i;

	for ( i=0 ; i < MEMSIZE; i++ )
	{
		mem[i].op = 0;
		mem[i].a_mode = 0;
		mem[i].b_mode = 0;
		mem[i].a = 0;
		mem[i].b = 0;
		mem[i].owner = 0;
	}
	nr_of_own_locs[0] = MEMSIZE;
}

X/*
 *	load:
 *		Load a redcode file at a random place im mem.
 *		Avoid placing files too close together.
 */

address
load(filename, owner)
char *filename;
short owner;
{
	address	r;		/* where to load current instruction */
	FILE	*f;		/* stream pointer for input file */
	char	buf[256];	/* line buffer */
	char 	*ptr;		/* pointer into the line; used in parsing */
	char	*ip;		/* pointer into the line; used in parsing */
	char	*index();
	char	error;		/* error flag printed at beginning of each 
				 * listing line; currently either ' ' or 'E' */
	address	start;		/* address of first executable instruction */
	int	op;		/* op-code value */
	int	i;		/* counter for for loops */

	/* select starting address */

	start = -1;		/* undefined */
	{
		register int mindist = DISTANCE+1;
		register int j;

	try_r:
		r = (rand() >> 12) % MEMSIZE;	/* 4.1 rand() sucks */
		mindist--;
		/*
		 * Second program must be at least DISTANCE addresses from
		 * first; I just make their starting-points about that much
		 * apart.
		 */
		for(j = 1; j < procno; j++)
			if(dist(r, procs[j]->pc) < mindist)
				goto try_r;
	}
	printf ("Loading %s at %d\n", filename, r);

	/* now do load */

	f = fopen (filename, "r");
	if (f == NULL ) {
		perror (filename); exit(-1);
	}
	/*
	 * There now follows a moderately crufty ad-hoc redcode assembler.
	 * It's not modular or very structured, but it seems to work, and
	 * redcode was so simple I didn't want to use YACC or LEX or SSL
	 */

	while ( fgets ( buf, 256, f) != NULL)	/* for each line in the file */
	{
		error = ' ';			/* no error yet */
		/* zap trailing newline to make listing generation easier */
		if ( (ptr = index(buf, '\n')) != NULL ) *ptr = '\0';

		/* zap comment */
		if ( (ptr = index(buf, '/')) != NULL ) *ptr = '\0';
		 
		/* decode instruction */

		ip = buf;	/* start at the beginning of the line */
		op = -1;	/* Invalid op-code */

		/* skip leading whitespace */
		while ( *ip && (*ip == ' ' || *ip == 011)) ip++;	
		if ( ip == ptr ) {	/* it's a 'blank' line */
			if ( ptr != NULL ) *ptr = '/';	/* put comment back */
			if (listflag)
				printf ("%c                      '%s'\n",
					error, buf);
			break;
		}
		if ( strncmp(ip, op_str[FORK], 4) == 0) {
			op = FORK;
			ip += 4;
		} else
		for ( i = 0; i <= CMP; i++)	/* CMP is highest op-code */
		{
			if ( strncmp(ip, op_str[i], 3) == 0){
				op = i;
				ip += 3;
				break;
			}
		}
		if ( op == -1 ) 		/* didn't find it! */
		{
			printf ("SYNTAX ERROR '%s' -- Bad opcode\n", buf);
			error = 'E';
			ip++;
		}
		mem[r].op = op;

		/* skip whitespace */
		while ( *ip && (*ip == ' ' || *ip == 011)) ip++;

		/* figure out addressing mode for operand A */
		if ( op != DAT ) { 	/* DAT has only B operand */
			if ( *ip == '#'){
				mem[r].a_mode = IMMEDIATE; 
				ip++;
			}
			else if ( *ip == '@') {
				mem[r].a_mode = INDIRECT; 
				ip++;
			}
			else 
			{
				mem[r].a_mode = DIRECT;
			}
			mem[r].a = atoi ( ip );
			if ( mem[r].a < 0 ) mem[r].a += MEMSIZE;
			while ( *ip && (*ip != ' ' && *ip != 011)) ip++;
		}
		/* skip whitespace */
		while ( *ip && ( *ip == ' ' || *ip == 011)) ip++;	

		if ( op != JMP && op != FORK) {	/* these have only A operand */
			if ( *ip == '#'){
				mem[r].b_mode = IMMEDIATE; 
				ip++;
			}
			else if ( *ip == '@') {
				mem[r].b_mode = INDIRECT; 
				ip++;
			}
			else 
			{
				mem[r].b_mode = DIRECT;
			}
			mem[r].b = atoi ( ip );
			if ( mem[r].b < 0 ) mem[r].b += MEMSIZE;
		}

		/* check for start of executable code */
		if ( op != DAT && start == -1) start = r;

		/* DAT has zero modes... */
		if ( op == DAT ) mem[r].b_mode = mem[r].a_mode = 0;

		nr_of_own_locs[mem[r].owner]--;
		nr_of_own_locs[owner]++;
		mem[r].owner = owner;

		/* Do listing stuff... */

		if ( ptr != NULL ) *ptr = '/';		/* put comment back */
		if (listflag)
			printf ("%c%4d %s  '%s'\n", error, r, pr_inst(mem[r]),
				buf);
		r++;			/* Advance to next memory location */
		if ( r >= MEMSIZE ) r %= MEMSIZE;
	}

	if (listflag)
		(void) fflush (stdout);
	(void) fclose (f);
	/* return starting address */
	return start;
}

xeq_all()
{
	register struct proc *p;

	for(p = head_procs; p; p = p->next_proc)
		if(p->status)
			execute(p);
}

execute (p)
register struct proc *p;
{

	memword inst;
	address addr,final;
	short me;

	/* fetch instruction */
	addr = p->pc;
	inst = mem[addr];
	me = inst.owner;

	/* separate the two instruction traces */
	if (traceflag && (p == procs[1] || p == procs[2])) {
		if(p == procs[1])
			printf ("     ||     ");
		printf ("@ %d  %s    ", addr, pr_inst(inst));
		if(p == procs[1] || !procs[1]->status)
			printf ("\n");
		(void) fflush (stdout);
	}

	switch ( inst.op )
	{
		case MOV:
		case ADD:
		case SUB:
			if (do_mas(addr, inst, me))
				goto badinstr;
			addr++;
			break;
		case JMP:
			addr += inst.a;
			break;
		case JMZ:
			final = (addr + inst.b) % MEMSIZE;
			if ( mem[final].op == DAT && mem[final].b == 0 )
				addr += inst.a;
			else
				addr++;
			break;
		case JMG:
			final = (addr + inst.b) % MEMSIZE;
			if ( mem[final].op == DAT && mem[final].b > 0 )
				addr += inst.a;
			else
				addr++;
			break;
		case DJZ:
			final = (addr + inst.b) % MEMSIZE;
			if(mem[final].b == 0)
				mem[final].b = MEMSIZE-1;
			else
				mem[final].b -= 1;
			if ( mem[final].b == 0 )
				addr += inst.a;
			else
				addr++;
			{ register int o = mem[final].owner;

			  if(o && o != me) {
				mem[final].owner = 0;
				nr_of_own_locs[o]--;
				nr_of_own_locs[0]++;
			  }
			}
			break;
		case CMP:
			addr += do_cmp(addr, inst);
			break;
		case FORK:
			if(forkflag) {
				final = (addr + inst.a) % MEMSIZE;
				(void) makeproc(p, final);
				addr++;
				break;
			}
			/* fall into next case */
		case DAT:
		default:
		badinstr:
			if(!p->ancestor) {
			    if(traceflag && p == procs[2]) printf("\n");
			    printf ("%s(%d): Illegal instruction %s @ %d\n",
				file[p->from], p->from,
				pr_inst(inst), addr);
			    if(traceflag && p == procs[2])
				printf("\t\t\t    ");
			}
			procdied(p);
			return;
	}

	/* test first now - we prefer "Illegal instr" above "Not own instr" */
	if (opti && p->from != me) {
		if(!p->ancestor) {
		    if(traceflag && p == procs[2]) printf("\n");
		    printf ("%s(%d): Not own instruction %s @ %d\n",
			file[p->from], p->from,
			pr_inst(inst), p->pc);
		    if(traceflag && p == procs[2])
			printf("\t\t\t    ");
		}
		procdied(p);
		return;
	}

	p->pc = addr % MEMSIZE;
}

X/*
 * CMP: compare a and b, return 1 if same, 2 if different 
 */

do_cmp(addr, inst)
address addr;
memword inst;
{
	address source, destination;
	memword data;

	data.op = 0;
	data.a_mode = data.b_mode = 0;
	data.a = data.b = 0;

	switch (inst.a_mode)
	{
		case IMMEDIATE:
			data.b = inst.a;
			break;
		case DIRECT:
			data = mem[(addr + inst.a) % MEMSIZE];
			break;
		case INDIRECT:
			source = mem[(addr + inst.a) % MEMSIZE].b;
			data =   mem[(source + addr + inst.a) % MEMSIZE];
			break;
		default: /* ERROR */
			printf ("do_cmp: illegal addressing mode\n");
			return 1;
	}
	switch (inst.b_mode)
	{
		case IMMEDIATE: /* error */
			if (data.b == inst.b) return 1;
			else return 2;
		case DIRECT:
			if ( data.b == mem[(addr + inst.b) % MEMSIZE].b)
				return 1;
			else return 2;
		case INDIRECT:
			destination = mem[(addr + inst.b) % MEMSIZE].b;
			if(data.b == mem[(destination+addr+inst.b)%MEMSIZE].b)
				return 1;
			else return 2;
		default: /* ERROR */
			printf ("do_cmp: illegal addressing mode\n");
			return 1;
	}	
}

do_mas(addr, inst, me)
address addr;
memword inst;
{
	address source, destination, final;
	memword data;

	data.op = 0;
	data.a_mode = data.b_mode = 0;
	data.a = data.b = 0;
	data.owner = me;

	switch (inst.a_mode)
	{
		case IMMEDIATE:
			data.b = inst.a;
			break;
		case DIRECT:
			data = mem[(addr + inst.a) % MEMSIZE];
			break;
		case INDIRECT:
			source = mem[(addr + inst.a) % MEMSIZE].b;
			data =   mem[(source + addr + inst.a) % MEMSIZE];
			break;
		default: /* ERROR */
			printf ("do_mas: illegal addressing mode\n");
			return 1;
	}
	switch (inst.b_mode)
	{
		case IMMEDIATE: /* error */
			printf ("do_mas: illegal immediate destination\n");
			return 1;
		case DIRECT:
			final = (addr + inst.b) % MEMSIZE;
			break;
		case INDIRECT:
			destination = mem[(addr + inst.b) % MEMSIZE].b;
			final = (destination + addr + inst.b) % MEMSIZE;
			break;
		default: /* ERROR */
			printf ("do_mas: illegal addressing mode\n");
			return 1;
	}
	switch(inst.op) {
	case SUB:
		data.b = -data.b;
		/* fall into next case */
	case ADD:
		mem[final].b = (mem[final].b + data.b) % MEMSIZE;
		{ register int o = mem[final].owner;
		  if(o && o != me){
			nr_of_own_locs[o]--;
			nr_of_own_locs[0]++;
			mem[final].owner = 0;
		  }
		}
		break;
	case MOV:
		{ register int o = mem[final].owner;
		  register int od = data.owner;
		  if(od != me)
			data.owner = od = 0;
		  if(o != od){
			nr_of_own_locs[o]--;
			nr_of_own_locs[od]++;
		  }
		}
		mem[final] = data;
	}
	return 0;
}

dump()
{
	int r;
	int flag = 0;

	printf ("\n\n----------%s MEMORY DUMP -------------\n",
		localdumpflag ? " LOCAL" : "");

	for ( r = 0; r < MEMSIZE; r++) {
		if(localdumpflag) {
			register struct proc *p;
			int here = 0, rmin = MEMSIZE+1, local = 0;

			/* find dist 0-LDW with wraparound, larger without */
			for(p = head_procs; p; p = p->next_proc) {
				if(r > p->pc + LDW) continue; /* too far */
				if(r == p->pc) {
					here++;
					goto localx;
				}
				if(dist(r, p->pc) <= LDW)
					local++;
				else if(!local && p->pc < rmin)
					rmin = p->pc - LDW;
			}
			if(local)
				goto localx;
			r = rmin-1;
			flag = 0;
			continue;
		localx:
			if(here) flag = 0;
			if(!flag || !iszero(mem[r]))
				printf(here ? ">" : " ");

		}

		if ( iszero(mem[r]) && flag == 0) {
			printf ("  %5d 0\n", r);
			flag = 1;
		}
		else if (iszero(mem[r]) && flag == 1) {
			printf ("   *\n");
			flag = 2;
		}
		else if (iszero(mem[r]) && flag == 2) {
			/* skip it */
		}
		else
		{
			printf ("%c %5d %s\n", letter(mem[r].owner),
				r, pr_inst(mem[r]));
			flag = 0;
		}
	}
}

iszero(x)
memword x;
{
	if (x.op == 0 && x.owner == 0 && x.a_mode == 0 && 
	    x.b_mode == 0 && x.a == 0 && x.b == 0 )
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

draw()
{
	printf ("Timed out after %d seconds\n", TIMEOUT);
	done();
}

intrup()
{
	printf("Interrupted.\n");
	done();
}

char
letter(n)
int n;
{
	return( (n == 0) ? ' ' : (1 <= n && n <= 26) ? '@'+n : 'a'+n-27);
}

char *
pr_inst(x)
memword x;
{
	char buf[200];

	(void) sprintf(buf,"%s%s%c%04d, %c%04d",
		op_str[x.op], (x.op == FORK) ? "" : " ",
		mode_char[x.a_mode], x.a,
		mode_char[x.b_mode], x.b);
	return buf;
}

outmemcontrol()
{
	register int j;

	printf("Memory control: ");
	for(j = 1; j < procno; j++) {
		if(j % 5 == 0) printf("\n\t");
		printf("%s: %d, ", file[j], nr_of_own_locs[j]);
	}
	printf("no_one: %d\n", nr_of_own_locs[0]);
	(void) fflush(stdout);
}

statistics()
{
	register int j;

	printf("Nr of cycles: %ld\n", cyclect);

	outmemcontrol();

	printf("Final pc's:");
	for(j = 1; j < procno; j++) {
		if(j % 5 == 0) printf("\n\t");
		printf(" %s: %ld", file[j], procs[j]->pc);
	}
	printf("\n");

	if(forkflag) {
		register struct proc *p;

		for(j = 1; j < procno; j++)
			descstat(procs[j], file[j]);
		for(p = head_procs; p; p = p->next_proc) if(p->status)
			printf("\t%c at %d was born at time %ld\n",
				letter(p->from), p->pc, p->time_of_birth);
	}
}

descstat(p,name)
register struct proc *p;
register char *name;
{
	printf("%s: %s.", name, p->status ? "alive" : "dead");
	if(p->no_of_alive_offspring + p->no_of_dead_offspring)
		printf(" Descendants: %ld (alive) %ld (dead).\n",
			p->no_of_alive_offspring,
			p->no_of_dead_offspring);
	else
		printf("\n");
}	

dist(r1, r2)
address r1,r2;
{
	register int d = (r1 > r2) ? r1-r2 : r2-r1;
	if(d > MEMSIZE-d)
		d = MEMSIZE-d;
	return d;
}

struct proc *
makeproc(ancestor, place)
struct proc *ancestor;
address place;
{
	register struct proc *proc;
	extern char * malloc();

	/*
	 * We need some means of controlling the number of processes;
	 * here I have chosen for max_no_of_procs and min_fork_dist. Note that
	 * some code gets rather inefficient (and should be rewritten)
	 * if max_no_of_procs is increased too much.
	 */
	if(ancestor) {
		if(procct >= max_no_of_procs ||
		    ancestor->time_of_birth + mature_at > cyclect)
			return((struct proc *) 0);
		for(proc = head_procs; proc; proc = proc->next_proc)
		    if(dist(proc->pc, place) < min_fork_dist)
			return((struct proc *) 0);
	}
	proc = (struct proc *) malloc(sizeof(struct proc));
	if(!proc) {
		if(!ancestor) {
			/* cannot create one of the two parent processes ? */
			printf("malloc fails.");
			exit(1);
		}
		return((struct proc *) 0);  /* child asphyxates immediately */
	}
	procct++;
	proc->next_proc = head_procs;
	head_procs = proc;
	proc->ancestor = ancestor;
	proc->pc = place;
	proc->status = 1;	/* alive */
	proc->time_of_birth = cyclect;
	proc->no_of_alive_offspring = proc->no_of_dead_offspring = 0;
	if(ancestor){
		ancestor->no_of_alive_offspring++;
		proc->from = ancestor->from;
	} else {
		proc->from = procno;
	}
	return(proc);
}

procdied(proc)
register struct proc *proc;
{
	register int who = proc->from;

	procct--;
	if(!proc->ancestor)
		proc->status = 0;	/* dead */
	else {
		register struct proc *p;

		proc->ancestor->no_of_alive_offspring +=
			proc->no_of_alive_offspring - 1;
		proc->ancestor->no_of_dead_offspring +=
			proc->no_of_dead_offspring + 1;
		if(head_procs == proc)
			head_procs = proc->next_proc;
		else
			for(p = head_procs; p; p = p->next_proc)
			    if(p->next_proc == proc) {
				p->next_proc = proc->next_proc;
				break;
			    }
		for(p = head_procs; p; p = p->next_proc)
			if(p->ancestor == proc)
				p->ancestor = proc->ancestor;
		free((char *) proc);
	}

	if(!procs[who]->status && !procs[who]->no_of_alive_offspring){
		register int ct = 0;

		/* check whether there are any others left */
		for(who = 1; who < procno; who++)
			if(procs[who]->status ||
			   procs[who]->no_of_alive_offspring)
				ct++;
		if(ct < 2)
			running = 0;
	}

	/* perhaps we want to report something here? */
	/* note that we probably just freed proc */
}

digit(c)
char c;
{
	return('0' <= c && c <= '9');
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 corewar.c
	/bin/echo -n '	'; /bin/ls -ld corewar.c
fi
/bin/echo 'Extracting corewar.h'
sed 's/^X//' <<'//go.sysin dd *' >corewar.h
X/*
 *	General defines for CoreWar, based on A.K. Dewdney's May 1984
 *	column in Scientific American.
 *
 *	Copyright 1984, Berry Kercheval.  All rights reserved.  Permission
 *	for distribution is granted provided no direct commercial
 *	advantage is gained, and that this copyright notice appears 
 *	on all copies.
 */

#define TIMEOUT 120		/* only play for two minutes */
struct	memword
	{
		short op;
		short a_mode;
		short b_mode;
		int   a;
		int   b;
		short owner;
	};

typedef struct memword memword;
typedef	int	address;

#define 	MEMSIZE		8000
#define 	DISTANCE	1000	/* programs at laest this far apart */
#define		LDW		10	/* width of local dump */

X/*
 *	Redcode Instruction Format:
 *
 *	N    N     N   NNNN NNNN	<-- decimal digits
 *	OP ModeA ModeB AAAA BBBB
 *
 *	Max. instruction: 82279997999 = 0x1 3245 222F
 *	Too bad it won't fit in a Long
 *
 */

X/*
 * The redcode Op-code values
 */

#define		MOV	1
#define		ADD	2
#define		SUB	3
#define		JMP	4
#define		JMZ	5
#define		JMG	6
#define		DJZ	7
#define		CMP	8
#define		FORK	9
#define		DAT	0

char *op_str[] =
{
	"dat",	/* 0 */
	"mov",	/* 1 */
	"add",	/* 2 */
	"sub",	/* 3 */
	"jmp",	/* 4 */
	"jmz",	/* 5 */
	"jmg",	/* 6 */
	"djz",	/* 7 */
	"cmp",	/* 8 */
	"fork",	/* 9 */
	0
};
	
X/*
 * Operand modes
 */

#define IMMEDIATE	0
#define DIRECT		1
#define INDIRECT	2

char mode_char[] = { '#', ' ', '@', 0};

struct proc {
	struct proc *next_proc;
	struct proc *ancestor;
	address	pc;
	int	status;			/* 0: dead. */
	short	from;			/* 1 or 2 (original ancestor) */
	long	time_of_birth;
	long	no_of_alive_offspring;
	long	no_of_dead_offspring;
};

extern struct proc * makeproc();
#define	MAXPROCNUM	20	/* max no of processes at top level */


//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 corewar.h
	/bin/echo -n '	'; /bin/ls -ld corewar.h
fi
/bin/echo 'Extracting duh'
sed 's/^X//' <<'//go.sysin dd *' >duh
jmp 0		/do nothing, ever
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 duh
	/bin/echo -n '	'; /bin/ls -ld duh
fi
/bin/echo 'Extracting dwarf'
sed 's/^X//' <<'//go.sysin dd *' >dwarf
dat		-1
add	#5	-1
mov	#0	@-2
jmp	-2
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dwarf
	/bin/echo -n '	'; /bin/ls -ld dwarf
fi
/bin/echo 'Extracting dwarf1'
sed 's/^X//' <<'//go.sysin dd *' >dwarf1
dat		999
mov	#0	@-1
add	#5	-2
jmp	-2
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dwarf1
	/bin/echo -n '	'; /bin/ls -ld dwarf1
fi
/bin/echo 'Extracting dwarf2'
sed 's/^X//' <<'//go.sysin dd *' >dwarf2
dat		-1
mov	#0	@-1
add	#2365	-2
jmp	-2
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dwarf2
	/bin/echo -n '	'; /bin/ls -ld dwarf2
fi
/bin/echo 'Extracting fork_imp'
sed 's/^X//' <<'//go.sysin dd *' >fork_imp
dat		-20
mov	#0	@-1
fork	-1
mov	0	1
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 fork_imp
	/bin/echo -n '	'; /bin/ls -ld fork_imp
fi
/bin/echo 'Extracting gemini'
sed 's/^X//' <<'//go.sysin dd *' >gemini
dat		0	/pointer to source address
dat		99	/pointer to destination address
mov	@-2	@-1	/copy source to destination
cmp	-3	#9	/if all 10 lines have been copied...
jmp	4		/...then leave the loop
add	#1	-5	/otherwise, increment the source address
add	#1	-5	/...and the destination address
jmp 	-5		/...and return to the loop
mov	#99	93	/restore the starting destination address
jmp	93		/jump to the new copy
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 gemini
	/bin/echo -n '	'; /bin/ls -ld gemini
fi
/bin/echo 'Extracting gemini2'
sed 's/^X//' <<'//go.sysin dd *' >gemini2
dat		0		/pointer to source address
dat		99		/pointer to destination address
mov	@-2	@-1		/copy source to destination
cmp	-3	#9		/if all 10 lines have been copied...
jmp	4			/...then leave the loop
add	#1	-5		/otherwise, increment the source address
add	#1	-5		/...and the destination address
jmp 	-5			/...and return to the loop
mov	#99	93		/restore the starting destination address
jmp	93			/jump to the new copy
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 gemini2
	/bin/echo -n '	'; /bin/ls -ld gemini2
fi
/bin/echo 'Extracting imp'
sed 's/^X//' <<'//go.sysin dd *' >imp
mov	0	1		/copy myself one instruction ahead
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 imp
	/bin/echo -n '	'; /bin/ls -ld imp
fi
/bin/echo 'Extracting juggernaut'
sed 's/^X//' <<'//go.sysin dd *' >juggernaut
dat		0		/pointer to source address
dat		9		/pointer to destination address
mov	@-2	@-1		/copy source to destination
cmp	-3	#9		/if all 10 lines have been copied...
jmp	4			/...then leave the loop
add	#1	-5		/otherwise, increment the source address
add	#1	-5		/...and the destination address
jmp 	-5			/...and return to the loop
mov	#9	3		/restore the starting destination address
jmp	3			/jump to the new copy
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 juggernaut
	/bin/echo -n '	'; /bin/ls -ld juggernaut
fi
/bin/echo 'Extracting makefile'
sed 's/^X//' <<'//go.sysin dd *' >makefile
CFLAGS = -O

corewar: corewar.o
	cc -o corewar corewar.o

corewar.o: corewar.c
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 makefile
	/bin/echo -n '	'; /bin/ls -ld makefile
fi

--
-- 
David C. Kovar    
	    USNET:      {linus|decvax|cornell|astrovax}!dartvax!davidk%amber
	    ARPA:	davidk%amber%dartmouth@csnet-relay
	    CSNET:	davidk%amber@dartmouth

"I felt like a punk who'd gone out for a switchblade and come back
 with a tactical nuke.

 'Shit', I thought. 'Screwed again. What good's a tactical nuke in a
  street fight?'"
			"Burning Chrome" by William Gibson