games-request@tekred.TEK.COM (10/27/87)
Submitted by: unicom!physh (Jon Foreman) Comp.sources.games: Volume 2, Issue 65 Archive-name: cg #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README makefile cg.6 cg.c # Wrapped by billr@tekred on Tue Oct 27 11:53:07 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(815 characters\) sed "s/^X//" >README <<'END_OF_README' XCg plays the game of chess guess, which was described in one of Martin XGardener's famous articles on recreational mathematics. The game starts Xout with a standard 8 X 8 chess board with 5 pieces on it, Xa King, a Queen, a Bishop, a Knight, and a Rook. The pieces Xare all disguised. But it isn't really a guessing game. You may query Xsquares on the board for how may pieces attack that square. From this Xinformation you can deduce which pieces are which. The object of the Xgame is to minimize the number of squares queried in order to find out Xthe identity of all the pieces. X XThis should be a complete package. You should just be Xable to make it and the correct things should happen. Mostly, Xthe instructions are in the manual file. There are no obvious Xcompile time options, except to invoke the optimizer. END_OF_README if test 815 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"makefile\" else echo shar: Extracting \"makefile\" \(47 characters\) sed "s/^X//" >makefile <<'END_OF_makefile' Xall: cg.c X cc -O -o cg cg.c -lcurses -ltermlib END_OF_makefile if test 47 -ne `wc -c <makefile`; then echo shar: \"makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f cg.6 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cg.6\" else echo shar: Extracting \"cg.6\" \(4200 characters\) sed "s/^X//" >cg.6 <<'END_OF_cg.6' X.. To view this file in a sensible manner, use "nroff -man cg.6 | more" X.. X.TH CG 6L "Sep 24, 1987" X.UC 4 X.SH NAME Xcg \- play the chess guess game X.SH SYNOPSIS X.B /usr/games/cg X[-n] X.SH DESCRIPTION X.I Cg Xplays the game of chess guess, which was described in one of Martin XGardener's famous articles on recreational mathematics. The game starts Xout with a standard 8 X 8 chess board with 5 pieces on it, Xa King, a Queen, a Bishop, a Knight, and a Rook. The pieces Xare all disguised. But it isn't really a guessing game. You may query Xsquares on the board for how may pieces attack that square. From this Xinformation you can deduce which pieces are which. The object of the Xgame is to minimize the number of squares queried in order to find out Xthe identity of all the pieces. X.PP XWhen the game starts up there is a help menu and a reminder on the right Xhand side of the screen, and the game board is to the left. To query Xa blank square for attacks, you move the to the square with the standard Xemacs(1?) or vi(1) cursor movement keys, and hit the space bar. The number Xof pieces that can attack that square will be displayed. To make a guess Xat what piece is at a certain square, you move to the square with the Xpiece on it, and type G (for guess) and they letter that represents Xthe piece you think it is: K for king, Q for queen, B for Bishop, N Xfor Knight, and R for Rook. If you are correct the piece will be displayed. XAn individual game will end when you have guessed all the pieces, or have Xquit. If you don't quit, and you finish the game, a list of statistics Xwill be displayed at the top of the screen. It is rumored that any Xlayout of the board can be successfully guessed with only two attack queries or Xone attack query and one missed guess. It is certainly possible to guess all Xthe pieces without making any attack queries, but it's probable that you Xwon't succeed. X.SH OPTIONS XThere is only one option: X.IP \-n XDisplay a black on black (or white on white, depending on how you view it) Xboard instead of the standard black/white arrangement. This can also Xbe selected from inside the program. X.SH AUTHOR XJon Foreman XCollege of Marin, in Kentfield, California. XPlausible net addresses are: ...!ucbvax!dual!unicom!physh, Xor ptsfa!unicom!physh or hplabs!well!unicom!physh or Xkiller!rrm!ssbn!physh X.SH "SEE ALSO" Xcurses(3X), X.I "Screen Updating and Cursor Movement Optimization:" X.IR "A Library Package" , X.SH BUGS XThere are X.I no Xbugs in X.I my Xcode, but there may be any number of undesirable features. X.SH PORTABILITY XOther than using curses(3X) for screen optimization, this code should Xbe easily portable to any machine running UNIX(r). There are no particularly Xmachine dependent things with the exception of "isupper()" and "islower()" Xwhich rely on [A-Z] and [a-z] being contiguous. X.SH PROBLEMS XThere are other ways of implementing this program, and I leave it to Xthe general body of students and others who wish to explore new and Xdifferent ideas to implement them. Here are some suggestions. Instead Xof displaying disguised pieces, don't display the pieces at all. This Xmakes the game harder. Another alternative would be to put all the Xnon pawn types of pieces on the board (1 King, 1 Queen, 2 Bishops (one on a Xwhile diagonal, and one on a black), 2 Knights, Xand 2 Rooks.) Still another would be to just display all the attacks, and Xto divine the location and types of all the pieces from just this information. XThe squares under the pieces should show the number of attacks on that piece. X.SH NOTES XThe code for this game has certain landmarks which people seem to Xpick out every time. For instance, the 'for' loops in the nitemove() Xfunction. In addition, I think that the program, while bigger, is Xa better sampler for the use of curses(3X) than either twinkle or Xlife, which are listed in the curses documents. At least the Xhelp() function does expand on the use of windows, which is not covered Xat all well in the curses documents that I have. In any case, I leave Xthis program in the custody of the public domain, so that all may Xbenefit. If you really enjoy it, send a thank you letter so that I Xmay know that some of my effort has been of use. END_OF_cg.6 if test 4200 -ne `wc -c <cg.6`; then echo shar: \"cg.6\" unpacked with wrong size! fi # end of overwriting check fi if test -f cg.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cg.c\" else echo shar: Extracting \"cg.c\" \(14136 characters\) sed "s/^X//" >cg.c <<'END_OF_cg.c' X#define VERSION 13 /* displays as X.X or so */ X/*************************************************************************\ X* The all new super dooper good nifty chess guess. * X* * X* This game is dedicated to Martin Gardener, who inspired it with * X* his wonderful articles on recreational mathematics. I hope someone * X* someday takes up where he left off. * X* * X* Notes: I can't concieve of a UNIX system where this won't compile * X* and run right out of the box, I'm really doing nothing particulary * X* bizzare. Well, thats not strictly true, you do need to have termcap * X* and curses. So for those that have, enjoy, those that don't, sorry. * X* * X* Modification History: * X* started: 9/4/84 * X* updated for the net: 4/7/86 * X* updated again for the net, 9/19/87 * X* updated 9/22/87 for bug fixes, and add version number * X* * X* The all important, super vicious copywrong message: * X* Copyright 1984,86 and 87 by Jon Foreman, all rights reserved * X* Permission is granted to distribute this code, or modify it, or use * X* portions in other programs, but you must give me credit in either the * X* program or documentation, and you must not remove the copyright from * X* the source text of this program. You may not sell this program or * X* source code for profit. * X* (This is really an leagally backed ego booster for me, really). * X* * X* It would be really enjoyable to have this become part of the Berkeley * X* or Bell unix distributions, hint, hint. * X* * X\*************************************************************************/ X X#include <curses.h> X#include <signal.h> X X#ifndef LINT Xchar *copyleft = "Copyright 1987 by Jon Foreman, all rights reserved."; X#endif X X#define T 1 /* TRUE */ X#define F 0 /* FALSE */ X Xstruct bd { X int b_attcnt; /* number of attacks on this cell */ X char b_pcetype; /* type piece type is on this cell */ X char b_shown; /* have we shown this cell yet? */ X} board[8][8]; X Xint kingmove(), queenmove(), rookmove(), bishmove(), nitemove(); X Xstruct pce { X char *p_name; X char p_type; X int (*p_attfun)(); X int p_x, p_y; X char p_guessed; X} piece[5] = { X {"King", 'K', kingmove, 0, 0, 0}, X {"Queen", 'Q', queenmove, 0, 0, 0}, /* queenmove is both bish & rook */ X {"Rook", 'R', rookmove, 0, 0, 0}, X {"Bishop", 'B', bishmove, 0, 0, 0}, X {"Knight", 'N', nitemove, 0, 0, 0} X}; X Xint bguess = 0, /* number of guessed pieces */ X tests = 0, /* number of attack tests */ X bw = 1; /* display black and white squares? */ X X/* X** If you haven't figured out what main is for yet, then you really X** will have a great deal of trouble figuring out what the rest of this X** code does. One note, though, single letter varibles are almost always X** loop indexes or other short term temporaries. X*/ Xmain (ac, av) Xchar **av; X{ X int endp(); X long time(); X int did = 0; /* have we seen the board yet? */ X X srandom (getpid () ^ (int) time (0L)); /* I bet this isn't portable */ X X/* X** Just have to find a way to get command line options in! X*/ X if (ac > 1 && av[1][0] == '-' && av[1][1] == 'n') X bw = 0; X X initscr (); X X (void) signal (SIGINT, endp); X (void) signal (SIGHUP, endp); X X nonl (); X noecho (); X crmode (); X leaveok (stdscr, FALSE); X scrollok (stdscr, FALSE); X X move (0, 0); X printw ("Chess guess, version %2d.%1d", VERSION/10, VERSION%10); X X for ( ; ; did = 1) { X initboard (); X dispboard (did, bw); X showpiece (); X userinterface (); X } X /* NOT REACHED */ X} X X/* X** Display the pieces on the gameboard X*/ Xshowpiece () X{ X int i; X X for (i = 0; i < 5; i++) { X move (piece[i].p_y*2+2, piece[i].p_x*4+3+2); X addch (piece[i].p_guessed ? piece[i].p_type : '*'); X refresh (); X } X return; X} X X/* X** Initialize the play board. First clear all the cells, then place the X** pieces, and then count attacks. Nothing to it. X*/ Xinitboard () X{ X int i, j; X X bguess = tests = 0; X X for (i = 0; i < 8; i++) X for (j = 0; j < 8; j++) X X board[i][j].b_pcetype = board[i][j].b_attcnt = board[i][j].b_shown = 0; X X X/* X** I suppose it is possible to get an infinite loop here, but there are X** after all 64 squares on the board, and I'm only using 5. I suspect X** that rnd() will eventually return 5 different pairs of x,y's. X*/ X for (i = 0; i < 5; i++) X for ( ;; ) X if (board[piece[i].p_x = rnd (8)][piece[i].p_y = rnd (8)].b_pcetype == 0) { X board[piece[i].p_x][piece[i].p_y].b_pcetype = piece[i].p_type; X break; X } X X for (i = 0; i < 5; i++) { X piece[i].p_guessed = 0; X piece[i].p_attfun (&piece[i]); X } X return; X} X X/* X** Come here whenever we want to stop playing, and unsetup all the stuff X** that got set up. X*/ Xendp () X{ X (void) signal (SIGINT, SIG_IGN); X (void) signal (SIGHUP, SIG_IGN); X mvcur (0, COLS-1, LINES-1, 0); /* cleveland */ X endwin (); X exit (0); X} X X/* X** Display the playfield, and stuff like that. X*/ Xdispboard (dispfix, bw) Xint dispfix; /* just fixing the display (=1) */ Xint bw; /* want black & white squares (-1) */ X{ X int i, j, phase; X X if (!dispfix) X mvaddstr (1, 40, "There are one each of these:"); X X for (phase = i = 0; i <= 8; i++) { X mvaddstr (i*2+1, 3, "+---+---+---+---+---+---+---+---+"); X if (i != 8) { X move (i*2+2, 0); X printw ("%2d", 8 - i); X move (i*2+2, 3); X X for (j = 0; j <= 8; j++, phase = !phase) { X addch ('|'); X if (j != 8) { X addch ((bw && phase) ? '.' : ' '); X if (board[j][i].b_shown) X addch (board[j][i].b_pcetype ? board[j][i].b_pcetype : (board[j][i].b_attcnt + '0')); X else if (board[j][i].b_pcetype != 0) X addch ('*'); X else X addch ((bw && phase) ? '.' : ' '); X addch ((bw && phase) ? '.' : ' '); X } X } X refresh (); X } X } X X if (dispfix) /* only fixing display board */ X return; X X mvaddstr (i*2, 5, "a b c d e f g h"); X refresh (); X for (i = 0; i < 5; i++) { X move (i+2, 40); X printw ("%c = %s\n", piece[i].p_type, piece[i].p_name); X refresh (); X } X mvaddstr ( 8, 40, "Commands:"); X mvaddstr ( 9, 40, "'Q' or <BREAK> is Quit"); X mvaddstr (10, 40, "'G' is Guess"); X mvaddstr (11, 40, "' ' is ask for attacks"); X mvaddstr (12, 40, "'h' or '^B' moves back"); X mvaddstr (13, 40, "'j' or '^N' moves down"); X mvaddstr (14, 40, "'k' or '^P' moves up"); X mvaddstr (15, 40, "'l' or '^F' moves forward"); X mvaddstr (16, 40, "'r' or '^L' redraws screen"); X mvaddstr (17, 40, "'t' to toggle black & white squares"); X mvaddstr (18, 40, "'?' to get help"); X refresh (); X} X X/* X** Kings can move one square in any direction. X*/ Xkingmove (p) Xstruct pce *p; X{ X int i, j; X X for (i = -1; i <= 1; i++) X for (j = -1; j <= 1; j++) { X if (!onboard (p->p_x + i, p->p_y + j) || (!i && !j)) X continue; X board[p->p_x + i][p->p_y + j].b_attcnt ++ ; X } X return; X} X X/* X** Knights can move over things, so just check to see if there is X** anything at where we end up. Problem: figure out exactly what X** the for(;;) loops do. X*/ Xnitemove (p) Xstruct pce *p; X{ X int i, j; X X for (i = -2; i <= 2; i += (!++i) ? 1 : 0) X for (j = 2; j >= -2; j += (!--j) ? -1 : 0) { X if (abs (j) == abs (i)) X continue; X if (!onboard (p->p_x + i, p->p_y + j)) X continue; X board[p->p_x + i][p->p_y + j].b_attcnt ++ ; X } X return; X} X X/* X** Rooks can only move horizontally or vertically, and cannot move through X** other pieces to get there X*/ Xrookmove (p) Xstruct pce *p; X{ X /* X ** radiate outward in the correct directions until we hit X ** something. Like the end of the board, or another piece. X */ X register int q; X X for (q = p->p_x - 1; onboard (q, p->p_y); --q) X board[q][p->p_y].b_attcnt++; X for (q = p->p_x + 1; onboard (q, p->p_y); ++q) X board[q][p->p_y].b_attcnt++; X for (q = p->p_y - 1; onboard (p->p_x, q); --q) X board[p->p_x][q].b_attcnt++; X for (q = p->p_y + 1; onboard (p->p_x, q); ++q) X board[p->p_x][q].b_attcnt++; X return; X} X X/* X** Bishops move diagonally X*/ Xbishmove (p) Xstruct pce *p; X{ X /* X ** radiate in the proper directions until you hit something. X */ X int i; X int done, a, b, c, d; X X for (a = b = c = d = T, done = 0, i = 1; !done; done = !(a|b|c|d), i++) { X if (a) X if (a = onboard (p->p_x + i, p->p_y + i)) X board[p->p_x + i][p->p_y + i].b_attcnt ++ ; X if (b) X if (b = onboard (p->p_x + i, p->p_y - i)) X board[p->p_x + i][p->p_y - i].b_attcnt ++ ; X if (c) X if (c = onboard (p->p_x - i, p->p_y + i)) X board[p->p_x - i][p->p_y + i].b_attcnt ++ ; X if (d) X if (d = onboard (p->p_x - i, p->p_y - i)) X board[p->p_x - i][p->p_y - i].b_attcnt ++ ; X } X return; X} X/* X** Queens are just rooks | bishops X*/ Xqueenmove (p) Xstruct pce *p; X{ X bishmove (p); X rookmove (p); X return; X} X X/* X** Make sure that we're still on the board someplace. X*/ Xonboard (x, y) Xregister int x, y; X{ X if (x >= 8 || y >= 8 || x < 0 || y < 0 || board[x][y].b_pcetype) X return (F); X return (T); X} X X/* X** Simplified integer random number generator, taylor for this application X*/ Xrnd (n) Xint n; X{ X long random(); X X return ((unsigned) random() % (unsigned) n); X} X X/* X** MacIntosh inspired keyboard interface..., no wait, that a lie. Actually, X** this one if fairly intuitional (what with the help on the screen and all) X** and I suppose if I had a Sun I could even implement mouse functions. X** But I don't, so I didn't. Just remember, all good programs have a X** well designed userinterface(). X*/ Xuserinterface () X{ X char c; X int x, y, ox, oy, gsd; X X x = y = gsd = 0; X move (y*2+2, x*4+3+2); X refresh (); X X for (;;) { X c = tolower (getch ()); X getyx (stdscr, oy, ox); X move (22, 0); X clrtoeol (); X move (oy, ox); X refresh (); X switch (c) { X case 'h': case '\002': X if (x > 0) X --x; X break; X X case 'j': case '\016': X if (y++ > 6) X --y; X break; X X case 'k': case '\020': X if (y > 0) X --y; X break; X X case 'l': case '\006': X if (x++ > 6) X --x; X break; X X case ' ': X if (board[x][y].b_shown) X break; X X if (board[x][y].b_pcetype == 0) { X printw ("%1d", board[x][y].b_attcnt); X board[x][y].b_shown = 1; X tests++; X } X break; X X case 'g': case 'G': X if (board[x][y].b_shown) X break; X X if (board[x][y].b_pcetype == 0) X break; X getyx (stdscr, oy, ox); X mvaddstr (22, 3, "Piece? "); X clrtoeol (stdscr); X refresh (); X echo (); X c = getch (); X refresh (); X move (oy, ox); X noecho (); X if (toupper (c) == board[x][y].b_pcetype) { X int q; X X addch (board[x][y].b_pcetype); X board[x][y].b_shown = 1; X refresh (); X for (q = gsd = 0; q < 5; q++) { X if (board[x][y].b_pcetype == piece[q].p_type) { X gsd++; X piece[q].p_guessed = 1; X } else if (piece[q].p_guessed) { X gsd++; X } X } X if (gsd == 5) { X win (); X return; X } X } else { X putchar ('\007'); X bguess++; X } X break; X X case 'q': X endp (); X X case 'r': case '\014': X wrefresh (curscr); X break; X X case 't': X dispboard (F, bw = !bw); X refresh (); X break; X X case '?': X help(); X break; X X default: /* reminder */ X break; X } X move (y*2+2, x*4+3+2); X refresh (); X } X} X X/* X** I have troubles finding toupper on every machine I use, so I wrote my X** own. I know, I know, "ctype.h" right. Wro. This is slower, but X** at least I know everyone will have it. X*/ Xtoupper (c) Xchar c; X{ X return ((c >= 'a' && c <= 'z') ? c -= '\040' : c); X} X X/* X** See comment for toupper (above). These routines also make more sense X** in that we don't have to find out if islower() or isupper is true X** or not first. X*/ Xtolower (c) Xchar c; X{ X return ((c >= 'A' && c <= 'Z') ? c += '\040' : c); X} X Xwin () X/* X** Colors, someone won one! Hurray!. X*/ X{ X char *buf[200]; X X sprintf (buf, "YOU WIN! statistics: %d tests, %d bad guesses\n", tests, bguess); X mvaddstr (0, 0, buf); X mvaddstr (22, 3, "Go again? "); X refresh (); X if (getch () == 'n') X endp (); X move (0, 0); X clrtoeol (); X move (22, 0); X clrtoeol (); X return; X} X X/* X** Generate a help screen, and if nothing else, this is a good X** example of how to create overlapping windows (like in rogue X** and so forth X*/ X#define HWXMAX 50 X#define HWYMAX 18 X Xhelp () X{ X WINDOW *hwin; X int curx, cury; X X getyx (stdscr, cury, curx); X hwin = newwin (HWYMAX, HWXMAX, 0, 0); X mybox (hwin, HWYMAX, HWXMAX); X X mvwaddstr (hwin,2,2," Chess guess is a game that was described in"); X mvwaddstr (hwin,3,2,"one of Martin Gardeners famous recreational"); X mvwaddstr (hwin,4,2,"mathematics articles for \"Scientific American\""); X mvwaddstr (hwin,5,2,"magazine."); X mvwaddstr (hwin,7,2," You are given a chess board with 5 pieces"); X mvwaddstr (hwin,8,2,"displayed. The pieces are disguised, and your"); X mvwaddstr (hwin,9,2,"mission (should you decide to accept it) is to"); X mvwaddstr (hwin,10,2,"guess which pieces are which. You can ask for"); X mvwaddstr (hwin,11,2,"help in the form of asking how many pieces can"); X mvwaddstr (hwin,12,2,"attack various squares on the board. The"); X mvwaddstr (hwin,13,2,"challenge is to pick squares that maximize"); X mvwaddstr (hwin,14,2,"your chance of guessing the correct pieces."); X mvwaddstr (hwin,16,2," (when done reading, press space) "); X wrefresh (hwin); X getch (); X X delwin (hwin); X move (cury, curx); X touchwin (stdscr); X refresh (); X return; X} X X/* X** This is my box routine, here because the standard box() didn't really X** do what I wanted. Note, it clear the window as it goes along. X*/ Xmybox (hwin, ymax, xmax) XWINDOW *hwin; X{ X int y, x; X X for (y = 0; y < ymax; y++) { X for (x = 0; x < xmax; x++) X if (x == 0 && y == 0) X mvwaddch (hwin, y, x, '/'); X else if (x == 0 && y == ymax-1) X mvwaddch (hwin, y, x, '\\'); X else if (x == xmax-1 && y == 0) X mvwaddch (hwin, y, x, '\\'); X else if (x == xmax-1 && y == ymax-1) X mvwaddch (hwin, y, x, '/'); X else if (x > xmax-1 || y > ymax-1) X mvwaddch (hwin, y, x, ' '); X else if (y == 0) X mvwaddch (hwin, y, x, '='); X else if (y == ymax-1) X mvwaddch (hwin, y, x, '-'); X else if (x == 0 || x == xmax-1) X mvwaddch (hwin, y, x, '|'); X } X wmove (hwin, 0, 2); X waddstr (hwin, " * Help * "); X return; X} END_OF_cg.c if test 14136 -ne `wc -c <cg.c`; then echo shar: \"cg.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0