DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦0387ee30f⟧ TextFile

    Length: 25282 (0x62c2)
    Types: TextFile
    Names: »main.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Cchess/main.c« 

TextFile

/*	C O R R E S P O N D E N C E   C H E S S			version 1.00
 *
 *	Play chess with another player, with notification of moves by mail.
 *
 *	(C) Copyright - Dec 1987 - Jan Dithmar Wolter.
 *	
 *	This source code may be freely used, but not for purposes of profit
 *	without the permission of the author.  This copyright notice should
 *	not be removed.
 *
 *	I would be very interested in hearing about suggestions, bug reports,
 *	and porting problems with cchess.  I can be mailed on usenet at
 *	janc@crim.eecs.umich.edu.  Better yet, dial into M-Net at
 *	(313)994-6333, give yourself an account and join the "ugames"
 *	conference.  This is a free public bbs and cchess's development site.
 *
 *	Any programmer who wishes to make improvements should be warned that
 *	this is a sadly unmodular program.  There are tons of global variables
 *	and subroutines have curious side-effects.  The arrays containing the
 *	board (b and bc) and the input buffers (mbuffer and sbuffer) are
 *	particularly strange this way, being used for just about everything.
 *	Sorry.  That's what happens when what was originally supposed to be a
 *	"quicky" project grows for five years.
 *
 *	version 0.10:
 *		First pre-release version.
 *	version 0.11:
 *		Added Unix 4.2bsd support.
 *		Rationalized version dependent signal handlers as much as
 *		  possible with three different signal handling libraries.
 *		Added Computer Kibitzing option to help make up for poor
 *		  graphics.
 *	version 0.12:
 *		Save illegal moves in kriegspeil games.
 *		Added Big Board option on Ron Theriault's suggestion.
 *		Solidified Forfiet/Draw code.  (Finally).
 *		Touched up transcripts.
 *		Added help command.
 *	version 0.13:
 *		Added support for 22 column terminals (Commodores).
 *		Pawn promotion noted on transcripts.
 *		Redraw and Version work at "Not your move prompt"
 *		Solidified Challenge/Accept code.  (Finally).
 *	version 0.14:
 *		Cosmetic changes to Exit command.
 *		Fix system() calls to protect them from dirty tricks.
 *		Let Kriegspielers replay the game after it is over.
 *		Improve castling code so it will work for halfboard games.
 *		Kriegspiel only counts some kinds of illegal moves.
 *		Time stamp added to each line of game file.
 *		Version and Redraw commands work at accept draw prompt.
 *		Replay renamed Playback, and dodraw() integrated with domove().
 *		White pieces displayed with highlighting on the big board.
 *		Divided sys.c file into sys.c and scrn.c.
 *		Fixed a bug that caused moves to get lost during playbacks.
 *	version 0.15:
 *		Fixed a pawn promotion bug that appeared in 0.14.
 *		Added Shatranj and Courier game variations.
 *		Added Karma, Rifle & Kamikazi Chess capture variations.
 *		Version 6 style ioctl() calls now understood by sys.c
 *	version 0.16
 *		Repeated position detection code kludged in.
 *		Fifty move rule enforcement installed.
 *		Game cancellation command added.
 *		Minor bug fixes to Karma chess, Kriegspiel and Scoreboard.
 *	version 0.17
 *		Big changes in the way options are represented internally
 *		   and in game files and in score file.
 *		Addition of Maharajah piece.
 *		Multiple moves for variant games.
 *		Steamroller, Double Chess and Progressive variants added.
 *		Initial board set-up specified in transcript file.
 *		O command to display current game options added.
 *		mprint() for "--More--" on Help and Options.
 *		Board editor for custom chess boards.
 *		Further generalization of castling code.
 *		No spaces allowed in transcript file names.
 *		Bug fixes to mate detection.
 *		Redraw works at "Are you sure" and "Move:" prompts.
 *		Use user defined backspace character from stty calls.
 *		Mailer is run in background.
 *		Clarification of format of comments under board.
 *	version 0.18
 *		May name a user with -g option.
 *		Speedup of -g option with lookaside buffer for passwd lookups.
 *		Auto-redraw after suspend (sort of) made to work.
 *		Addition of French and German piece names.
 *		Various small bug fixes for system V.
 *		Added -a option to move in all possible games.
 *		Fixed printing of cancellation requests in transcripts.
 *		Illegal moves optionally printed in kriegspiel transcripts.
 *		Enter kibitz mode only if you are neither of the players.
 *		Changes to allow no king, or some other mateable piece.
 *		Fixes to the computer kibitzer (rooks don't cover themselves).
 *		Bug Fixes to playback of multimove games.
 *		Broke cmd.c file into cmd.c and init.c.
 *		Added Last command to display date of last move.
 *		Redesign of challenge and accept subsystems.
 *		Maharajah and Losing chess variant games added.
 *		Many fixes to mate detection.
 *		Tab'iyat option for sped up openings.
 *	version 0.19
 *		Turned off nl to crnl mapping and fixed stuff to work that way.
 *		Rewrote directory reading to use clone of 4.2bsd readdir().
 *		Fix things so display isn't confused by R lines in gamefile.
 *		Close files when -a option is used.
 *		Fix queen moves in mate detection.
 *		Simplification of compile time definitions.
 *		Rewrite to simplify cctrans() routine.
 *		Innumerable minor fixes and clean up work all over.
 *		Conversion Chess added with thanks to Kenneth Larimer.
 *		Version numbers added to game files.
 *		Crude support of 4.3bsd windowing interupt.
 *	version 1.00
 *		Cleaned up for posting to USENET.
 */

#include "cchess.h"

/* String identifying current version */
char *version = "0.19";
char *copyright = "(c) 1987 Jan Wolter";

/* Characters and Names for pieces (some foreign name sets are incomplete) */

char pc[] = "HJDEMIRNBQK kqbnrimedjh";
char *chessname[HI_NAMES+1][PIECES+1] = {
      { "Empty Square",	"King",		"Queen",	"Bishop",
	"Knight",	"Rook",		"Pawn",		"Minister",
	"Elephant",	"Duke",		"Jester",	"Maharajah"},

      { "Empty Square",	"Shah",		"Queen",	"Bishop",
	"Faras",	"Rukh",		"Baidaq",	"Firz",
	"Fil",		"Duke",		"Jester",	"Maharajah"},

      { "Empty Square",	"Roi",		"Dame",		"Fou",
	"Cavaler",	"Tour",		"Pion",		"Ministre",
	"Elephant",	"Duc",		"Jester",	"Maharajah"},

      { "Empty Square",	"Konig",	"Dame",		"Laufer",
	"Springer",	"Turm",		"Bauer",	"Minister",
	"Elefant",	"Herzog",	"Jester",	"Maharajah"} };
char **piecename;

short wfr,wfc,wtr,wtc;	/* last white move - used for en paussant legality */
short bfr,bfc,btr,btc;	/* last black move - used for en paussant legality */
schar promote = 0;	/* Character to promote pawn to - 0 if no promotion */

/* Have the Kings or the Rooks been moved? */
boolean wcck = TRUE;	/* White can castle king-side  */
boolean wccq = TRUE;	/* White can castle queen-side */
boolean bcck = TRUE;	/* Black can castle king-side  */
boolean bccq = TRUE;	/* Black can castle queen-side */

/* Initial board layout */
				         /* Last four columns */
schar ib[R_SIZE][C_SIZE] = {	         /* for Courier only. */
	WR, WN, WB, WQ, WK, WB, WN, WR,     WB, WE, WN, WR,
	WP, WP, WP, WP, WP, WP, WP, WP,     WP, WP, WP, WP,
	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
	BP, BP, BP, BP, BP, BP, BP, BP,     BP, BP, BP, BP,
	BR, BN, BB, BQ, BK, BB, BN, BR,     BB, BE, BN, BR,
	};

schar bc[R_SIZE][C_SIZE]; /* Copy of the board, so moves can be taken back */
schar b[R_SIZE][C_SIZE];  /* Main board */
int errcode;			/* Move error code */

int hisuid;			/* Opponent user id number */
int myuid;			/* Player user id number */
char hisid[20];			/* Opponent login name */
char myid[20];			/* Player login name */
#ifdef COMPAT018
char file_version[6] = "0.18";	/* Version of cchess that produced game file */
				/* If no version line, assume 0.18 */
#else
char file_version[6] = "";	/* Version of cchess that produced game file */
#endif COMPAT018

int movecnt;			/* Number of moves made so far in game */
int playcnt;			/* Number of moves including proposals */
int mvssize;			/* Number of moves on the move stack */
int tamemoves;			/* Number of tame moves made */
int consmoves;			/* Number of consecutive moves allowed */
int consmade;			/* Number of consecutive moves made */

char fname[50];		/* Name of the gameboardfile */
FILE *rfp;		/* File pointer for reading from boardfile */
FILE *wfp;		/* File pointer for writing to boardfile */

/* Game status code:
 *    0 -> No challenge made.
 *    1 -> Challenge has been sent.
 *    2 -> (not used)
 *    3 -> Ready to move.
 *    4 -> A draw has been proposed.
 *    5 -> A draw has been accepted.
 *    6 -> Player has forfeited.
 *    7 -> cancellation has been proposed.
 *    8 -> cancellation has been accepted.
 */

char status;

/* General Purpose Global Flags */

boolean newgame;		/* Are we starting a new game file? */
boolean moveok = TRUE;		/* Allow player to move? */
boolean solo;			/* Is he playing himself? */
boolean kibitz = FALSE;		/* Is this a kibitzing session? */
boolean bigboard = FALSE;	/* Display board in large format? */
boolean hidden = FALSE;		/* Should enemy moves be shown? */
boolean incheck = FALSE;	/* Is player in check (or mate)? */
boolean inmate = FALSE;		/* Is plater (check or stale) mated */
boolean repeated = FALSE;	/* Is this a thrice repeated position? */
boolean stripped = FALSE;	/* Have we just stripped the other player? */
boolean istame;			/* Was the last move a tame one? */
boolean interupt;		/* OK to interupt out of program? */
boolean eachgame = FALSE;	/* Play each playable game? */
boolean must_take = FALSE;	/* Allow only moves which capture? */

schar toplay=WHITE;		/* color to play next */
schar order;			/* -1 if other player named first, else 1 */
schar mycolor;			/* What color am I? */
schar taken;			/* Piece taken in last move.  SQ for none. */
long lastday;			/* Day number on which last move was made. */
boolean erases=TRUE;		/* Can terminal erase properly? */
boolean issmart=FALSE;		/* Can address cursor and erase? */
boolean cleardown=FALSE;	/* Can clear screen below cursor and smart? */
boolean commodore=FALSE;	/* Do we have a 22 column terminal? */
boolean scrolled=FALSE;		/* Has the screen scrolled? */
int illmoves;			/* Count of illegal Kriegspiel moves */
int myillmoves;			/* Count of my illegal Kriegspiel moves */
short cx,cy;			/* Current Cursor position (used by TERMCAP) */
short msgarea = 0;		/* Line below screen where prompts begin */
int LINES = 0;			/* Number of lines per screen */
int COLS = 40;			/* Number of columns per screen */
char bs_char = '\b';		/* User definable backspace character */
#ifdef DEBUG
boolean debugon = FALSE;	/* Debugging flag */
#endif DEBUG

/* Names of standard variant games */
char *typename[HI_GAME+1] = {
	"Mixed", "Chess", "Kriegspiel", "Shatranj", "Courier",
	"Halfboard Chess", "Karma Chess", "Rifle Chess", "Kamikazi Chess",
	"Double Chess", "Steamroller", "Progressive Chess", "Maharajah",
	"Losing Chess", "Conversion Chess"};

char *langname[HI_NAMES+1] = { "English","Persian","French","German"};

/* Names of game results */
char *resltname[4] = {"Draw","Win","Lose","Continue"};

/* Names of Capture rules */
char *captname[HI_CAPTURE+1] =
	{"Standard","No","Rifle","Conversion","Karma","Kamikazi"};

/* Current game options */
char option[OPTIONS];

/* Maximum legal values for the options */
char maxopt[OPTIONS] =
      { HI_COLOR,     HI_PRIVATE,   HI_KIBITZ,    HI_GAME,
        HI_ROWS,      HI_COLS,      HI_BOARD,     HI_NAMES,
        HI_VISIB,     HI_CASTLE,    HI_DPAWN,     HI_STRIP,
        HI_STALE,     HI_CAPTURE,   HI_KCAPTURE,  HI_PROMOTE,
	HI_WIMOVES,   HI_BIMOVES,   HI_WMOVES,    HI_BMOVES,
	HI_THRUCHECK, HI_WHITEKING, HI_BLACKKING, HI_MUSTTAKE,
	HI_TABIYAT };

/* Variant game default options */
char defopt[HI_GAME+1][OPTIONS] =
    {
    			/* Customized game */
      { FALSE,       FALSE,        TRUE,         TY_MIXED,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Standard Chess */
      { FALSE,       FALSE,        TRUE,         TY_CHESS,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Kriegspiel */
      { FALSE,       FALSE,        TRUE,         TY_KRIEGSPIEL,
	7,           7,            FALSE,        0,
	TRUE,        FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Shatranj */
      { FALSE,       FALSE,        TRUE,         TY_SHATRANJ,
	7,           7,            TRUE,         1,
	FALSE,       TRUE,         TRUE,         RE_LOSE,
	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_MINISTER,
	10,	     10,	   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	TRUE },

			/* Courier */
      { FALSE,       FALSE,        TRUE,         TY_COURIER,
	7,           11,           TRUE,         0,
	FALSE,       TRUE,         TRUE,         RE_LOSE,
	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_MINISTER,
	12,	     12,	   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	TRUE },

			/* Halfboard */
      { FALSE,       FALSE,        TRUE,         TY_HALFBOARD,
	7,           3,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Karma Chess */
      { FALSE,       FALSE,        TRUE,         TY_KARMA,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_KARMA,     CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Rifle Chess */
      { FALSE,       FALSE,        TRUE,         TY_RIFLE,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_RIFLE,     CA_RIFLE,     PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Kamikazi Chess */
      { FALSE,       FALSE,        TRUE,         TY_KAMIKAZI,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_KAMIKAZI,  CA_NONE,      PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE },

			/* Double Move Chess */
      { FALSE,       FALSE,        TRUE,         TY_DOUBLE,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	2,	     2,		   2,		 2,
	TRUE,        WK,           WK,		 FALSE,
	FALSE },

			/* Steamroller */
      { FALSE,       FALSE,        TRUE,         TY_STEAMROLLER,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	2,	     1,		   2,		 1,
	TRUE,        WK,           WK,		 FALSE,
	FALSE },

			/* Progressive Chess */
      { FALSE,       FALSE,        TRUE,         TY_PROGRESSIVE,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_LOSE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     MO_PROGRESS,  MO_PROGRESS,  MO_PROGRESS,
	FALSE,       SQ,           SQ,		 FALSE,
	FALSE },

			/* Maharajah */
      { FALSE,       FALSE,        TRUE,         TY_MAHARAJAH,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WH,           WK,		 FALSE,
	FALSE },

			/* Losing Chess */
      { FALSE,       FALSE,        FALSE,        TY_LOSING,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_WIN,
	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       SQ,           SQ,		 FALSE,
	FALSE },

			/* Conversion Chess */
      { FALSE,       FALSE,        TRUE,         TY_CONVERSION,
	7,           7,            FALSE,        0,
	FALSE,       FALSE,        FALSE,        RE_NONE,
	RE_DRAW,     CA_CONVERSION,CA_CONVERSION,PR_QRBN,
	1,	     1,		   1,		 1,
	FALSE,       WK,           WK,		 FALSE,
	FALSE } };

char cbuffer[CB_LEN+1];		/* Comment Buffer */
char mb1[MB_LEN+1];		/* Move Buffer One. */
char mb2[MB_LEN+1];		/* Move Buffer Two. */
char *mbuffer=mb1;		/* Pointer to current move buffer */
char *sbuffer=mb2;		/* Pointer to spare move buffer */
jmp_buf jmpenv;			/* Long jump buffer */

/* Some really weird things used to sort of recover from suspends: */
/* susp1_flg is set if susp_env contains a place to jump to after */
/* we've been suspended.  susp2_flg is turned on if we got suspended */
/* while there was no susp_env defined */
#ifndef LSIGNAL
jmp_buf susp_env;
boolean susp1_flg = FALSE, susp2_flg = FALSE;
#endif LSIGNAL

/* String of spaces used when arbitary strings of spaces are needed */
char blankstr[BLANK_LEN+1]	/* Must be exactly BLANK_LEN spaces */
    = "                                                                      ";


char transcript = FALSE;	/* Should we just print the transcript? */

int realuid;
boolean activeonly = FALSE;

main(argc,argv)
int argc;
char *argv[];
{
struct passwd *pwd;		/* Password file entry */
register int players,i,j;

	/* check legality of arguments */
	players = 0;
	for (i=1;i<argc;i++)
	    if (argv[i][0] == '-') 
		for (j = 1; argv[i][j]; j++)
		    switch (argv[i][j])
		    {
		    case 'a':
		        eachgame = TRUE;
		        break;

		    case 's':
			scoreboard();
			exit(0);

		    case 'b':
			bigboard = TRUE;
			break;

		    case 'g':
			if (++i < argc)
			{
			    if ((pwd = getpwnam(argv[i])) == 0)
			    {
				printf("No user %s on this system\n",argv[i]);
				exit(1);
			    }
			    printf("%s's games in progress\n-----------------------------\n",
				    argv[i]);
			    list(pwd->pw_uid);
			}
			else
			{
			    printf("Games in progress\n-----------------\n");
			    list(-1);
			}
			exit(0);

		    case 't':
			transcript = TRUE;
			break;
#ifdef DEBUG
		    case 'd':
			debugon = TRUE;
			break;
#endif DEBUG
		    default:
			printf("Illegal %s option: -%c\n",argv[0],argv[i][j]);
			usage(argv[0]);
		    }
	    else
		if (++players == 1)
		    strcpy(hisid,argv[i]);
		else if (players == 2)
			strcpy(myid,argv[i]);
		    else
		    {
			printf("Too many options for %s\n",argv[0]);
			usage(argv[0]);
		    }

	/* Look up the two players */

	realuid = getuid();

	if (players >= 1)
	{
		/* does opponent exist? */
		if ((pwd = getpwnam(hisid)) == 0)
		{
			printf("No user %s on this system\n",hisid);
			exit(1);
		}
		hisuid = pwd->pw_uid;
	}
	if (players == 2)
	{
		/* does second name exist? */
		if ((pwd = getpwnam(myid)) == 0)
		{
			printf("No user %s on this system\n",myid);
			exit(1);
		}
		myuid = pwd->pw_uid;

		/* If one of the named players is me, ignore it */
#ifdef DEBUG
		if (!eachgame && !debugon)
#else
		if (!eachgame)
#endif DEBUG
		{
			if (myuid == realuid)
				players = 1;
			else if (hisuid == realuid)
			{
				players = 1;
				/* Swap names */
				strcpy(myid,hisid);
				strcpy(hisid,pwd->pw_name);
				hisuid = myuid;
				myuid = realuid;
			}
		}
	}
	else if (players == 1)
	{
		/* Get my name */
		if ((pwd = getpwuid(realuid)) == 0)
		{
			printf("Panic:  Can't get your password entry\n");
			exit(1);
		}
		strcpy(myid,pwd->pw_name);
		myuid = realuid;
	}

	/* If -a flag and less than two names, do all matching games */
	if (eachgame)
	{
		if (players < 2)
		{
			activeonly = (players == 0);
			scangames();			/* Doesn't return */
		}
		else
			eachgame = FALSE;
	}

	/* If no -a flag, must have at least one player name */
	if (players == 0)
	{
		printf("Must specify name of opponent.\n");
		usage(argv[0]);
	}

	/* Are we kibitzing? */
	if (players == 2) kibitz = TRUE;

#ifdef DEBUG
	if (debugon)
	{
		if (players == 2)
			kibitz = FALSE;
		else
		{
			printf("Debug option requires two names.\n");
			exit(1);
		}
	}
#endif DEBUG

	/* Get termcap, set cbreak, noecho, trap interupts */
	initterm();

	run();
	exit(-1);
}


/* myid, myuid, hisid and hisuid must be set before calling this */
/* this never returns.  It always calls done() instead.          */

run()
{
	/* Initialize various globals */
	wcck = wccq = bcck = bccq = TRUE;
	interupt = TRUE;
	errcode = E_OK;
	status = 0;
	taken = SQ;

	/* As he playing himself? */
	solo = (hisuid == myuid);

	/* See if the Move File Exists */
	order = -1;
	sprintf(fname,"%s/%d.%d",CCDIR,hisuid,myuid);
	
	if ((rfp=fopen(fname,"r"))==NULL)
	{
		order = 1;
		sprintf(fname,"%s/%d.%d",CCDIR,myuid,hisuid);

		if ((rfp=fopen(fname,"r"))==NULL)
		{
			clr();
			wprintf("No game in progress between %s and %s\n",
				myid,hisid);
			if (eachgame || kibitz || transcript) done(0);
		        wprintf("Would you like to challenge %s (Y/N)? ",
				hisid);
			if (enterdyn(TRUE))
			{
				newgame = TRUE;
				status = 0;
				dochallenge(FALSE);
			}
			done(0);
		}
	}
	
	/* Open the Game file to write */

	if ((wfp=fopen(fname,"a"))==NULL)
	{
		wprintf("Cchess error:  Unable to write to gamefile %s\n",
			fname);
		done(1);
	}

	/* Just print a transcript, if that option was selected */
	if (transcript)
	{
		if (eachgame)
		{
			if (activeonly)
			    wprintf("Transcript of game against %s? ",hisid);
			else
			    wprintf("Transcript of game between %s and %s? ",
					myid,hisid);
			if (!enterdyn(FALSE)) done(0);
		}
		trans(TRUE);
		done(0);
	}

	newgame = FALSE;

	/* read in the game to date */
	ldboard();

	if (solo) mycolor = toplay;
	if (mycolor != toplay)
		moveok = FALSE;
	else
		moveok = !kibitz;
	if (eachgame)
	{
		if (activeonly)
		{
			if (mycolor == toplay)
			{
				wprintf("Move against %s? ",hisid);
				if (!enterdyn(FALSE)) done(0);
			}
			else
				done(0);
		}
		else
		{
			wprintf("Game between %s and %s? ",myid,hisid);
			if (!enterdyn(FALSE)) done(0);
		}
	}

	switch (status)
	{
	case 0: /* no challenge made */
		wprintf("Cchess Error: No Challenge after load.\n");
		done(1);
	
	case 1: /* challenge made */
		doaccept();
		/* if white accepted, let him move */
		if (status != 3 || (mycolor != WHITE && !solo)) break;
		toplay = WHITE;
		if (Winitmoves == MO_PROGRESS)
			consmoves = 1;
		else
			consmoves = Winitmoves;
	
	case 3: /* make move */
		if (stripped)
			domate(Stripresult,EV_FORCES);
		else if (inmate)
		{
			if (incheck)
				domate(RE_LOSE,EV_CHECKMATE);
			else
				domate(Staleresult,EV_STALEMATE);
		}
		else if (repeated)
			domate(RE_DRAW,EV_REPEATED);
		else
			domove(RE_NONE);  /* Make a move */
		break;
	
	case 4: /* draw proposal made */
		if (tamemoves >= MAXTAME)
			domate(RE_DRAW,EV_FIFTYMOVES);   /* Draw is final */
		else
			domove(RE_DRAW);	    /* Answer a draw proposal */
		break;
		
	case 5: /* other player accepted draw */
		domate(RE_DRAW,EV_AGREEMENT);
		break;

	case 6: /* other player forfeited */

		domate(RE_WIN,EV_FORFIET);
		break;

	case 7: /* cancellation proposal made */
		domove(RE_CANCEL);	    /* Answer a cancellation proposal */
		break;

	case 8: /* other player accepted cancellation */
		domate(RE_CANCEL,EV_AGREEMENT);
		break;

	default:
		wprintf("Cchess Error:  Weird status %d\n",status);
		done(1);
	}

	done(0);
}



/*   SCANGAMES()
 *
 *   If activeonly is set, list all games the user can move in.  If activeonly
 *   is not set, list all games that hisuid is in.  For each one, prompt if
 *   he wants to move in it.  Run the program if he does.  Visual mode
 *   not used here.
 */
   
scangames()
{
register struct direct *gfd;
register char *pwname;
register int n;
int uid1,uid2;
DIR *fp;

	if ((fp = opendir(CCDIR))== 0)
	{
		printf("Panic: unable to read %s directory\n",CCDIR);
		exit(1);
	}
	n = 0;
	igpwuid();

	/* Get name and uid to search for */
	if (activeonly)
	{
		if ((pwname = gpwuid(myuid = realuid)) == 0)
		{
			printf("Panic:  Can't get your password entry\n");
			exit(1);
		}
		strcpy(myid,pwname);
	}
	else
	{
		strcpy(myid,hisid);
		myuid = hisuid;
		kibitz = TRUE;
	}

	while ((gfd = readdir(fp)) != NULL)
		if (gfd->d_name[0] != '.' && sscanf(gfd->d_name,"%d.%d",&uid1,&uid2)==2)
		{
			/* Does this game involve me? */
			if (uid1 == myuid)
				hisuid = uid2;
			else if (uid2 == myuid)
				hisuid = uid1;
			else
				continue;

			/* Look up the other person's id */
			if ((pwname=gpwuid(hisuid)) == 0)
				continue;
			strcpy(hisid,pwname);

			if (n == 0)
			{
				initterm();
				clr();
			}

			/* Play the game */
			if (!setjmp(jmpenv))
				run();
			n++;
		}
	endpwent();  /* close the password file */
	if (n == 0)
		printf("No games\n");

	/* Turn off eachgame flag so done() will really exit us */
	eachgame = FALSE;
	closedir(fp);
	done(0);
}



/* USAGE
 * 
 *  Print a rather long winded usage message.  This doesn't return.
 */

usage(name)
char *name;
{
	printf("To play:          %s [-a] [-b] opponent\n",name);
	printf("To peek:          %s [-b] player player\n",name);
	printf("For transcript:   %s [-a] -t player [player]\n",name);
	printf("For scoreboard:   %s -s\n",name);
	printf("For game list:    %s -g [player]\n",name);
	exit(1);
}