home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume18 / clife / part01 next >
Internet Message Format  |  1991-04-20  |  14KB

  1. From: jek5036@ultb.isc.rit.edu (J.E. King)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i056:  clife - Curses based Life simulator, Part01/01
  4. Message-ID: <1991Apr19.024645.8063@sparky.IMD.Sterling.COM>
  5. Date: 19 Apr 91 02:46:45 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 4955564a 9bb48de2 8d5f88a0 c6e15a04
  8.  
  9. Submitted-by: J.E. King <jek5036@ultb.isc.rit.edu>
  10. Posting-number: Volume 18, Issue 56
  11. Archive-name: clife/part01
  12. Supersedes: clife: Volume 17, Issue 61
  13.  
  14.     With some help from someone out on the net (read the man page)
  15. I have improved the life program.  Because it is such a small program
  16. I thought I would repost it instead of patches (because the p[atches were
  17. larger than the original).
  18.  
  19. This is called clife, or a curses implementation life simulator. It
  20. simulates the life 'function' which is described in the manual page.
  21. Basically it could be thought of as a game, but it isn't.  That's 
  22. why the manual page is under clife.6.
  23.  
  24. Jim King, (jek5036@ultb.isc.rit.edu)
  25.  
  26. -- cut here -- cut here -- cut here -- cut here -- cut here -- cut here --
  27. #!/bin/sh
  28. # to extract, remove the header and type "sh filename"
  29. if `test ! -s ./Makefile`
  30. then
  31. echo "writing ./Makefile"
  32. cat > ./Makefile << '\End\Of\Shar\'
  33. # On the next line, add a -DHJKL if you wish to use HJKL instead of
  34. # arrow keys when building a life screen.
  35.  
  36. CFLAGS        = -g #-DHJKL
  37. DEST          = .
  38. MANDEST       = /usr/man/man6
  39. EXTHDRS          = /usr/include/curses.h \
  40.         /usr/include/sgtty.h \
  41.         /usr/include/signal.h \
  42.         /usr/include/stdio.h \
  43.         /usr/include/sys/ioctl.h \
  44.         /usr/include/sys/ttychars.h \
  45.         /usr/include/sys/ttydev.h \
  46.         /usr/include/sys/ttyio.h \
  47.         /usr/include/time.h
  48. HDRS          =
  49. LDFLAGS          = -g
  50. LIBS          = -lcurses -ltermlib
  51. LINKER          = cc
  52. MAKEFILE      = Makefile
  53. OBJS          = clife.o
  54. PRINT          = lpr
  55. PROGRAM          = clife
  56. SRCS          = clife.c
  57.  
  58. all:        $(PROGRAM)
  59.  
  60. $(PROGRAM):     $(OBJS)
  61.         @echo -n "Loading $(PROGRAM) ... "
  62.         @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
  63.         @echo "done"
  64.  
  65. clean:;        @rm -f $(OBJS)
  66.  
  67. depend:;    @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
  68.  
  69. index:;        @ctags -wx $(HDRS) $(SRCS)
  70.  
  71. install:    $(PROGRAM)
  72.         @echo Installing $(PROGRAM) in $(DEST)
  73.         @install -s $(PROGRAM) $(DEST)
  74.         @echo Copying manual pages...
  75.         @cp clife.6 $(MANDEST)
  76.         @chmod 644 $(MANDEST)/clife.6
  77.  
  78. print:;        @$(PRINT) $(HDRS) $(SRCS)
  79.  
  80. program:        $(PROGRAM)
  81.  
  82. tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
  83.  
  84. update:        $(DEST)/$(PROGRAM)
  85.  
  86. $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
  87.         @make -f $(MAKEFILE) DEST=$(DEST) 
  88. ###
  89. clife.o: /usr/include/signal.h /usr/include/time.h /usr/include/stdio.h \
  90.     /usr/include/curses.h /usr/include/sgtty.h /usr/include/sys/ioctl.h \
  91.     /usr/sys/h/ttychars.h /usr/sys/h/ttydev.h /usr/sys/h/ttyio.h \
  92.     /usr/sys/h/sgtty.h /usr/include/sys/ttychars.h \
  93.     /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h
  94. \End\Of\Shar\
  95. else
  96.   echo "will not over write ./Makefile"
  97. fi
  98. if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 1646 ]
  99. then
  100. echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 1646}'`
  101. fi
  102. if `test ! -s ./Makefile.sysv`
  103. then
  104. echo "writing ./Makefile.sysv"
  105. cat > ./Makefile.sysv << '\End\Of\Shar\'
  106. # On the next line, add a -DHJKL if you wish to use HJKL instead of
  107. # arrow keys when building a life screen.
  108.  
  109. CFLAGS        = -O -DHJKL
  110. DEST          = .
  111. MANDEST       = /usr/man/man6
  112. EXTHDRS          = /usr/include/curses.h \
  113.         /usr/include/sgtty.h \
  114.         /usr/include/signal.h \
  115.         /usr/include/stdio.h \
  116.         /usr/include/time.h
  117. HDRS          =
  118. LDFLAGS          = -O
  119. LIBS          = -lcurses
  120. LINKER          = cc
  121. MAKEFILE      = Makefile
  122. OBJS          = clife.o
  123. PRINT          = lpr
  124. PROGRAM          = clife
  125. SRCS          = clife.c
  126.  
  127. all:        $(PROGRAM)
  128.  
  129. $(PROGRAM):     $(OBJS)
  130.         @echo -n "Loading $(PROGRAM) ... "
  131.         @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
  132.         @echo "done"
  133.  
  134. clean:;        @rm -f $(OBJS)
  135.  
  136. depend:;    @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
  137.  
  138. index:;        @ctags -wx $(HDRS) $(SRCS)
  139.  
  140. install:    $(PROGRAM)
  141.         @echo Installing $(PROGRAM) in $(DEST)
  142.         @install -s $(PROGRAM) $(DEST)
  143.         @echo Copying manual pages...
  144.         @cp clife.6 $(MANDEST)
  145.         @chmod 644 $(MANDEST)/clife.6
  146.  
  147. print:;        @$(PRINT) $(HDRS) $(SRCS)
  148.  
  149. program:        $(PROGRAM)
  150.  
  151. tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
  152.  
  153. update:        $(DEST)/$(PROGRAM)
  154.  
  155. $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
  156.         @make -f $(MAKEFILE) DEST=$(DEST) 
  157. ###
  158. clife.o: /usr/include/signal.h /usr/include/time.h /usr/include/stdio.h \
  159.      /usr/include/curses.h
  160. \End\Of\Shar\
  161. else
  162.   echo "will not over write ./Makefile.sysv"
  163. fi
  164. if [ `wc -c ./Makefile.sysv | awk '{printf $1}'` -ne 1302 ]
  165. then
  166. echo `wc -c ./Makefile.sysv | awk '{print "Got " $1 ", Expected " 1302}'`
  167. fi
  168. if `test ! -s ./clife.6`
  169. then
  170. echo "writing ./clife.6"
  171. cat > ./clife.6 << '\End\Of\Shar\'
  172. .TH clife 6
  173. .SH Name
  174. clife \- Life simulation using curses
  175. .SH Syntax
  176. .B clife
  177. \fI[-dp]\fR
  178. .SH Description
  179. The
  180. .PN clife
  181. program is a simulator which has been around for quite some time.
  182. The screen is set up with random 'people' on the screen.  Each
  183. person is represented by a '*'.  The rules are simple:  If
  184. three people are around any given square, a person is born there.  If
  185. only two people are around any given square, then that person stays.
  186. Any other number around a square kills the person there. (not enough food)
  187. .PP
  188. The clife (which stands for curses life) simulator will produce certain
  189. distinguishable patterns attributable to the life equation.
  190. .SH Options
  191. The
  192. .PN \-d
  193. option allows you to draw your own pattern on the screen
  194. and run it through the simulator.  This is done by moving around the
  195. screen with the arrow keys, (or using the 'hjkl' keys if the program
  196. was compiled with that option) and using the spacebar to put a person in the
  197. square you are currently over. If a person is there already,
  198. kill the person. (blank the space)
  199.  
  200. The
  201. .PN \-p
  202. option will print out information about the life cycles on the bottom
  203. of the screen after each cycle.
  204. .SH Author
  205. Jim King, (jek5036@ritvax.isc.rit.edu)
  206.  
  207. .SH Additions
  208. Sameer Parekh (zane@ddsw1.MCS.COM) added wrap ability, fixed quit bug,
  209. enhanced draw segment to allow HJKL or arrows at compile time, and 
  210. enhanced argument parsing.
  211.  
  212. \End\Of\Shar\
  213. else
  214.   echo "will not over write ./clife.6"
  215. fi
  216. if [ `wc -c ./clife.6 | awk '{printf $1}'` -ne 1399 ]
  217. then
  218. echo `wc -c ./clife.6 | awk '{print "Got " $1 ", Expected " 1399}'`
  219. fi
  220. if `test ! -s ./clife.c`
  221. then
  222. echo "writing ./clife.c"
  223. cat > ./clife.c << '\End\Of\Shar\'
  224. /*
  225.  * clife.c - curses life simulator.  Translated from Pascal to C implementing
  226.  *           curses Oct 1988 by pulsar@lsrhs, now jek5036@ritvax.isc.rit.edu
  227.  *
  228.  *    V2    pulsar@lsrhs Oct 1988
  229.  *       -     Draw your own pattern then 'life' it.
  230.  *
  231.  *      V2.1    zane@ddsw1.MCS.COM  Apr 1991 
  232.  *       -     Addition so the screen wraps around.
  233.  *       -    Fix of the bug which caused the shell to mess up after
  234.  *        quitting with SIGINT.
  235.  *       -    Also enable all options with one argument.  (clife -dp
  236.  *        instead of clife -d -p, both are usable.)
  237.  *       -    Enable choice of arrow keys or HJKL at compile-time.
  238.  *
  239.  *              jek5036@ultb.isc.rit.edu (formerly pulsar@lsrhs)
  240.  *         -    SYSV Makefile (I hope it works..)
  241.  *         -    Couple of minor fixes including random() instead of rand()
  242.  */
  243.  
  244. #include <signal.h>
  245. #include <time.h>
  246. #include <stdio.h>
  247. #include <curses.h>
  248.  
  249.                 /* a value of -1 will make it go forever */
  250.                 /* a value of 0 will make it exit immed. */
  251. #define    REPSTOP        -1    /* number of repetitions before stop */
  252.                 /* in a looping pattern */
  253.  
  254. /*
  255.  * I don't need any flames about global variables.
  256.  */
  257.  
  258. #define    MAXROW    23
  259. #define    MAXCOL    79
  260.  
  261. int    present[MAXROW+1][MAXCOL+1],    /* screen 1 cycle ago */
  262.     past[MAXROW+1][MAXCOL+1],    /* screen this cycle */
  263.     total,            /* total # of changes */
  264.     icnt,            /* counter to check for repetition */
  265.     minrow = 0,
  266.     mincol = 0,
  267.     pri = 0,
  268.     draw = 0,
  269.     i, j, k,        /* loop counters */
  270.     cycle,            /* current cycle # */
  271.     changes,        /* # of changes this cycle (live + die) */
  272.     die,            /* number of deaths this cycle */
  273.     live;            /* number of births this cycle */
  274.  
  275. WINDOW    *mns,                /* Main Screen */
  276.     *info;                /* Bottom line */
  277.  
  278. /*
  279.  * cleanup - cleanup then go back to makscr
  280.  */
  281.  
  282. cleanup()
  283. {
  284.     move(23, 0);        /* go to bottom of screen */
  285.     refresh();        /* update cursor */
  286.     endwin();        /* Clean up curses */
  287.     exit(1);
  288. }
  289.  
  290. /*
  291.  * initialize - init windows, variables, and signals
  292.  */
  293.  
  294. initialize()
  295. {
  296.     srandom(getpid());        /* init rand seed */
  297.     initscr();            /* init curses */
  298.     signal(SIGINT, cleanup);    /* catch ^C */
  299.     signal(SIGTERM, exit);        /* exit on kill -15 */
  300.     mns = newwin(MAXROW, MAXCOL, 0, 0);    /* new window */
  301.     scrollok(mns, FALSE);
  302.     info = newwin(1, 80, 23, 0);
  303.     scrollok(info, FALSE);
  304.     wclear(mns);
  305.     if (!draw) {        /* if no draw, make rand pattern */
  306.         for (j = 0; j < MAXROW; j++) {
  307.             for (k = 0; k < MAXCOL; k++) {
  308.                 present[j][k] = random()%2;
  309.                 if (present[j][k] == 1) changes++, live++;
  310.             }
  311.         } 
  312.     }
  313. }
  314.  
  315. /*
  316.  * makscr - make your own screen using arrow keys and space bar
  317.  */
  318.  
  319. makscr()
  320. {
  321.     int    curx, cury;        /* current point on screen */
  322.     char    c;            /* input char */
  323.     
  324.     wclear(info);
  325.     wmove(info, 0, 0);
  326. #ifdef    HJKL
  327.     wprintw(info, "Use 'hjkl' keys to move, space to place / erase, ^D to start");
  328. #else
  329.     wprintw(info, "Use arrow keys to move, space to place / erase, ^D to start");
  330. #endif
  331.     wrefresh(info);
  332.     curx = cury = 1;
  333.     wmove(mns, cury-1, curx-1); wrefresh(mns);
  334.     noecho(); crmode();
  335.     for (;;) {
  336.         c = wgetch(mns);
  337.         if (c == '\004')
  338.             break;
  339.         else if (c == ' ') {
  340.             if (present[cury][curx]) {
  341.                 --present[cury][curx];
  342.                 changes++;
  343.                 die++;
  344.                 mvwaddch(mns, cury, curx, ' ');
  345.             } else {
  346.                 ++present[cury][curx];
  347.                 changes++;
  348.                 live++;
  349.                 mvwaddch(mns, cury, curx, '*');
  350.             }
  351. #ifndef    HJKL    /* This portion is used for the arrow keys */
  352.         } else if (c == '\033') {
  353.             wgetch(mns);
  354.             switch(wgetch(mns)) {
  355.                 case 'A':
  356.                     --cury; break;
  357.                 case 'B':
  358.                     ++cury; break;
  359.                 case 'C':
  360.                     ++curx; break;
  361.                 case 'D':
  362.                     --curx; break;
  363.                 default:
  364.                     break;
  365.             }
  366.         }
  367. #else    /* This portion for HJKL */
  368.         } else {
  369.             switch(c) {
  370.                 case 'H':
  371.                 case 'h':
  372.                     --curx; break;
  373.                 case 'J':
  374.                 case 'j':
  375.                     ++cury; break;
  376.                 case 'K':
  377.                 case 'k':
  378.                     --cury; break;
  379.                 case 'L':
  380.                 case 'l':
  381.                     ++curx; break;
  382.                 default:
  383.                     break;
  384.             }
  385.         }
  386. #endif    /* End the HJKL section */
  387.  
  388.         if (cury > MAXROW) cury = minrow;
  389.         if (cury < minrow) cury = MAXROW;
  390.         if (curx > MAXCOL) curx = mincol;
  391.         if (curx < mincol) curx = MAXCOL;
  392.         wmove(mns, cury, curx);
  393.         wrefresh(mns);
  394.     }
  395.     wclear(info);
  396. }
  397.  
  398. /* Update rules:  2 or 3 adjacent alive --- stay alive
  399.  *                3 adjacent alive -- dead to live
  400.  *                all else die or stay dead
  401.  */
  402.  
  403. update()    /* Does all mathmatical calculations */
  404. {
  405.     int    howmany, w, x, y, z;
  406.     changes = die = live = 0;
  407.     for (j = 0; j < MAXROW; j++) {
  408.         for (k = 0; k < MAXCOL; k++) {
  409.             w = (j-1 < 0) ? (MAXROW-1) : j-1;
  410.             x = (j+1 > MAXROW-1) ? 0 : j+1;
  411.             y = (k-1 < 0) ? (MAXCOL-1) : k-1;
  412.             z = (k+1 > MAXCOL-1) ? 0 : k+1;
  413.  
  414. /*
  415.  * Nice addition above four lines for wrap.. wouldn't have thought
  416.  * of it myself.. -- Jim
  417.  */
  418.  
  419.             howmany = (past[w][y] + past[w][k] + past[w][z] +
  420.                   past[j][y] + past[j][z] + past[x][y] +
  421.                   past[x][k] + past[x][z]);
  422.  
  423.             switch(howmany) {
  424.                 case 0:
  425.                 case 1:
  426.                 case 4:
  427.                 case 5:
  428.                 case 6:
  429.                 case 7:
  430.                 case 8:
  431.                     present[j][k] = 0;
  432.                     if (past[j][k]) changes++, die++;
  433.                     break;
  434.                 case 3:
  435.                     present[j][k] = 1;
  436.                     if (!past[j][k]) changes++, live++;
  437.                     break;
  438.                 default:
  439.                     break;
  440.             }
  441.         }
  442.     }
  443.     if (live == die)
  444.         ++icnt;
  445.     else
  446.         icnt = 0;
  447.  
  448.     if (icnt == REPSTOP)
  449.         cleanup();
  450. }
  451.  
  452. /*
  453.  * print - updates the screen according to changes from past to present
  454.  */
  455.  
  456. print()        /* Updates the screen, greatly improved using curses */
  457. {
  458.     if (pri) {
  459.         wmove(info, 0, 0);
  460.         total += changes;
  461.         wprintw(info, "Cycle %d | %d changes: %d died and %d born & %d total changes", ++cycle, changes, die, live, total);
  462.         wclrtoeol(info);
  463.     }
  464.     for (j = 0; j < MAXROW; j++) {
  465.         for (k = 0; k < MAXCOL; k++) {
  466.             if (present[j][k] != past[j][k] && present[j][k] == 1) {
  467.                 wmove(mns, j, k);
  468.                 wprintw(mns, "*");
  469.             } else if (present[j][k] != past[j][k] && present[j][k] == 0) {
  470.                 wmove(mns, j, k);
  471.                 wprintw(mns, " ");
  472.             }
  473.         }
  474.     }
  475.     if (pri) wrefresh(info);
  476.     wrefresh(mns);
  477. }
  478.  
  479. /*
  480.  * main - main procedure
  481.  */
  482.  
  483. main(ac, av)
  484. int    ac;
  485. char    *av[];
  486. {
  487.     if (ac > 1) {
  488.         for (j = 1; j < ac; j++) {
  489.             if (av[j][0] == '-') {
  490.                 for(i = 1; i < strlen(av[j]); i++) {
  491.                     switch(av[j][i]) {
  492.                     case 'd':
  493.                         ++draw;
  494.                         break;
  495.                     case 'p':
  496.                         ++pri;
  497.                         break;
  498.                     default:
  499.                         fprintf(stderr, "%s: usage: %s [-dpf] <filename>]\n", av[0], av[0]);
  500.                         exit(1);
  501.                     }
  502.                 }
  503.             }
  504.         }
  505.     }
  506.  
  507.     if (draw)
  508.         printf("User-built screen\n");
  509.     if (pri)
  510.         printf("Print statistics\n");
  511.  
  512.     initialize();
  513.     if (draw)
  514.         makscr();
  515.  
  516.     wclear(info);
  517.     wmove(info, 0, 0);
  518.     wprintw(info, "Life V2.1 by Jim King (jek5036@ultb.isc.rit.edu), additions by Sameer Parekh");
  519.     wrefresh(info);
  520.  
  521.     for (;;) {
  522.         print();
  523.         for (j = 0; j < MAXROW; j++) {
  524.             for (k = 0; k < MAXCOL; k++)
  525.                 past[j][k] = present[j][k];
  526.         }
  527.         update();
  528.     }
  529. }
  530. \End\Of\Shar\
  531. else
  532.   echo "will not over write ./clife.c"
  533. fi
  534. if [ `wc -c ./clife.c | awk '{printf $1}'` -ne 6649 ]
  535. then
  536. echo `wc -c ./clife.c | awk '{print "Got " $1 ", Expected " 6649}'`
  537. fi
  538. echo "Finished archive 1 of 1"
  539. exit
  540.  
  541. exit 0 # Just in case...
  542. -- 
  543. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  544. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  545. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  546. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  547.