home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 245_01 / lca22.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-26  |  16.4 KB  |  574 lines

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