ado@elsie.UUCP (Arthur David Olson) (09/22/84)
: to unbundle, "sh" this file -- DO NOT use csh : SHAR archive format. Archive created Fri Sep 21 18:49:17 EDT 1984 echo x - ocelot.c sed 's/^X//' >ocelot.c <<'+FUNKY+STUFF+' X#include <stdio.h> X X#define TRUE 1 X#define FALSE 0 X Xchar * progname; Xint hflag; /* output a header line */ Xint lflag; /* label lines with generation numbers */ Xint nflag; /* output only number of repeating generation */ Xlong gvalue; /* output only every so many generations */ Xlong wvalue; /* work with this many cells */ Xlong xvalue; /* exit after so many generations */ Xchar * istring; /* initial state(s) */ X Xlong generation; Xchar t_s_map[28]; /* maps Totals of states of neighbors to new State */ X Xmain(argc, argv) Xint argc; Xchar * argv[]; X{ X register char * cp; X register i; X char * now; X char * new; X char * tmp; X char ** oldargv; X int oldargc; X char dum; X long l; X unsigned n; X extern char * malloc(); X X oldargc = argc; X oldargv = argv; X progname = cp = argv[0]; X while (*cp != '\0') X if (*cp++ == '/') X progname = cp; X ++argv; X --argc; X if (argc == 1 && argv[1][0] == '=' && argv[1][1] == '\0') X for ( ; ; ) X usage(); X while (argc > 0) { X cp = argv[0]; X if (*cp++ != '-') X break; X if (*cp == '-') { /* end of options */ X ++argv; X --argc; X break; X } X switch (*cp) { X case '\0': X for ( ; ; ) X wildexit("lone dash as argument"); X case 'g': X case 'w': X case 'x': X case 'i': /* Value-taking flags */ X if (*(cp + 1) != '\0') X for ( ; ; ) Xwildexit("stuff after value-taking flag"); X ++argv; X --argc; X if (argc == 0) X for ( ; ; ) Xwildexit("option without value"); X dum = '\0'; X i = sscanf(argv[0], "%ld%c", &l, &dum); X if (i != 1 || dum != '\0' || X (*cp != 'i' && l <= 0)) X for ( ; ; ) Xwildexit("option value"); X switch (*cp) { X case 'i': X istring = argv[0]; X break; X case 'g': X gvalue = l; X break; X case 'w': X wvalue = l; X break; X case 'x': X xvalue = l; X break; X } X break; X default: /* Handle flag options */ X while (*cp != '\0') switch (*cp++) { X case 'h': X hflag = TRUE; X break; X case 'l': X lflag = TRUE; X break; X case 'n': X nflag = TRUE; X break; X default: X for ( ; ; ) X usage(); X } X break; X } X ++argv; X --argc; X } X if (argc != 1) X for ( ; ; ) X usage(); X /* X ** Crack the code. X */ X for (cp = argv[0]; *cp != '\0'; ++cp) X ; X for (i = 0; --cp >= argv[0]; ++i) { X if (ctoi(*cp) < 0) X for ( ; ; ) X wildexit("code argument"); X if (i >= (sizeof t_s_map / sizeof t_s_map[0])) X for ( ; ; ) X wildexit("long code argument"); X t_s_map[i] = ctoi(*cp); X } X /* X ** Handle defaults. X */ X if (gvalue == 0) X gvalue = 1; X if (wvalue == 0) X wvalue = lflag ? 72 : 80; X if (istring != 0 && strlen(istring) > wvalue) X for ( ; ; ) X wildexit("length of -i string (greater than width)"); X for (n = 0; n < wvalue; ++n); /* Don't ask! */ X now = malloc(n); X new = malloc(n); X if (now == NULL || new == NULL) X for ( ; ; ) X wildexit("result from malloc"); X for (l = 0; l < wvalue; ++l) X now[l] = 0; X if (istring == 0) X now[wvalue / 2] = 1; X else for (i = 0; istring[i] != '\0'; ++i) X now[((wvalue - strlen(istring)) / 2) + i] = X ctoi(istring[i]); X if (!nflag) { X if (hflag) { X for (i = 0; i < oldargc; ++i) { X if (i != 0) X putchar(' '); X printf("%s", oldargv[i]); X } X putchar('\n'); X } X dump(now); X } X for (generation = 1; xvalue == 0 || generation <= xvalue; ++generation){ X update(now, new); X if (same(now, new)) { X if (nflag) X printf("%ld\n", generation); X for ( ; ; ) X exit(0); X } X if (!nflag && (generation % gvalue) == 0) X dump(new); X tmp = now; X now = new; X new = tmp; X } X if (nflag) X printf("0\n"); X for ( ; ; ) X exit(0); X} X Xwildexit(string) Xchar * string; X{ X fprintf(stderr, "%s: wild %s\n", progname, string); X for ( ; ; ) X exit(1); X} X Xusage() X{ X fprintf(stderr, "%s: Usage: %s ", progname, progname); X fprintf(stderr, X "[-h] [-l] [-n] [-g gap] [-w width] [-i initial] [-x exitgen] code\n"); X for ( ; ; ) X exit(1); X} X Xdump(buf) Xregister char * buf; X{ X register long n; X X if (nflag) X return; X if (lflag) X printf("%7ld-", generation); X n = wvalue; X do putchar(" 123456789"[*buf++]); X while (--n > 0); X putchar('\n'); X} X Xupdate(now, new) Xregister char * now; Xregister char * new; X{ X register char * map; X register long n; X X map = t_s_map; X n = wvalue; X if (n == 1) X new[0] = map[now[0]]; X else if (n == 2) X new[0] = new[1] = map[now[0] + now[1]]; X else { X *new++ = map[*now + *(now + 1)]; X ++now; X n -= 2; X do { X *new++ = map[*(now - 1) + *now + *(now + 1)]; X ++now; X } while (--n > 0); X *new = map[*(now - 1) + *now]; X } X} X Xint same(now, new) Xregister char * now; Xregister char * new; X{ X register long n; X X n = wvalue; X do if (*now++ != *new++) X return FALSE; X while (--n > 0); X return TRUE; X} X Xint ctoi(c) X{ X int i; X char buf[2]; X X buf[0] = c; X buf[1] = '\0'; X return (sscanf(buf, "%d", &i) == 1) ? i : -1; X} +FUNKY+STUFF+ ls -l ocelot.c echo x - ocelot.n sed 's/^X//' >ocelot.n <<'+FUNKY+STUFF+' X.TH OCELOT new X.SH NAME Xocelot \- one-dimensional cellular automata X.SH SYNOPSIS X.B ocelot X[ option ... ] code X.br X.B ocelot = X(to get a `how to use it' message) X.SH DESCRIPTION X.I Ocelot Xlets you observe one-dimensional cellular automata through time. XThe automata systems handled are the `code-numbered' ilk described by XWolfram in the 9/84 X.ul XScientific American. X.PP XAt each instant, Xeach automaton is in a numbered state. XIt's state at the next instant is determined by the sum of the Xstates of it and its neighbors. XThe low-order digit of the X.I code Xargument to X.I ocelot Xis the state at the next instant if the sum is zero; Xthe next-to-low-order digit is the state at the next instant if the sum is one; Xand so forth. XIf a sum is greater than the number of digits in the X.IR code , Xthe state at the next instant is zero. X.PP XIn the absence of command line options, X.I ocelot Xcreates a system of eighty automata with the fortieth automaton in state one Xand all others in state zero. XIt lists these states on the standard output, Xwith state zero represented by a blank and other states represented by a digit. XIt then loops, Xdetermining and listing the states of the automata at later times. XIt exits if the states of all automata at two successive instants are the same. X.PP X.PP XThese options are available: X.TP X.BI \-g \ number XOnly output each X.IR number th Xgeneration (the number is known as the `generation gap'). X.TP X.BI \-w \ number XWork with X.I number Xautomata. X.TP X.BI \-x \ number XExit after at most X.I number Xgenerations. X.TP X.BI \-i \ string XInitialize the central automata to the state(s) given in X.IR string . X.TP X.B \-h XOutput a header line. X.TP X.B \-l XLabel each line with its `generation number.' XIf this option is used and no `w' option is used, Xa system of 72 automata is created. X.TP X.B \-n XOnly output the number of the generation which repeats its predecessor. XIf this option and the `x' option are used, Xzero is output if the number of generations specified with the `x' option Xpasses without a generation repeating its predecessor. X.PP XAutomata may have at most ten states. X.SH EXAMPLES XThe command X.ti +.5i X.B "ocelot 2213310" X.br Xruns the system illustrated in the upper-left-hand corner of page 199 of XWolfram's article. X.PP XThe command X.ti +.5i X.B "ocelot 6345789" X.br Xproves that inspiring automata systems are distinct from inspiring pop tunes. +FUNKY+STUFF+ ls -l ocelot.n exit 0