jek5036@ultb.isc.rit.edu (J.E. King) (04/19/91)
Submitted-by: J.E. King <jek5036@ultb.isc.rit.edu> Posting-number: Volume 18, Issue 56 Archive-name: clife/part01 Supersedes: clife: Volume 17, Issue 61 With some help from someone out on the net (read the man page) I have improved the life program. Because it is such a small program I thought I would repost it instead of patches (because the p[atches were larger than the original). This is called clife, or a curses implementation life simulator. It simulates the life 'function' which is described in the manual page. Basically it could be thought of as a game, but it isn't. That's why the manual page is under clife.6. Jim King, (jek5036@ultb.isc.rit.edu) -- cut here -- cut here -- cut here -- cut here -- cut here -- cut here -- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./Makefile` then echo "writing ./Makefile" cat > ./Makefile << '\End\Of\Shar\' # On the next line, add a -DHJKL if you wish to use HJKL instead of # arrow keys when building a life screen. CFLAGS = -g #-DHJKL DEST = . MANDEST = /usr/man/man6 EXTHDRS = /usr/include/curses.h \ /usr/include/sgtty.h \ /usr/include/signal.h \ /usr/include/stdio.h \ /usr/include/sys/ioctl.h \ /usr/include/sys/ttychars.h \ /usr/include/sys/ttydev.h \ /usr/include/sys/ttyio.h \ /usr/include/time.h HDRS = LDFLAGS = -g LIBS = -lcurses -ltermlib LINKER = cc MAKEFILE = Makefile OBJS = clife.o PRINT = lpr PROGRAM = clife SRCS = clife.c all: $(PROGRAM) $(PROGRAM): $(OBJS) @echo -n "Loading $(PROGRAM) ... " @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) @echo "done" clean:; @rm -f $(OBJS) depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST) index:; @ctags -wx $(HDRS) $(SRCS) install: $(PROGRAM) @echo Installing $(PROGRAM) in $(DEST) @install -s $(PROGRAM) $(DEST) @echo Copying manual pages... @cp clife.6 $(MANDEST) @chmod 644 $(MANDEST)/clife.6 print:; @$(PRINT) $(HDRS) $(SRCS) program: $(PROGRAM) tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS) update: $(DEST)/$(PROGRAM) $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS) @make -f $(MAKEFILE) DEST=$(DEST) ### clife.o: /usr/include/signal.h /usr/include/time.h /usr/include/stdio.h \ /usr/include/curses.h /usr/include/sgtty.h /usr/include/sys/ioctl.h \ /usr/sys/h/ttychars.h /usr/sys/h/ttydev.h /usr/sys/h/ttyio.h \ /usr/sys/h/sgtty.h /usr/include/sys/ttychars.h \ /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h \End\Of\Shar\ else echo "will not over write ./Makefile" fi if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 1646 ] then echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 1646}'` fi if `test ! -s ./Makefile.sysv` then echo "writing ./Makefile.sysv" cat > ./Makefile.sysv << '\End\Of\Shar\' # On the next line, add a -DHJKL if you wish to use HJKL instead of # arrow keys when building a life screen. CFLAGS = -O -DHJKL DEST = . MANDEST = /usr/man/man6 EXTHDRS = /usr/include/curses.h \ /usr/include/sgtty.h \ /usr/include/signal.h \ /usr/include/stdio.h \ /usr/include/time.h HDRS = LDFLAGS = -O LIBS = -lcurses LINKER = cc MAKEFILE = Makefile OBJS = clife.o PRINT = lpr PROGRAM = clife SRCS = clife.c all: $(PROGRAM) $(PROGRAM): $(OBJS) @echo -n "Loading $(PROGRAM) ... " @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) @echo "done" clean:; @rm -f $(OBJS) depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST) index:; @ctags -wx $(HDRS) $(SRCS) install: $(PROGRAM) @echo Installing $(PROGRAM) in $(DEST) @install -s $(PROGRAM) $(DEST) @echo Copying manual pages... @cp clife.6 $(MANDEST) @chmod 644 $(MANDEST)/clife.6 print:; @$(PRINT) $(HDRS) $(SRCS) program: $(PROGRAM) tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS) update: $(DEST)/$(PROGRAM) $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS) @make -f $(MAKEFILE) DEST=$(DEST) ### clife.o: /usr/include/signal.h /usr/include/time.h /usr/include/stdio.h \ /usr/include/curses.h \End\Of\Shar\ else echo "will not over write ./Makefile.sysv" fi if [ `wc -c ./Makefile.sysv | awk '{printf $1}'` -ne 1302 ] then echo `wc -c ./Makefile.sysv | awk '{print "Got " $1 ", Expected " 1302}'` fi if `test ! -s ./clife.6` then echo "writing ./clife.6" cat > ./clife.6 << '\End\Of\Shar\' .TH clife 6 .SH Name clife \- Life simulation using curses .SH Syntax .B clife \fI[-dp]\fR .SH Description The .PN clife program is a simulator which has been around for quite some time. The screen is set up with random 'people' on the screen. Each person is represented by a '*'. The rules are simple: If three people are around any given square, a person is born there. If only two people are around any given square, then that person stays. Any other number around a square kills the person there. (not enough food) .PP The clife (which stands for curses life) simulator will produce certain distinguishable patterns attributable to the life equation. .SH Options The .PN \-d option allows you to draw your own pattern on the screen and run it through the simulator. This is done by moving around the screen with the arrow keys, (or using the 'hjkl' keys if the program was compiled with that option) and using the spacebar to put a person in the square you are currently over. If a person is there already, kill the person. (blank the space) The .PN \-p option will print out information about the life cycles on the bottom of the screen after each cycle. .SH Author Jim King, (jek5036@ritvax.isc.rit.edu) .SH Additions Sameer Parekh (zane@ddsw1.MCS.COM) added wrap ability, fixed quit bug, enhanced draw segment to allow HJKL or arrows at compile time, and enhanced argument parsing. \End\Of\Shar\ else echo "will not over write ./clife.6" fi if [ `wc -c ./clife.6 | awk '{printf $1}'` -ne 1399 ] then echo `wc -c ./clife.6 | awk '{print "Got " $1 ", Expected " 1399}'` fi if `test ! -s ./clife.c` then echo "writing ./clife.c" cat > ./clife.c << '\End\Of\Shar\' /* * clife.c - curses life simulator. Translated from Pascal to C implementing * curses Oct 1988 by pulsar@lsrhs, now jek5036@ritvax.isc.rit.edu * * V2 pulsar@lsrhs Oct 1988 * - Draw your own pattern then 'life' it. * * V2.1 zane@ddsw1.MCS.COM Apr 1991 * - Addition so the screen wraps around. * - Fix of the bug which caused the shell to mess up after * quitting with SIGINT. * - Also enable all options with one argument. (clife -dp * instead of clife -d -p, both are usable.) * - Enable choice of arrow keys or HJKL at compile-time. * * jek5036@ultb.isc.rit.edu (formerly pulsar@lsrhs) * - SYSV Makefile (I hope it works..) * - Couple of minor fixes including random() instead of rand() */ #include <signal.h> #include <time.h> #include <stdio.h> #include <curses.h> /* a value of -1 will make it go forever */ /* a value of 0 will make it exit immed. */ #define REPSTOP -1 /* number of repetitions before stop */ /* in a looping pattern */ /* * I don't need any flames about global variables. */ #define MAXROW 23 #define MAXCOL 79 int present[MAXROW+1][MAXCOL+1], /* screen 1 cycle ago */ past[MAXROW+1][MAXCOL+1], /* screen this cycle */ total, /* total # of changes */ icnt, /* counter to check for repetition */ minrow = 0, mincol = 0, pri = 0, draw = 0, i, j, k, /* loop counters */ cycle, /* current cycle # */ changes, /* # of changes this cycle (live + die) */ die, /* number of deaths this cycle */ live; /* number of births this cycle */ WINDOW *mns, /* Main Screen */ *info; /* Bottom line */ /* * cleanup - cleanup then go back to makscr */ cleanup() { move(23, 0); /* go to bottom of screen */ refresh(); /* update cursor */ endwin(); /* Clean up curses */ exit(1); } /* * initialize - init windows, variables, and signals */ initialize() { srandom(getpid()); /* init rand seed */ initscr(); /* init curses */ signal(SIGINT, cleanup); /* catch ^C */ signal(SIGTERM, exit); /* exit on kill -15 */ mns = newwin(MAXROW, MAXCOL, 0, 0); /* new window */ scrollok(mns, FALSE); info = newwin(1, 80, 23, 0); scrollok(info, FALSE); wclear(mns); if (!draw) { /* if no draw, make rand pattern */ for (j = 0; j < MAXROW; j++) { for (k = 0; k < MAXCOL; k++) { present[j][k] = random()%2; if (present[j][k] == 1) changes++, live++; } } } } /* * makscr - make your own screen using arrow keys and space bar */ makscr() { int curx, cury; /* current point on screen */ char c; /* input char */ wclear(info); wmove(info, 0, 0); #ifdef HJKL wprintw(info, "Use 'hjkl' keys to move, space to place / erase, ^D to start"); #else wprintw(info, "Use arrow keys to move, space to place / erase, ^D to start"); #endif wrefresh(info); curx = cury = 1; wmove(mns, cury-1, curx-1); wrefresh(mns); noecho(); crmode(); for (;;) { c = wgetch(mns); if (c == '\004') break; else if (c == ' ') { if (present[cury][curx]) { --present[cury][curx]; changes++; die++; mvwaddch(mns, cury, curx, ' '); } else { ++present[cury][curx]; changes++; live++; mvwaddch(mns, cury, curx, '*'); } #ifndef HJKL /* This portion is used for the arrow keys */ } else if (c == '\033') { wgetch(mns); switch(wgetch(mns)) { case 'A': --cury; break; case 'B': ++cury; break; case 'C': ++curx; break; case 'D': --curx; break; default: break; } } #else /* This portion for HJKL */ } else { switch(c) { case 'H': case 'h': --curx; break; case 'J': case 'j': ++cury; break; case 'K': case 'k': --cury; break; case 'L': case 'l': ++curx; break; default: break; } } #endif /* End the HJKL section */ if (cury > MAXROW) cury = minrow; if (cury < minrow) cury = MAXROW; if (curx > MAXCOL) curx = mincol; if (curx < mincol) curx = MAXCOL; wmove(mns, cury, curx); wrefresh(mns); } wclear(info); } /* Update rules: 2 or 3 adjacent alive --- stay alive * 3 adjacent alive -- dead to live * all else die or stay dead */ update() /* Does all mathmatical calculations */ { int howmany, w, x, y, z; changes = die = live = 0; for (j = 0; j < MAXROW; j++) { for (k = 0; k < MAXCOL; k++) { w = (j-1 < 0) ? (MAXROW-1) : j-1; x = (j+1 > MAXROW-1) ? 0 : j+1; y = (k-1 < 0) ? (MAXCOL-1) : k-1; z = (k+1 > MAXCOL-1) ? 0 : k+1; /* * Nice addition above four lines for wrap.. wouldn't have thought * of it myself.. -- Jim */ howmany = (past[w][y] + past[w][k] + past[w][z] + past[j][y] + past[j][z] + past[x][y] + past[x][k] + past[x][z]); switch(howmany) { case 0: case 1: case 4: case 5: case 6: case 7: case 8: present[j][k] = 0; if (past[j][k]) changes++, die++; break; case 3: present[j][k] = 1; if (!past[j][k]) changes++, live++; break; default: break; } } } if (live == die) ++icnt; else icnt = 0; if (icnt == REPSTOP) cleanup(); } /* * print - updates the screen according to changes from past to present */ print() /* Updates the screen, greatly improved using curses */ { if (pri) { wmove(info, 0, 0); total += changes; wprintw(info, "Cycle %d | %d changes: %d died and %d born & %d total changes", ++cycle, changes, die, live, total); wclrtoeol(info); } for (j = 0; j < MAXROW; j++) { for (k = 0; k < MAXCOL; k++) { if (present[j][k] != past[j][k] && present[j][k] == 1) { wmove(mns, j, k); wprintw(mns, "*"); } else if (present[j][k] != past[j][k] && present[j][k] == 0) { wmove(mns, j, k); wprintw(mns, " "); } } } if (pri) wrefresh(info); wrefresh(mns); } /* * main - main procedure */ main(ac, av) int ac; char *av[]; { if (ac > 1) { for (j = 1; j < ac; j++) { if (av[j][0] == '-') { for(i = 1; i < strlen(av[j]); i++) { switch(av[j][i]) { case 'd': ++draw; break; case 'p': ++pri; break; default: fprintf(stderr, "%s: usage: %s [-dpf] <filename>]\n", av[0], av[0]); exit(1); } } } } } if (draw) printf("User-built screen\n"); if (pri) printf("Print statistics\n"); initialize(); if (draw) makscr(); wclear(info); wmove(info, 0, 0); wprintw(info, "Life V2.1 by Jim King (jek5036@ultb.isc.rit.edu), additions by Sameer Parekh"); wrefresh(info); for (;;) { print(); for (j = 0; j < MAXROW; j++) { for (k = 0; k < MAXCOL; k++) past[j][k] = present[j][k]; } update(); } } \End\Of\Shar\ else echo "will not over write ./clife.c" fi if [ `wc -c ./clife.c | awk '{printf $1}'` -ne 6649 ] then echo `wc -c ./clife.c | awk '{print "Got " $1 ", Expected " 6649}'` fi echo "Finished archive 1 of 1" exit exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.