home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume1 / rot22 / rot.c < prev   
C/C++ Source or Header  |  1987-05-05  |  10KB  |  480 lines

  1. /*
  2.  * Revision History:
  3.  *
  4.  * Original source from:
  5.  *  Peter da Silva (ihnp4!shell!neuro1!{hyd-ptd,datafact,baylor}!peter)
  6.  *
  7.  * Changes for padding added by:
  8.  *  Andrew Scott Beals ({ucbvax,decwrl}!amdcad!bandy or bandy@amdcad.amd.com)
  9.  *  20 April 1987
  10.  *
  11.  * Additional changes for padding, fix for computation of tglen,
  12.  * increase max lines, improve termlib handling, add System V #ifdefs.
  13.  *  Bill Randle (billr@tekred.TEK.COM)
  14.  *  21 April 1987
  15.  *
  16.  * Add padding for cl.
  17.  *  Andrew Scott Beals ({ucbvax,decwrl}!amdcad!bandy or bandy@amdcad.amd.com)
  18.  *  22 April 1987
  19.  *
  20.  * Add comments and scroll fixes from Colin Plumb (ccplumb@watmath.UUCP)
  21.  * More terminal handling cleanup and error checking.
  22.  *  Bill Randle (billr@tekred.TEK.COM)
  23.  *  22 April 1987
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include "patchlvl.h"
  28.  
  29. #ifdef SYSV
  30. # include <termio.h>
  31. #else
  32. # include <sgtty.h>
  33. #endif
  34.  
  35. /*        -- Miscellaneous defines --                     */
  36. #define FALSE 0
  37. #define TRUE 1
  38. #define MAXCOL 80
  39. #define MAXLI 36
  40.  
  41. #define min(a,b)    ((a)<(b) ? a : b)
  42.  
  43. extern char *tgetstr();
  44.  
  45. int lastx, lasty;
  46. struct _c {
  47.     struct _c *c_next;
  48.     int c_line, c_column;
  49.     char c_mark;
  50. } *clist;
  51.  
  52. /*        -- Global variables --                         */
  53. char *tent;                                               /* Pointer to tbuf */
  54. extern char PC;                                             /* Pad character */
  55. extern char *UP, *BC;                         /* Upline, backsapce character */
  56. extern short ospeed;                                /* Terminal output speed */
  57. int tglen, bclen;
  58.  
  59. char *cm,                                                   /* Cursor motion */
  60.      *cl,                                                    /* Clear screen */
  61.      *ti,                            /* Init terminal */
  62.      *te;                           /* Reset terminal */
  63. int  li,                                                  /* lines on screen */
  64.      co;                                                    /* columns ditto */
  65. char screen[MAXLI+1][MAXCOL];
  66. char newscreen[MAXLI+1][MAXCOL];
  67.  
  68. main(ac, av)
  69. int ac;
  70. char **av;
  71. {
  72.     /* set ospeed so padding works correctly */
  73. #ifdef SYSV
  74.     struct termio    p;
  75.  
  76.     if(ioctl(1, TCGETA, &p) != -1)
  77.         ospeed=p.c_cflag & CBAUD;
  78. #else
  79.     struct sgttyb    p;
  80.  
  81.     if(ioctl(1, TIOCGETP, &p) != -1)
  82.         ospeed=p.sg_ospeed;
  83. #endif
  84.  
  85.     srand(getpid());    /* init random number generator */
  86.     tinit(getenv("TERM"));    /* init terminal */
  87.     if(ac > 1)
  88.         /* do all files */
  89.         while(--ac)
  90.             dropf(*++av);
  91.     else
  92.         /* or stdin */
  93.         fdropf(stdin);
  94.     tend();            /* clean up terminal */
  95. }
  96.  
  97. /* put character c at (x, y) */
  98. at(x, y, c)
  99. int x, y;
  100. char c;
  101. {
  102. #ifdef DEBUG
  103.     _at(x, y);
  104. #else
  105.     /* optimize cursor motion if goal is on *same* line */
  106.     if(y==lasty) {
  107.         if(x!=lastx) {
  108.             if(x<lastx && (lastx-x)*bclen<tglen)
  109.                 /* backspace into place if it takes */
  110.                 /* less characters than cursor motion */
  111.                 while(x<lastx) {
  112.                     if (bclen > 1)
  113.                         outs(BC);
  114.                     else
  115.                         putchar(*BC);
  116.                     lastx--;
  117.                 }
  118.             else if(x>lastx && x-lastx<tglen)
  119.                 /* print intervening characters */
  120.                 while(x>lastx) {
  121.                     putchar(newscreen[lasty][lastx]);
  122.                     lastx++;
  123.                 }
  124.             else
  125.                 _at(x, y);
  126.         }
  127.     } else
  128.         _at(x, y);
  129. #endif
  130.     c &= ~0200;
  131.     putchar(c);
  132.     if(c >= ' ' && c != '\177')
  133.         lastx++;
  134.     if(lastx>=co) {
  135.         lastx -= co;
  136.         lasty++;
  137.     }
  138. }
  139.  
  140. _at(x, y)
  141. int x, y;
  142. {
  143.     extern void    outc();
  144.  
  145.     tputs(tgoto(cm, x, y), 1, outc);     /* handle padding */
  146.     lastx = x;
  147.     lasty = y;
  148. }
  149.  
  150. void
  151. outc(c)
  152. register c;
  153. {
  154.     putc(c, stdout);
  155. }
  156.  
  157. /* initialize terminal dependent variables */
  158. tinit(name)
  159. char *name;
  160. {
  161.     static char junkbuf[1024], *junkptr;
  162.     char tbuf[1024];
  163.     int  intr();
  164.  
  165.     junkptr = junkbuf;
  166.  
  167.     tgetent(tbuf, name);
  168.  
  169.     if (!tgetflag("bs"))        /* is backspace not used? */
  170.         BC = tgetstr("bc",&junkptr);    /* find out what is */
  171.     else
  172.         BC = "\b";        /* make a backspace handy */
  173.     bclen = strlen(BC);        /* for optimization stuff */
  174.     if (tgetstr("pc", &junkptr) != NULL)
  175.         PC = *junkptr;  /* set pad character */
  176.     else
  177.         PC = '\0';
  178.     UP = tgetstr("up", &junkptr);
  179.     cm = tgetstr("cm", &junkptr);
  180.     if (cm == NULL) {
  181.         printf("Can't rot on dumb terminals.\n");
  182.         exit(1);
  183.     }
  184.     cl = tgetstr("cl", &junkptr);
  185.     ti = tgetstr("ti", &junkptr);
  186.     te = tgetstr("te", &junkptr);
  187.     li = min(tgetnum("li"), MAXLI);
  188.     if (li == -1)
  189.         li = 24;
  190.     /* the original code had special case code for last line and */
  191.     /* last column.  Unfortunately, it didn't always work on all */
  192.     /* terminals so we take the easy way out and don't use the   */
  193.     /* bottom line of the screen                     */
  194.     li--;    /* prevent bottom screen line from scrolling */
  195.     co = min(tgetnum("co"), MAXCOL);
  196.     if (co == -1)
  197.         co = 80;
  198.     tglen = strlen(tgoto(cm, co-1, li-1)); /* for optimization stuff */
  199.     if (ti != NULL)
  200.         outs(ti);
  201. }
  202.  
  203. /* cleanup terminal after use */
  204. tend()
  205. {
  206.     if (te != NULL)
  207.         outs(te);
  208.     _at(0, li);
  209.     putchar('\n');
  210.     fflush(stdout);
  211. }
  212.  
  213. /* read in a new screen */
  214. readscreen(fp)
  215. FILE *fp;
  216. {
  217.     int line, column, p;
  218.     char tmp[256];
  219.  
  220.     for(line=0; line<li; line++)
  221.         for(column=0; column<co; column++)
  222.             newscreen[line][column] = screen[line][column] = ' ';
  223.     for(column=0; column<co; column++)
  224.         newscreen[li][column] = screen[li][column] = '*';
  225.     line=0;
  226.     while(line<li) {
  227.         if(!fgets(tmp, 256, fp))
  228.             return;
  229.  
  230.         for(column=0, p=0; tmp[p]; p++) {
  231.             tmp[p] &= ~0200;
  232.             if(tmp[p] < ' ' || tmp[p] == 127)
  233.                 switch(tmp[p]) {
  234.                     case '\t':
  235.                         while(++column % 8)
  236.                             continue;
  237.                         break;
  238.                     case '\n':
  239.                         column = 0;
  240.                         line++;
  241.                         break;
  242.                     default:
  243.                         newscreen[line][column] = '^';
  244.                         column++;
  245.                         if(column>=co) {
  246.                             column -= co;
  247.                             line++;
  248.                         }
  249.                         newscreen[line][column] =
  250.                             (tmp[p]+'@') & 127;
  251.                         column++;
  252.                         break;
  253.                 }
  254.             else {
  255.                 newscreen[line][column] = tmp[p];
  256.                 column++;
  257.             }
  258.             if(column >= co) {
  259.                 column -= co;
  260.                 line++;
  261.             }
  262.             if(line >= li)
  263.                 break;
  264.         }
  265.     }
  266.     for(column=0; column<co; column++)
  267.         newscreen[line][column] = screen[li][column] = '*';
  268. }
  269.  
  270. drawscreen()
  271. {
  272.     extern void    outc();
  273.  
  274.     lastx = lasty = 0;
  275.     if (cl != NULL)
  276.         tputs(cl, li, outc);    /* for really slow terminals */
  277.     update();
  278. }
  279.  
  280. /* copy newscreen[][] to physical screen and screen[][] */
  281. update()
  282. {
  283.     int l, c;
  284.  
  285.     for(l=0; l<li; l++)
  286.         for(c=0; c<co; c++)
  287.             /* copy any changes */
  288.             if(screen[l][c] != newscreen[l][c]) {
  289.                 /* are they *really* different? */
  290.                 if((screen[l][c] & ~0200) !=
  291.                    (newscreen[l][c] & ~0200))
  292.                     at(c, l, newscreen[l][c]);
  293.                 screen[l][c] = newscreen[l][c];
  294.             }
  295. }
  296.  
  297. /* add char at (column, line) to clist if feasable */
  298. drop(line, column)
  299. int line, column;
  300. {
  301.     struct _c *hold;
  302.  
  303.     if(line<0 || line>=li || column<0 || column>=co || /* off screen */
  304.        screen[line][column]==' ' || /* empty */
  305.        screen[line][column] & 0200) /* already in list */
  306.         return;
  307.     if(screen[line+1][column]!=' ' &&
  308.        (column==co-1 ||screen[line+1][column+1]!=' ') &&
  309.        (column==0 ||screen[line+1][column-1]!=' ')) /* can't be dropped */
  310.         return;
  311.  
  312.     hold = (struct _c *) malloc(sizeof(struct _c));
  313.     hold -> c_next = clist;
  314.     hold -> c_column = column;
  315.     hold -> c_line = line;
  316.     hold -> c_mark = 0;
  317.     screen[line][column] |= 0200;
  318.     clist = hold;
  319. }
  320.  
  321. /* drop everything in the clist */
  322. drops()
  323. {
  324.     int line, column;
  325.     struct _c *hold;
  326.  
  327.     for(hold = clist; hold; hold=hold->c_next) {
  328.         line = hold->c_line;
  329.         column = hold->c_column;
  330.         /* add adjacent characters to clist */
  331.         drop(line+1, column);
  332.         drop(line, column+1);
  333.         drop(line-1, column);
  334.         drop(line, column-1);
  335.         /* drop straight down if possible */
  336.         if(newscreen[line+1][column]==' ') {
  337.             newscreen[line+1][column] = screen[line][column];
  338.             newscreen[line][column] = ' ';
  339.             line++;
  340.         }
  341.         /* otherwise try and drop to the sides.  Randomly pick
  342.         /* which side to try first. */
  343.         else if(rand()&01000) {
  344.             if(column>0 && newscreen[line][column-1] == ' ' &&
  345.                 newscreen[line+1][column-1]==' ') {
  346.                 newscreen[line][column-1] =
  347.                     screen[line][column];
  348.                 newscreen[line][column] = ' ';
  349.                 column--;
  350.             }
  351.             else if(column<co-1 &&
  352.                 newscreen[line][column+1] == ' ' &&
  353.                 newscreen[line+1][column+1]==' ') {
  354.                     newscreen[line][column+1] =
  355.                         screen[line][column];
  356.                     newscreen[line][column] = ' ';
  357.                     column++;
  358.             }
  359.             else {
  360.                 /* forget it */
  361.                 screen[line][column] &= ~0200;
  362.                 newscreen[line][column] &= ~0200;
  363.                 hold -> c_mark = 1;
  364.             }
  365.         } else {
  366.             if(column<co-1 && newscreen[line][column+1] == ' ' &&
  367.                 newscreen[line+1][column+1]==' ') {
  368.                 newscreen[line][column+1] =
  369.                     screen[line][column];
  370.                 newscreen[line][column] = ' ';
  371.                 column++;
  372.             }
  373.             else if(column>0 && newscreen[line][column-1] == ' ' &&
  374.                 newscreen[line+1][column-1]==' ') {
  375.                 newscreen[line][column-1] =
  376.                     screen[line][column];
  377.                 newscreen[line][column] = ' ';
  378.                 column--;
  379.             }
  380.             else {
  381.                 /* forget it */
  382.                 newscreen[line][column] &= ~0200;
  383.                 screen[line][column] &= ~0200;
  384.                 hold -> c_mark = 1;
  385.             }
  386.         }
  387.         /* update list entry */
  388.         hold -> c_column = column;
  389.         hold -> c_line = line;
  390.     }
  391.  
  392.     /* delete all list entries marked for deletion */
  393.     /* do all at head of list */
  394.     while(clist && clist->c_mark) {
  395.         struct _c *p = clist;
  396.         clist = clist -> c_next;
  397.         free(p);
  398.     }
  399.     /* ...and all in body */
  400.     hold = clist;
  401.     while(hold && hold->c_next)
  402.         if(hold->c_next->c_mark) {
  403.             struct _c *p = hold->c_next;
  404.             hold->c_next = p->c_next;
  405.             free(p);
  406.         } else
  407.             hold=hold->c_next;
  408. }
  409.  
  410. droplet(line, column)
  411. int line, column;
  412. {
  413.     int ret;
  414.     while(column>=0 && screen[line][column]!=' ')
  415.         column--;
  416.     column++;
  417.     while(column<co && screen[line][column]!=' ')
  418.         drop(line, column++);
  419.     ret = clist != 0;
  420.     while(clist) {
  421.         drops();
  422.         update();
  423.     }
  424.     return ret;
  425. }
  426.  
  427. dropscreen()
  428. {
  429.     int column, line;
  430.     int rubbish = 0, count = 0;
  431.  
  432.     do {
  433.         int start, limit, incr;
  434.         count++;
  435.         rubbish = 0;
  436.         if(count&1) { start=li-2; limit=0; incr = -1; }
  437.         else { start=0; limit=li-2; incr=1; }
  438.         for(line=start; line!=limit && !rubbish; line+=incr) {
  439.             if(line&1)
  440.                 for(column=0; column<co && !rubbish; column++)
  441.                     rubbish += droplet(line, column);
  442.             else
  443.                 for(column=co-1; column>=0 && !rubbish; column--)
  444.                     rubbish += droplet(line, column);
  445.         }
  446.     } while(rubbish);
  447. }
  448.  
  449. dropf(file)
  450. char *file;
  451. {
  452.     FILE *fp;
  453.  
  454.     if((fp = fopen(file, "r")) == NULL) {
  455.         perror(file);
  456.         return;
  457.     }
  458.     fdropf(fp);
  459. }
  460.  
  461. fdropf(fp)
  462. FILE *fp;
  463. {
  464.     int i;
  465.  
  466.     while(!feof(fp)) {
  467.         readscreen(fp);
  468.         drawscreen();
  469.         for(i=0; i<20; i++)
  470.             droplet((rand()>>4) % li, (rand()>>4) % co);
  471.         dropscreen();
  472.     }
  473. }
  474.  
  475. outs(s)
  476. char *s;
  477. {
  478.     fputs(s, stdout);
  479. }
  480.