home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 245_01 / lca31.c < prev    next >
Text File  |  1987-10-28  |  16KB  |  576 lines

  1.  
  2. /* (3,1) Linear Cellular Automaton    */
  3.  
  4. /* Reference:                */
  5. /*                    */
  6. /*    Kenneth E. Perry            */
  7. /*    Abstract Mathematical Art        */
  8. /*    BYTE                */
  9. /*    December, 1986            */
  10. /*    pages 181-192            */
  11.  
  12. /*    Copyright (C) 1987        */
  13. /*    Harold V. McIntosh        */
  14. /*    Gerardo Cisneros S.        */
  15.  
  16. /* G. Cisneros, 4.3.87                        */
  17. /* 10 April 1987 - modified for (4,2) [HVM]            */
  18. /* 26 April 1987 - Multiple menus [HVM]                */
  19. /* 28 April 1987 - back modified to (4,1) [HVM]            */
  20. /* 28 April 1987 - version for XVI Feria de Puebla [HVM]    */
  21. /* 14 May 1987 - modified for (3,1) and general rule [HVM]    */
  22.  
  23. # include <bdos.h>
  24.  
  25. # define COLGRAF     4  /* graph resolution            */
  26. # define T80X25      3  /* text resolution            */
  27. # define WHCYMAG     1  /* color quad for normal screen        */
  28. # define AL        320  /* array length (screen width)        */
  29. # define TS         7  /* distinct sums w/totalistic rule    */
  30. # define DS        27  /* number of distinct sums        */
  31. # define KK         3  /* number of states per cell        */
  32. # define NX         21     /* number of sample rules        */
  33.  
  34. char xrule[NX][KK][KK][KK];
  35.  
  36. char ixrule[NX][DS]=
  37.  
  38.     "001200111011011222201121100",    /* interfaces of 2 vel    */
  39.     "001200211221001010221220120",
  40.     "001210120212011110020110100",    /* mottled background    */
  41.     "002110012010121101201012211",    /* (0*102211200)* still */
  42.     "002110012110021201001012221",    /* symmetrized        */
  43.  
  44.     "002200011112011011012022200",    /* threads on triangles    */
  45.     "010002101012100210102011211",    /* dendrites        */
  46.     "010020202121101100222101120",    /* gldrs, puffr trn    */
  47.     "010022101200112021010000110",    /* threads among trngs    */
  48.     "010102020102020202020202020",
  49.  
  50.     "010102022102022221022221210",    /* open triangles    */
  51.     "011200122100121212211112212",
  52.     "012100200110011022102202022",    /* 2 comes and goes    */
  53.     "012112212012012112012212210",    /* 12 irresistible gldr    */
  54.     "020101011101011112011112120",    /* diagonal black gaps    */
  55.  
  56.     "020122100021210222210022111",    /* black triangles    */
  57.     "020201010201010102010102020",    /* class iv, sparse    */
  58.     "021111222210112122112122220",    /* 102 ia a barrier    */
  59.     "021211110211110102110102020",    /* blue bgrnd cl iv    */
  60.     "210021220202112222100220222",    /* 0122 barrier        */
  61.  
  62.     "221212021202011210012120111"    /* 2 glider on 1 bkgrnd    */
  63.  
  64.     ;
  65.  
  66. char  xx[4], rule[DS+1], ascrule[KK][KK][KK];
  67. int   binrule[KK][KK][KK], arule[DS], arr1[AL], arr2[AL];
  68. char  trule[TS]="0000000";
  69.  
  70. main()
  71. {
  72. int  i, j, i0, i1, i2, jj, n;
  73. int  more = 'r';
  74. char a, b, c;
  75.  
  76. for (i=0; i<NX; i++) {                    /* copy to 3-index array */
  77. i0=0; i1=0; i2=0;
  78. for (j=0; j<DS; j++) {
  79.   xrule[i][i0][i1][i2]=ixrule[i][j];
  80.   i2++;
  81.   if (i2>2) {i2=0; i1++;};
  82.   if (i1>2) {i1=0; i0++;};
  83.   if (i0>2) {i2=0; };
  84. };};
  85.  
  86.  
  87.     videopalette(WHCYMAG);                /* white/cyan/magenta */
  88.  
  89.     tuto();
  90.     while (!kbdst()) jj=rand();                /* wait for keypress */
  91.     c=kbdin();                        /* ignore it */
  92.     jj=rand()%NX;
  93.     for (i0=0; i0<KK; i0++) {
  94.     for (i1=0; i1<KK; i1++) {
  95.     for (i2=0; i2<KK; i2++) {
  96.     ascrule[i0][i1][i2] = xrule[jj][i0][i1][i2];    /* random sample rule */
  97.     };};};
  98.     rule[DS]=0;
  99.     ranlin();                        /* random initial array */
  100.     videomode(T80X25);
  101.     videoscroll(3,0,5,71,0,3);                /* menu on blue background */
  102.     videoscroll(19,0,24,71,0,3);
  103.     xmenu(jj+1);                    /* show initial rule */
  104.  
  105.     while (more!='n') {                    /* execute multiple runs */
  106.     rmenu();
  107.     lmenu();
  108.     while (0<1) {                    /* set up one run */
  109.     c=kbdin();
  110.     if (c=='g') break;                    /* go draw graph */
  111.     if (c=='q') more='n';                /* quit for good */
  112.     if (more=='n') break;
  113.     switch (c) {
  114.     case '@':                    /* numbered tot rule */
  115.         nutoto(numin(0));
  116.         totoasc();
  117.         rmenu();
  118.         videocursor(0,4,0);
  119.         break;
  120.     case '$':                    /* dozen totalistics */
  121.         j=numin(0);
  122.         for (i=0; i<12; i++) {
  123.           nutoto(j+i);
  124.           totoasc();
  125.           ranlin();
  126.           evolve(rule);
  127.           };
  128.         videomode(T80X25);
  129.         rmenu();
  130.         lmenu();
  131.         break;
  132.     case 't':                    /* totalistic rule */
  133.         xblnk();
  134.         tmenu();
  135.         edtrule();
  136.         totoasc();
  137.         for (i0=0; i0<3; i0++) {
  138.         for (i1=0; i1<3; i1++) {
  139.         for (i2=0; i2<3; i2++) {
  140.         ascrule[i0][i1][i2]=trule[i0+i1+i2];
  141.         };};};
  142.         videocursor(0,4,0);
  143.         rmenu();
  144.         xmenu(totonu(0));
  145.         break;
  146.         case 'r':                    /* edit rule */    
  147.         xblnk();
  148.         edrule();
  149.         videocursor(0,4,0);
  150.         rmenu();
  151.         break;
  152.         case 'l':                    /* edit cell string */
  153.         xblnk();
  154.         edline();
  155.         videocursor(0,3,0);
  156.         lmenu();
  157.         break;
  158.         case '#':                    /* read stored rule */
  159.         xmenu(NX);
  160.         n=(i=lim(1,numin(0),NX))-1;
  161.         xmenu(i);
  162.         xtoasc(n);
  163.         rmenu();
  164.             break;
  165.     case 'D':                    /* run through samples */
  166.         for (i=0; i<NX; i++) {
  167.           xmenu(i);
  168.           xtoasc(i);
  169.           ranlin();
  170.           evolve(rule);
  171.           };
  172.         videomode(T80X25);
  173.         rmenu();
  174.         break;
  175.         case 'u':                    /* sparse init arry */
  176.         xblnk();
  177.         for (i=0; i<AL; i++) arr1[i]=0;
  178.         arr1[AL/4]=1;
  179.             arr1[AL/2]=2;
  180.             arr1[(3*AL)/4]=1;
  181.             arr1[(3*AL)/4+2]=2;
  182.         lmenu();
  183.             break;
  184.     case 'x':                    /* random rule */
  185.         xblnk();
  186.         for (i0=0; i0<KK; i0++) {
  187.         for (i1=0; i1<KK; i1++) {
  188.         for (i2=0; i2<KK; i2++) {
  189.           if ((KK*(KK*i0+i1)+i2)%4 == 0) i=rand();
  190.           ascrule[i0][i1][i2]='0'+i%3;
  191.           i/=3;
  192.         };};};
  193.         rmenu();
  194.         break;
  195.     case 'y':                    /* random line */
  196.         xblnk();
  197.         ranlin();
  198.             lmenu();
  199.         break;
  200.     case 'Y':                    /* symmetrize rule */
  201.         for (i0=0; i0<KK; i0++) {
  202.         for (i1=0; i1<KK; i1++) {
  203.         for (i2=0; i2<KK; i2++) {
  204.         ascrule[i2][i1][i0]=ascrule[i0][i1][i2];      
  205.         };};};
  206.         break;
  207.     case 'B':                    /* begin barrier */
  208.         a=kbdin();
  209.         b=kbdin();
  210.         ascrule[0][a-'0'][b-'0']=a;
  211.         ascrule[1][a-'0'][b-'0']=a;
  212.         ascrule[2][a-'0'][b-'0']=a;
  213.         rmenu();
  214.         break;
  215.     case 'E':                    /* end barrier */
  216.         a=kbdin();
  217.         b=kbdin();
  218.         ascrule[a-'0'][b-'0'][0]=b;
  219.         ascrule[a-'0'][b-'0'][1]=b;
  220.         ascrule[a-'0'][b-'0'][2]=b;
  221.         rmenu();
  222.         break;
  223.     case 'L':                    /* left glider link */
  224.         a=kbdin();
  225.         b=kbdin();
  226.         c=kbdin();
  227.         ascrule[a-'0'][b-'0'][c-'0']=c;
  228.         rmenu();
  229.         break;
  230.     case 'R':                    /* left glider link */
  231.         a=kbdin();
  232.         b=kbdin();
  233.         c=kbdin();
  234.         ascrule[a-'0'][b-'0'][c-'0']=a;
  235.         rmenu();
  236.         break;
  237.     case 'S':                    /* still life link */
  238.         a=kbdin();
  239.         b=kbdin();
  240.         c=kbdin();
  241.         ascrule[a-'0'][b-'0'][c-'0']=b;
  242.         rmenu();
  243.         break;
  244.     case '=':
  245.         for (i=1; i<8;  i++) {
  246.         for (j=0; j<40; j++) arr1[40*i+j]=arr1[j];};
  247.         lmenu();
  248.         break;
  249.     case '~':
  250.         for (i=1; i<16;  i++) {
  251.         for (j=0; j<20; j++) arr1[20*i+j]=arr1[j];};
  252.         lmenu();
  253.         break;
  254.         default: break;
  255.         };
  256.     };
  257.     if (more=='n') break;
  258.     do {
  259.     evolve(rule);
  260.     videocursor(0,0,0);
  261.     scrstr("More?");
  262.     videocursor(0,0,34);
  263.     scrstr("y/n/cr");
  264.     more=kbdin();
  265.     } while (more=='\015');
  266.     videomode(T80X25);                    /* reset the screen */
  267.     if (more=='n') break;
  268.     };
  269.   videomode(T80X25);}    
  270.  
  271. /* edit the rule */
  272. edrule() {
  273. char c;
  274. int  i, i0, i1, i2;
  275.  
  276. i=6; i0=0; i1=0, i2=0;
  277.     while (0<1) {
  278.         videocursor(0,3,i);
  279.         c = kbdin();
  280.         if (c == '\015') break;                /* carriage return exits */
  281.         switch (c) {
  282.         case '0':  case '1': case '2':            /* state */
  283.         ascrule[i0][i1][i2] = c;
  284.             i2++;
  285.         if (i2>2) {i2=0; i1++;};
  286.         if (i1>2) {i1=0; i0++;};
  287.         if (i0>2) {i2=0; };
  288.             videocattr(0,c,3,1);
  289.             if (i<6+DS) i++;
  290.             break;
  291.         case ' ': case '\315':                /* space = advance */
  292.             i2++;
  293.         if (i2>2) {i2=0; i1++;};
  294.         if (i1>2) {i1=0; i0++;};
  295.         if (i0>2) {i2=0; };
  296.             if (i<6+DS) i++;
  297.             break;
  298.         case '\010': case '\313':            /* backspace */
  299.         if (i2!=0) i2--; else {i2=2;
  300.         if (i1!=0) i1--; else {i1=2;
  301.         if (i0!=0) i0--; else {i0=2;
  302.         };};};
  303.             if (i>6) i--;
  304.             break;
  305.     default: break;
  306.         };
  307.     };
  308. }
  309.  
  310. /* edit totalistic rule */
  311. edtrule() {char c; int  i;
  312.     i=0;
  313.     while (i<TS) {
  314.     c=trule[i];
  315.     videocursor(0,3,56+i);
  316.         videocattr(0,c,3,1);
  317.         c = kbdin();
  318.         if (c == '\015') break;
  319.         switch (c) {
  320.           case '0': case '1': case '2':            /* state */
  321.             trule[i]=c;
  322.             videocattr(0,c,5,1);
  323.         i++;
  324.             break;
  325.           case ' ': case '\315':            /* space = advance */
  326.         i++;
  327.             break;
  328.           case '\010': case '\313':            /* backspace */
  329.             if (i!=0) i--;
  330.         break;
  331.       default: break;
  332.           };
  333.     };
  334. }
  335.  
  336. /* edit the line */
  337. edline() {
  338. char c;
  339. int  i, j, k, ii, jj;
  340.  
  341.     videocursor(0,19,0);
  342.     scrstr("insert states using 0, 1, 2");
  343.     videocursor(0,20,0);
  344.     scrstr("move cursor with n(north), s(south), e(east), w(west), or");
  345.     videocursor(0,21,0);
  346.     scrstr("with keyboard arrows. Space, backspace move right and left.");
  347.     videocursor(0,22,0);
  348.     scrstr("( seeks left margin, < absolutely, { up one line, [ down one line");
  349.     videocursor(0,23,0);
  350.     scrstr(") seeks right margin, > absolutely, } up one line, ] down one line");
  351.     videocursor(0,24,0);
  352.     scrstr("carriage return exits");
  353.     jj=4;
  354.     ii=1;
  355.     while (0<1) {
  356.     ii=lim(1,ii,40);
  357.     jj=lim(1,jj,8);
  358.     j=jj-1;
  359.     i=ii-1;
  360.     videocursor(0,j+9,i);
  361.     c=kbdin();
  362.     if (c == '\015') {videoscroll(19,0,24,70,0,3); break;};
  363.     switch (c) {
  364.     case '0':  case '1': case '2':  /* enter  state */
  365.        arr1[40*j+i]=c-'0'; ii++; break;
  366.     case 's': case '\012': case '\320':          jj++; break;    /* down - next line */
  367.     case 'n': case '\013': case '\310':          jj--; break;    /* up   - last line */
  368.     case 'e': case '\014': case '\315': case ' ': ii++; break;    /* space = advance  */
  369.     case 'w': case '\010': case '\313':          ii--; break;    /* backspace */
  370.     case '<': ii=1;  jj=1;  break;  /* absolute left */
  371.     case '{': ii=1;  jj--;  break;  /* left one row up */
  372.     case '(': ii=1;         break;  /* left this row */
  373.     case '[': ii=1;  jj++;  break;  /* left next row */
  374.     case '>': ii=40; jj=40; break;  /* absolute right */
  375.     case '}': ii=40; jj--;  break;  /* right one row up */
  376.     case ')': ii=40;        break;  /* right this row */
  377.     case ']': ii=40; jj++;  break;  /* right next row */
  378.     default: break;
  379.         };
  380.     videocursor(0,j+9,0);
  381.     for (k=0; k<40; k++) videoputc('0'+arr1[40*j+k],1);
  382.     };
  383. }
  384.  
  385. /* display a screen of evolution */
  386. evolve(rule) char *rule; {
  387. int i0, i1, i2, i, j;
  388.     videomode(COLGRAF);                    /* erase the screen */
  389.     videocursor(0,0,0);                    /* top text line */
  390.     scrstr("Rule: ");
  391.     scrrul();
  392.     for (i=0; i<DS; i++) {arule[i] = rule[i]-'0';};
  393.     for (i0=0; i0<KK; i0++) {
  394.     for (i1=0; i1<KK; i1++) {
  395.     for (i2=0; i2<KK; i2++) {
  396.       binrule[i0][i1][i2]=ascrule[i0][i1][i2]-'0';
  397.       };};};
  398.     for (j=8; j<200; j++) videodot(j,AL-1,2);
  399.     for (j=8; j<200; j++) {                /* evolve for 192 generations */
  400.             arr2[0] = binrule[arr1[AL-1]][arr1[0]][arr1[1]];
  401.         for (i=1; i<AL-1; i++) {
  402.             arr2[i] = binrule[arr1[i-1]][arr1[i]][arr1[i+1]];
  403.             };
  404.             arr2[AL-1] = binrule[arr1[AL-2]][arr1[AL-1]][arr1[0]];
  405.         for (i=0;  i<AL; i++) {videodot(j,i,arr1[i]); arr1[i] = arr2[i];};
  406.     if (kbdst()) {kbdin(); break;};
  407.         }
  408. }
  409.  
  410. /* generate a random line of cells in arr1 */
  411. ranlin() {int i, c;
  412. for (i=0; i<AL; i++) {
  413.   if (i%8 == 0) c=rand();
  414.   arr1[i]=c%3; c/=3;};
  415. }
  416.  
  417. /* tutorial and Help screen */
  418. tuto() {
  419.     videomode(T80X25);
  420.     videocursor(0,2,0);
  421.     scrstr("<Copyright (C) 1987 - H.V. McIntosh, G. Cisneros S.>");
  422.     videocursor(0,4,0);
  423.     scrstr("          *** LIFE in One Dimension ***");
  424.     videocursor(0,6,0);
  425.     scrstr("Three States - Black(0), Cyan(1), Magenta(2).");
  426.     videocursor(0,8,0);
  427.     scrstr("First neighbors - one on each side, three altogether.");
  428.     videocursor(0,10,0);
  429.     scrstr("Complete transition rule - random, edited, or stored.");
  430.     videocursor(0,12,0);
  431.     scrstr("Initial Cellular Array - random, edited, or patterned.");
  432.     videocursor(0,14,0);
  433.     scrstr("Some rules are fragile and require several tries before");
  434.     videocursor(0,15,0);
  435.     scrstr("manifesting an interesting evolutionary pattern.");
  436.     videocursor(0,17,0);
  437.     scrstr("Use any key to terminate a display in progress.");
  438.     videocursor(0,21,0);
  439.     scrstr("now, press any key to continue ...");
  440. }
  441.  
  442. /* rule menu */
  443. rmenu() {
  444.     videocursor(0,0,0);
  445.     scrstr("      0........1........2........");
  446.     videocursor(0,1,0);
  447.     scrstr("      0..1..2..0..1..2..0..1..2..");
  448.     videocursor(0,2,0);
  449.     scrstr("      012012012012012012012012012");
  450.     videocursor(0,3,0);
  451.     scrstr("Rule: ");
  452.     scrrul();
  453.     if (istot()==1) {scrstr("     "); printf("%5d",totonu(0));};
  454.     videocursor(0,5,0);
  455.     scrstr("    r(rule), l(line), #nn(stored rule), g(graph), q(quit),");
  456.     videocursor(0,6,0);
  457.     scrstr("             x(random rule), y(random line), u(unit line),");
  458.     videocursor(0,7,0);
  459.     scrstr("             @nn(tot/rule), $nn(dzn tot/rules), t(ed tot/rule).");
  460.     videocursor(0,5,0);
  461.     }
  462.  
  463. /* totalistic rule menu*/
  464. tmenu() {
  465.     videocursor(0,2,50);
  466.     scrstr("      0..1..2");
  467.     videocursor(0,3,50);
  468.     scrstr("rule: ");
  469.     tscrrul();
  470.     videocursor(0,3,56);
  471.     }
  472.  
  473. /* line menu */
  474. lmenu() {int i, j;
  475.     for (j=0; 40*j<AL; j++) {
  476.     videocursor(0,9+j,0);
  477.     for (i=0; i<40; i++) videoputc('0'+arr1[40*j+i],1);
  478.     }
  479.     videocursor(0,5,0); }
  480.  
  481. /* display rule number */
  482. xmenu(n) int n;
  483. {int i, nn;  
  484.     nn=sprintf(xx,"%3d",n);
  485.     videocursor(0,1,40);
  486.     for (i=0; i<nn; i++) videoputc(xx[i],1);
  487.     videocursor(0,1,40); }
  488.  
  489. /* clear screen space for rule number */
  490. xblnk() {
  491.     videocursor(0,1,40);
  492.     scrstr("    ");
  493.     videocursor(0,5,0); }
  494.  
  495. /* copy saved rule #n into active rule */
  496. xtoasc(n) int n; { int i0, i1, i2;
  497.     xmenu(n);
  498.     for (i0=0; i0<KK; i0++) {
  499.     for (i1=0; i1<KK; i1++) {
  500.     for (i2=0; i2<KK; i2++) {
  501.     ascrule[i0][i1][i2] = xrule[n][i0][i1][i2];        /* random sample rule */
  502.     };};}; }
  503.  
  504. /* change totalistic rule to general rule */
  505. totoasc() {
  506. int i0, i1, i2;
  507. for (i0=0; i0<3; i0++) {
  508. for (i1=0; i1<3; i1++) {
  509. for (i2=0; i2<3; i2++) {
  510. ascrule[i0][i1][i2]=trule[i0+i1+i2];
  511. };};};
  512. }
  513.  
  514. /* change decimal totalistic rule to sum values */
  515. nutoto(x) int x; {int i;
  516. for (i=0; i<TS; i++) {trule[i]=x%3+'0'; x/=3;};}
  517.  
  518. /* change sum values to decimal totalistic rule */
  519. int totonu(i) int i; {int r;
  520.   if (i<TS) r=(trule[i]-'0')+3*totonu(i+1); else r=0;
  521.   return r; }
  522.  
  523. /* test whether a rule is totalistic */
  524. int istot() {int i0, i1, i2, l;
  525.     l=1;
  526.     trule[0]=ascrule[0][0][0];
  527.     trule[1]=ascrule[1][0][0];
  528.     trule[2]=ascrule[2][0][0];
  529.     trule[3]=ascrule[2][1][0];
  530.     trule[4]=ascrule[2][2][0];
  531.     trule[5]=ascrule[2][2][1];
  532.     trule[6]=ascrule[2][2][2];
  533.     for (i0=0; i0<KK; i0++) {
  534.     for (i1=0; i1<KK; i1++) {
  535.     for (i2=0; i2<KK; i2++) {
  536.     if (ascrule[i0][i1][i2]!=trule[i0+i1+i2]) l=0;      
  537.     };};};
  538.     return l; }
  539.  
  540. /* limit j to interval (i,k) */
  541. int lim(i,j,k) int i, j, k;
  542.     {if (i>=j) return i; if (k<=j) return k; return j;}
  543.  
  544. /* display the rule number on the screen */
  545. scrrul() {int i0, i1, i2;
  546.   for (i0=0; i0<KK; i0++) {
  547.   for (i1=0; i1<KK; i1++) {
  548.   for (i2=0; i2<KK; i2++) {
  549.   videoputc(ascrule[i0][i1][i2],1);      
  550.   };};}; }
  551.  
  552. /* display totalistic rule number by sum */
  553. tscrrul() {int i;
  554.   for (i=0; i<TS; i++) {videoputc(trule[i]); }; }
  555.  
  556. /* write a string in graphics mode */
  557. scrstr(s) char *s;
  558.   {for (; *s != '\0'; s++) videoputc(*s,1); }
  559.  
  560. /* keyboard status */
  561. int kbdst() {return(bdos(11) & 0xFF);}
  562.  
  563. /* direct keyboard input, no echo */
  564. kbdin() {int c;
  565.   if ((c = bdos(7) & 0xFF) == '\0') c = (bdos(7) & 0xFF) | 0x80;
  566.   return(c);
  567. }
  568.  
  569. /* read number from keyboard */
  570. int numin(n) int n; {char c;
  571.   c=kbdin();
  572.   if (c>='0'&&c<='9') return(numin(10*n+(c-'0'))); else return(n);
  573. }
  574.  
  575. /* end */
  576.