[comp.sources.games] v03i088: cchess - corrispondence chess, Part03/05

games-request@tekred.TEK.COM (03/02/88)

Submitted by: Jan Wolter <janc@crim.eecs.umich.edu>
Comp.sources.games: Volume 3, Issue 88
Archive-name: cchess/Part03

#! /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 archive 3 (of 5)."
# Contents:  cchess.h init.c main.c
# Wrapped by billr@tekred on Tue Jan 12 12:09:54 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f cchess.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cchess.h\"
else
echo shar: Extracting \"cchess.h\" \(2560 characters\)
sed "s/^X//" >cchess.h <<'END_OF_cchess.h'
X/*	C O R R E S P O N D E N C E   C H E S S			Version 1.00
X *
X *	Play chess with another player, with notification of moves by mail.
X *
X *	(C) Apr 1986 - Jan Dithmar Wolter.
X *
X *	This source code may be freely distributed and modified, but not
X *	sold or used for profit without the permission of the author.
X */
X
X#include <stdio.h>
X#include <setjmp.h>
X#include <signal.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X
X#include "def.h"
X
X/* External declarations of all globals */
Xextern boolean newgame,moveok,kibitz,solo,hidden,eachgame;
Xextern boolean commodore,incheck,inmate,repeated,stripped,interupt,bigboard;
Xextern boolean istame,must_take;
Xextern int myillmoves, illmoves, tamemoves, mvssize;
Xextern short cx,cy;
Xextern short msgarea;
Xextern short wfr,wfc,wtr,wtc,bfr,bfc,btr,btc;
Xextern schar promote;
Xextern schar ib[R_SIZE][C_SIZE],b[R_SIZE][C_SIZE],bc[R_SIZE][C_SIZE];
Xextern schar order,mycolor,toplay,taken;
Xextern boolean wcck, wccq, bcck, bccq;
Xextern int movecnt,playcnt;
Xextern int hisuid,myuid;
Xextern int consmade,consmoves;
Xextern char status;
Xextern char *version, *copyright,file_version[];
Xextern char *resltname[], *captname[HI_CAPTURE+1],*typename[],*langname[];
Xextern char **piecename,*chessname[HI_NAMES+1][PIECES+1],pc[2*PIECES+2];
Xextern char hisid[20],myid[20];
Xextern char cbuffer[CB_LEN+1],*mbuffer,*sbuffer;
Xextern char mb1[MB_LEN+1],mb2[MB_LEN+1];
Xextern char blankstr[BLANK_LEN+1];
Xextern char option[OPTIONS],maxopt[OPTIONS];
Xextern char defopt[HI_GAME+1][OPTIONS];
Xextern int errcode;
Xextern char bs_char;
Xextern char fname[50];
Xextern long lastday;
Xextern FILE *rfp;
Xextern FILE *wfp;
Xextern jmp_buf jmpenv;
Xextern boolean issmart,erases,cleardown,scrolled;
Xextern int LINES, COLS;
X
X#ifndef LSIGNAL
Xextern jmp_buf susp_env;
Xextern boolean susp1_flg, susp2_flg;
X#endif LSIGNAL
X
X#ifdef DEBUG
Xextern boolean debugon;
X#endif
X
X/* Declarations of routines */
Xextern struct passwd *getpwnam(), *getpwuid(), *getpwent();
Xextern char enter(), enterd(), xenter(), xenterd(), *getenv(), *fgetl();
Xextern boolean check(), legal(), cart(), diag(), canmove(), place(),forces();
Xextern boolean isrepeat(), compare(),checkbd(), enterdyn(), enteryn();
Xextern boolean editbd();
Xextern char *index(), *strcpy(), *strcat(), *malloc(), *gpwuid();
Xextern char *pcol(), *pcapcol(), *pman(), *pcolman(), *yorn(), *cday();
Xextern char *sprintf(), *strncpy();
Xextern schar compkib();
Xextern long day(), atol();
Xextern int mprintf();
Xextern FILE *upopen();
Xextern int fseek();
X
Xextern struct direct *readdir();
END_OF_cchess.h
if test 2560 -ne `wc -c <cchess.h`; then
    echo shar: \"cchess.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f init.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"init.c\"
else
echo shar: Extracting \"init.c\" \(22583 characters\)
sed "s/^X//" >init.c <<'END_OF_init.c'
X/* CCHESS CHALLENGE ROUTINES					version 1.00
X *
X *    (C) Copyright - Jan D. Wolter - Apr 1986
X *
X *    Mostly routines to make and accept game challenges.
X */
X
X#include "cchess.h"
X
X#ifndef NOTERMCAP
Xextern char *DL;
X#endif NOTERMCAP
X
X/* CHALLENGE()
X *
X *   Make a challenge.  User is prompted for options.  Challenge line is
X *   written in the game file.  The flag counter is set if this is a
X *   counter challenge to a previous challenge.
X */
X
Xdochallenge(counter)
Xboolean counter;
X{
Xregister int i;
Xchar ch,var;
X	
X    /* Choose colors */
X
X    wprint("\nWhat color would you like ");
X    if (counter)
X    {
X	wprintf("[%s]? ",pcol(mycolor));
X	ch = enterd("WB",(mycolor==WHITE)?'W':'B');
X    }
X    else
X    {
X	wprint("(B/W)? ");
X	ch = enter("WB");
X    }
X    if (ch == 'W')
X    {
X	wprint("hite");
X	mycolor = WHITE;
X    }
X    else
X    {
X	wprint("lack");
X	mycolor = BLACK;
X    }
X    if (order == (schar) -1)
X	Firstwhite = (ch == 'B');
X    else
X	Firstwhite = (ch == 'W');
X
X    wprint("\nDo you wish to play a variant game ");
X    if (counter)
X    {
X	ch = (Game_type != TY_CHESS);
X	wprintf("[%s]? ",yorn(ch));
X	ch = enterdyn(ch);
X    }
X    else
X    {
X	wprint("(Y/N)? ");
X	ch = enteryn();
X    }
X
X    if (ch)
X    {
X	wprint("\nVariants games are:\n");
X	wprint("  (A) Chess            - Standard modern game\n");
X	wprint("  (B) Kriegspiel       - Other player's moves hidden\n");
X	wprint("  (C) Shatranj         - 6th century Persian game\n");
X	wprint("  (D) Courier          - 13th century 12x8 board game\n");
X	wprint("  (E) Halfboard        - Standard game on 4x8 board\n");
X	wprint("  (F) Karma Chess      - Capturing men promoted to victim's rank\n");
X	wprint("  (G) Rifle Chess      - Capture without moving\n");
X	wprint("  (H) Kamikazi Chess   - Capturing men lost\n");
X	wprint("  (I) Double Chess     - Make two moves per turn\n");
X	wprint("  (J) Steamroller      - White pawns and king move twice\n");
X	wprint("  (K) Progressive      - One more move every turn\n");
X	wprint("  (L) Maharajah        - White has only maharajah piece\n");
X	wprint("  (M) Losing Chess     - First one to lose all his men wins.\n");
X	wprint("  (N) Conversion Chess - Combination of Karma and Rifle Chess\n");
X	/* If you add to the menu above, add letter to string below */
X	if (counter && Game_type == TY_MIXED)
X	    wprint("  (Z) Mixed Game     - Same custom game you were challenged to\n");
X	wprintf("\nWhich would you like to play [%s]? ",
X	    typename[counter ? Game_type : TY_CHESS]);
X	ch = xenterd("ZABCDEFGHIJKLMN" + (!counter || Game_type != TY_MIXED),
X	    counter?((Game_type == TY_MIXED)? 'Z': Game_type+'A'-1):'A');
X
X	var = (ch == 'Z') ? TY_MIXED : ch - 'A' + 1;
X	wprintf("%c - %s",ch,typename[var]);
X
X	if (var != TY_MIXED)
X	{
X	    /* Set up default options */
X	    for (i=1;i<OPTIONS;i++)
X		option[i] = defopt[var][i];
X
X	    /* Make the initial board */
X	    setup(b);
X	}
X
X	wprint("\nWould you like to customize the game? ");
X	if (enterdyn(counter?(Game_type==TY_MIXED):FALSE))
X	{
X	    customize();
X	    goto skip;
X	}
X    }
X    else
X    {
X	/* Copy in the default options */
X	for (i=1;i<OPTIONS;i++)
X	    option[i] = defopt[1][i];
X	setup(b);
X    }
X
X    /* Ask about the basic stuff */
X
X    wprint("Would you like the game to be private (Y/N)? ");
X    Private = enterdyn(Kriegspiel);
X
X    if (!Musttake && !Kriegspiel && !Musttake &&
X	Capture == CA_NORMAL && Kcapture == CA_NORMAL)
X    {
X	wprint("Would you like the computer to kibitz (Y/N)? ");
X	Help_me = enterdyn(Help_me);
X    }
X    else
X	Help_me = FALSE;
X
X    /* write challenge line to game file */
X
Xskip:if (newgame)
X    {
X	if ((wfp=fopen(fname,"w"))==NULL)
X	{
X	    wprintf("Cchess error:  Unable to create gamefile %s\n",fname);
X	    done(1);
X	}
X	chmod(fname,0700);
X        fprintf(wfp,"%5ld:V %s\n",day(),version);
X    }
X
X    /* Save the challenge */
X    fprintf(wfp,"%5ld:C ",day());
X    saveopts(wfp);
X    placeboard(b);
X    fflush(wfp);
X
X    /* send a challenge message */
X    sprintf(cbuffer,"You have been challenged to a game of chess by %s.\nRun \042%s %s\042 to respond.\n",myid,RUN_CMD,myid);
X    mesg("Cchess Challenge",cbuffer);
X
X}
X
X/* CUSTOMIZE
X *
X *   Fiddle with low-level game options.  This does run in visual mode.
X *   The use of the goofy loop here is to make suspends work correctly.
X */
X
Xcustomize()
X{
Xschar ob[R_SIZE][C_SIZE];
Xregister int question;
Xregister int i;
Xboolean progress;
Xint v,r,c,tmparea;
X
X    hidden = FALSE;
X    question = 0;
X#ifndef LSIGNAL
X    susp1_flg = TRUE;
X    setjmp(susp_env);
X#endif LSIGNAL
X    scrolled = TRUE;
X
X    for ( ; question >= 0 ; question++)
X    {
X	if (scrolled)
X	{
X	    disp(b,WHITE);
X	    if (question != 9)
X	    {
X		tmparea = (cy + 1 >= LINES) ? LINES - 1 : cy + 1;
X		cprint("[default answers shown in brackets]");
X	    }
X	    wputchar('\n');
X	    msgarea = (cy >= LINES) ? LINES - 1 : cy;
X	}
X	switch(question)
X	{
X	case 0:		/* Get the board size */
X	    wprintf("Board Size [%dx%d]:",Rows+1,Cols+1);
X	    wprintf("\nRows     (1-%d)? ", HI_ROWS+1);
X	    v = readdint(HI_ROWS+1,Rows+1)-1;
X	    wputchar('\n');
X	    if (v != Rows) scrolled = TRUE;
X	    Rows = v;
X	    break;
X	case 1:
X	    wprintf("Columns (1-%d)? ", HI_COLS+1);
X	    v = readdint(HI_COLS+1,Cols+1)-1;
X	    wputchar('\n');
X	    if (v != Cols) scrolled = TRUE;
X	    Cols = v;
X	    if (Cols == 0 && Rows == 0)
X	    {
X		wprint("You got to be kidding!\n");
X		scrolled = FALSE;
X		question -=2;
X	    }
X	    break;
X
X	case 2:
X	    wprintf("Is the board checkered [%s]? ",yorn(!Plain));
X	    v = !enterdyn(!Plain);
X	    if (v != Plain) scrolled = TRUE;
X	    Plain = v;
X	    break;
X
X	case 3:		/* Piece names */
X	    initmore();
X	    mprintf("What names should the pieces be given");
X	    Language = enterone(langname,HI_NAMES,Language);
X	    piecename = chessname[Language];
X	    break;
X
X	case 4:		/* White King piece */
X	    wprintf("Should white have a mateable piece [%s]? ",
X		yorn(Whiteking != SQ));
X	    if (!enterdyn(Whiteking != SQ))
X	    {
X		Whiteking = SQ;
X		question++;	
X	    }
X	    break;
X	case 5:
X	    wprintf("Which is the white mateable piece [%s]? ",
X		    (Whiteking != SQ)? pman(Whiteking) : "");
X	    while ((v = xenterd(pc,pc[PIECES-Whiteking])) == ' ')
X		bell();
X	    Whiteking = PIECES - (index(pc,v)-pc);
X	    wprintf("%s\n",pman(Whiteking));
X	    break;
X
X	case 6:		/* Black King piece */
X	    wprintf("Should black have a mateable piece [%s]? ",
X		yorn(Blackking != SQ));
X	    if (!enterdyn(Blackking != SQ))
X	    {
X		Blackking = SQ;
X		question++;
X	    }
X	    break;
X	case 7:
X	    wprintf("Which is the black mateable piece [%s]? ",
X		    (Blackking != SQ)? pman(Blackking) : "");
X	    while ((v = xenterd(pc,pc[PIECES-Blackking])) == ' ')
X		bell();
X	    Blackking = PIECES - (index(pc,v)-pc);
X	    wprintf("%s\n",pman(Blackking));
X	    break;
X
X
X	case 8:	/* Edit the board - If board is illegal keep asking till ok */
X	    wprintf("Would you like to edit the initial placement [No]? ");
X	    if (enterdyn(FALSE))
X	    {
X		/* Set things up for the editor */
X		copy(b,bc);
X		copy(b,ob);
X#ifndef NOTERMCAP
X		/* Clear scrolling area */
X		if (cleardown)
X		{
X		    cursor(1,tmparea);
X		    msgarea = tmparea;
X		    clbot();
X		}
X		else
X#endif NOTERMCAP
X		    scrolled = TRUE;
X
X		break;
X	    }
X	    else
X	    {
X#ifndef NOTERMCAP
X		if (!DL && cy == LINES) wputchar('\n');
X#endif NOTERMCAP
X		/* If he says not to edit, make sure board is OK */
X		if (!checkbd(b,WHITE) || !checkbd(b,BLACK))
X		    question--;
X		else
X		    question++;
X	    }
X	    break;
X
X	case 9:		/* Take an editor command */
X	    if (editbd(b,ob))
X		question--;
X	    else
X	    {
X#ifndef NOTERMCAP
X		if (cleardown)
X		{
X		    cursor(1,msgarea);
X		    clbot();
X		    cprint("[default answers shown in brackets]");
X		    wputchar('\n');
X		    msgarea = (cy >= LINES) ? LINES - 1 : cy;
X		}
X		else
X#endif NOTERMCAP
X		    scrolled = TRUE;
X	    }
X	    break;
X
X	case 10:	/* Enter Capture Rules */
X	    initmore();
X	    mprint("What is the rule for pieces capturing");
X	    Capture = enterone(captname,HI_CAPTURE,Capture);
X	    break;
X	case 11:
X	    if (Whiteking != SQ || Blackking != SQ)
X	    {
X		initmore();
X		mprint("What is the rule for ");
X		pkings(mprintf);
X		mprint(" capturing");
X		Kcapture = enterone(captname,HI_KCAPTURE,Kcapture);
X	    }
X	    break;
X
X	case 12:	/* Is this Kriegspiel? */
X	    wprintf("Are enemy pieces visible to player [%s]? ",
X		yorn(!Kriegspiel));
X	    Kriegspiel = !enterdyn(!Kriegspiel);
X	    break;
X
X	case 13:	/* May both players castle? */
X	    if (cancastle(b,WHITE) || cancastle(b,BLACK))
X	    {
X		wprintf("Is castling allowed [%s]? ", yorn(!Oldcastle));
X		Oldcastle = !enterdyn(!Oldcastle);
X	    }
X	    /* if not possible to castle, just leave option with default */
X	    break;
X
X	case 14:	/* Old fashioned pawns? */
X	    /* Ask if there are any pawns, ask about pawn moves */
X	    if ((find(b,WP,&r,&c),r != -1) || (find(b,BP,&r,&c),r != -1))
X	    {
X		wprintf("Can Pawn move double on their first moves [%s]? ",
X		    yorn(!Oldpawn));
X		Oldpawn = (!enterdyn(!Oldpawn));
X	    }
X	    else
X		question++;
X	    break;
X	case 15:
X	    if (Whiteking != WP && Blackking != WP)
X	    {
X		wprintf("Pawn promotion to %s, %s, %s or %s [%s]? ",
X		    piecename[WQ], piecename[WR], piecename[WB],
X		    piecename[WN], yorn(Promotion==PR_QRBN));
X		if (enterdyn(Promotion==PR_QRBN))
X		{
X		    Promotion = PR_QRBN;
X		    question++;
X		}
X	    }
X	    else
X	    {
X		Promotion = PR_NONE;
X		question++;
X	    }
X	    break;
X	case 16:
X	    if (Whiteking != WM && Blackking != WM)
X	    {
X		wprintf("Pawn promotion to %s only [%s]? ",
X		    piecename[WM], yorn(Promotion!=PR_NONE));
X		if (enterdyn(Promotion!=PR_NONE))
X		    Promotion = PR_MINISTER;
X		else
X		    Promotion = PR_NONE;
X	    }
X	    else
X		Promotion = PR_NONE;
X	    break;
X
X	case 17:	/* Select Multiple moves */
X	    if (Capture == CA_CONVERSION || Kcapture == CA_CONVERSION)
X	    {
X		Whitemoves = Blackmoves = Winitmoves = Binitmoves = 1;
X		question += 4;
X	    }
X	    else
X	    {
X		wprintf("Is this a Progressive chess game [%s]? ",
X			yorn(!Whitemoves));
X		progress = enterdyn(!Whitemoves);
X	    }
X	    break;
X	case 18:
X	    wprintf("How many moves on White's first turn [%d]? ",Winitmoves);
X	    Winitmoves = readdint(HI_WIMOVES,Winitmoves);
X	    wputchar('\n');
X	    if (progress)
X	    {
X		Binitmoves = Whitemoves = Blackmoves = MO_PROGRESS;
X		question += 3;
X	    }
X	    break;
X	case 19:
X	    wprintf("How many moves on White's later turns [%d]? ",
X		Whitemoves);
X	    Whitemoves = readdint(HI_WMOVES,Whitemoves);
X	    wputchar('\n');
X	    break;
X	case 20:
X	    wprintf("How many moves on Black's first turn [%d]? ",
X		Binitmoves);
X	    Binitmoves = readdint(HI_BIMOVES,Binitmoves);
X	    wputchar('\n');
X	    break;
X	case 21:
X	    wprintf("How many moves on Black's later turns [%d]? ",
X		Blackmoves);
X	    Blackmoves = readdint(HI_BMOVES,Blackmoves);
X	    wputchar('\n');
X	    break;
X	case 22:
X	    if (Winitmoves > 1 || Binitmoves > 1)
X	    {
X		wprintf("Must players stay on their own sides on the first turns [%s]? ",yorn(Tabiyat));
X		Tabiyat = enterdyn(Tabiyat);
X	    }
X	    else
X		Tabiyat = FALSE;
X	    break;
X	case 23:
X	    if ((Winitmoves > 1 || Binitmoves > 1 ||
X		 Whitemoves > 1 || Blackmoves > 1 ||
X		 Whitemoves == MO_PROGRESS) &&
X		(Whiteking != SQ || Blackking != SQ))
X	    {
X		wprintf("May ");
X		pkings(wprintf);
X		wprintf(" move through check [%s]? ",
X		    yorn(Thrucheck));
X		Thrucheck = enterdyn(Thrucheck);
X	    }
X	    break;
X
X	case 24:	/* Enter results */
X	   initmore();
X	   mprint("What is the effect of being stalemated");
X	   Staleresult = enterone(resltname,HI_STALE,Staleresult);
X	   break;
X	case 25:
X	   initmore();
X	   mprint("What is the effect of losing all forces");
X	   if (Blackking != SQ || Whiteking != SQ)
X	       mprint(" except your mateable piece");
X	   Stripresult = enterone(resltname,HI_STRIP,Stripresult);
X	   break;
X
X	case 26:	/* Must take? */
X	    if (Capture != CA_NONE || Kcapture != CA_NONE)
X	    {
X		wprintf("Must pieces be captured whenever possible [%s]? ",
X			yorn(Musttake));
X		Musttake = enterdyn(Musttake);
X	    }
X	    else
X		Musttake = FALSE;
X	    break;
X
X	case 27:	/* Privacy */
X	    if (Kriegspiel)
X		wprint("To prevent peeking, Kriegspiel games should be private:\n");
X
X	    wprintf("Would you like the game to be private [%s]? ",
X		yorn(Kriegspiel));
X	    Private = enterdyn(Kriegspiel);
X	    break;
X
X	case 28:	/* Computer Kibitzing */
X	    if (!Musttake && !Kriegspiel &&
X		Capture == CA_NORMAL && Kcapture == CA_NORMAL)
X	    {
X		wprintf("Would you like the computer to kibitz [Yes]? ");
X		Help_me = enterdyn(TRUE);
X	    }
X	    else
X		Help_me = FALSE;
X	    break;
X
X	case 29:	/* Give him a chance to make another pass */
X
X	    /* Figure out if anything really got changed */
X	    for (i=4;i<OPTIONS;i++)
X		if (i != OP_NAMES && i != OP_BOARD &&
X		    option[i] != defopt[Game_type][i])
X		{
X		    Game_type = TY_MIXED;
X		    break;
X		}
X
X	    /* Print out the options */
X	    initmore();
X	    mprint("Options selected:\n");
X	    printopts(mprintf);
X
X	    mprint("Are these correct? ");
X	    if (enteryn())
X		question = -100;	/* Exit loop */
X	    else
X		question = -1;		/* Restart loop */
X	    break;
X
X	default:
X	    wprint("Lost in customization\n");
X	    question = -100;
X	    break;
X	}
X    }
X#ifndef LSIGNAL
X    susp1_flg = FALSE;
X#endif LSIGNAL
X}
X
Xint enterone(name,hi,def)
Xint hi;
Xchar *name[];
Xint def;
X{
Xregister int i;
Xregister char ch;
X	mprintf(" [%s]:\n",name[def]);
X	for (i = 0; i <= hi; i++)
X		mprintf("   (%c) %s\n",i+'A',name[i]);
X	mprintf("enter (A-%c)? ",hi+'A');
X	for (;;)
X	{
X		if ((ch = getchar()) == '\n' || ch == '\r')
X			i = def;
X		else
X			i = (ch <= 'Z') ? ch - 'A' : ch - 'a';
X
X		if (i > hi || i < 0)
X			bell();
X		else
X			break;
X	}
X
X	mprintf("%c - %s\n",i+'A',name[i]);
X	return(i);
X}
X
X/* PKINGS()
X *
X *   Print names of mateable pieces.  Don't call this if there are none.
X *   prtf is the function to print with.  mprintf or wprintf or printf.
X */
X
Xpkings(prtf)
Xint (*prtf)();
X{
X    if (Whiteking != SQ)
X    {
X	(*prtf)("%ss",pman(Whiteking));
X	if (Whiteking != Blackking && Blackking != SQ)
X	    (*prtf)(" and %ss",pcolman(-Blackking));
X    }
X    else
X	(*prtf)("%ss", pcolman(-Blackking));
X}
X
X/*  ACCEPT()
X *
X *    Accept Challange mode.  Print options.  Accept, Reject or
X *    Counter-challenge.  Write appropriate selection in game file.
X *    Not in visual mode.
X */
X
Xdoaccept()
X{
Xboolean first = TRUE;
Xboolean washidden;
X
X    /* Some initialization stuff */
X    washidden = hidden;
X    hidden = FALSE;
X#ifndef LSIGNAL
X    susp1_flg = TRUE;
X    setjmp(susp_env);
X#endif LSIGNAL
X    scrolled = TRUE;
X
X    for (;;)
X    {
X	if (scrolled)
X	{
X	    disp(b,kibitz?WHITE:mycolor);
X	    wputchar('\n');
X	    msgarea = (cy >= LINES) ? LINES - 1 : cy;
X	}
X
X	if (first)
X	{
X	    initmore();
X	    if (kibitz)
X	    {
X		if (moveok)
X		    mprintf("%s has been challenged by %s",myid,hisid);
X		else
X		    mprintf("%s has been challenged by %s",hisid,myid);
X	    }
X	    else
X	    {
X		if (moveok)
X		    mprintf("You have been challenged by %s",hisid);
X		else 
X		    mprintf("You have challenged %s",hisid);
X	    }
X
X	    mprint(" to a game of correspondence chess\nwith the following options:\n\n");
X	    printopts(mprintf);
X	    if (!moveok)
X	    {
X#ifndef LSIGNAL
X		susp1_flg = FALSE;
X#endif LSIGNAL
X		hidden = washidden;
X		return;
X	    }
X	    mprint("Help, ");
X	    first = FALSE;
X	}
X
X	mprint("Accept, Reject or Counter-Challenge? ");
X	switch (xenter("LACRVOH?EQ\014"))
X	{
X	case 'H': /* Offer help */
X	case '?':
X		wprint("Help\n");
X		initmore();
X		mprint(" A - Accept this cchess challenge\n");
X		mprint(" R - Reject this cchess challenge\n");
X		mprint(" C - Counter-challenge with different options\n");
X		mprint(" O - Print the options again\n");
X		mprint(" L - Print date of challenge\n");
X		mprint("^L - Redraw display\n");
X		mprint(" Q - Quit the program without doing anything\n");
X		break;
X
X	case '\014':
X		wprint("Redraw\n");
X		scrolled = TRUE;
X		break;
X	case 'L':
X		wprintf("Last challenge made on %s\n",cday(lastday));
X		break;
X
X	case 'O':	/* Redisplay the options */
X		wprint("Options\n");
X		initmore();
X		printopts(mprintf);
X		break;
X
X	case 'Q':	/* Quit */
X		wprint("Quit\n");
X		return;
X	case 'E':	/* Exit */
X		wprint("Exit\n");
X		return;
X
X	case 'A':	/* challenge accepted */
X		wprint("Accept\n");
X#ifndef LSIGNAL
X		susp1_flg = FALSE;
X#endif LSIGNAL
X		status = 3;
X		fprintf(wfp,"%5ld:A      \n",day());
X		/* mail message */
X		sprintf(cbuffer,
X		    "Your challenge has been accepted.  Run \042%s %s\042.\n",
X		    RUN_CMD,myid);
X		mesg("Cchess Challenge Accepted",cbuffer);
X		hidden = washidden;
X		return;
X
X	case 'R': /* challenge rejected */
X		wprint("Reject\n");
X#ifndef LSIGNAL
X		susp1_flg = FALSE;
X#endif LSIGNAL
X		unlink(fname);
X		mesg("Cchess Challenge Rejected",
X		    "Your challenge has been rejected.\n");
X		return;
X
X	case 'C': /* counter challenge */
X		wprint("Challenge\n");
X#ifndef LSIGNAL
X		susp1_flg = FALSE;
X#endif LSIGNAL
X		clr();
X		dochallenge(TRUE);
X		return;
X
X	case 'V': /* version command */
X		versprint();
X		break;
X	}
X    }
X}
X
X
X/* EDITBD()
X *
X * Edit a board set up.  Board ob is passed in with the original arrangment.
X * Board nb is the current set up.  Upon return, it contains the edited set up.
X * The global board, bc should be a copy of nb.  This reads just one command.
X * It returns FALSE if the last command was a quit.
X */
X
Xboolean editbd(nb,ob)
Xschar nb[R_SIZE][C_SIZE];
Xschar ob[R_SIZE][C_SIZE];
X{
Xshort ox, oy;
Xint row,col,i;
Xchar buf[40],*name;
Xchar ch,cmd;
Xschar piece;
Xchar *tp;
X
X    /* Prompt for a command */
X
X    wprint("Place, Delete or Quit? ");
X    cmd = xenter("PDUEQVH?\014");
X
X    switch (cmd)
X    {
X    case 'H':
X    case '?':
X	wprint("Help\n");
X
X	wprint("Would you like a list of commands? ");
X	if (enteryn())
X	{
X	    initmore();
X	    mprint("Place -    Put a piece on a square\n");
X	    mprint("Delete -   Remove a piece from board\n");
X	    mprint("Undo -     Undo all changes to board\n");
X	    mprint("Quit -     Exit board edit mode\n");
X	    mprint("^L -       Redraw the screen\n");
X	}
X
X	wprint("Would you like a list of pieces? ");
X	if (enteryn())
X	{
X	    initmore();
X	    for (i=1;i<PIECES;i+=2)
X		mprintf(" %c = %-9.9s  %c = %-9.9s\n",
X		    pc[PIECES-i],piecename[i],
X		    pc[PIECES-i-1],piecename[i+1]);
X#if (PIECES % 2) == 1
X	    mprintf(" %c = %-9.9s\n",
X		pc[0],piecename[PIECES]);
X#endif
X	}
X	break;
X
X    case 'P':
X	wprint("Place\n");
X
X	/* Get the piece */
X	wprint("What Type of Piece (upper case for black)? ");
X	for (;;)
X	{
X	    ch = getchar();
X	    if (ch == '\n' || ch == '\r') break;
X	    if (ch == 'p') ch = 'i';
X	    else if (ch == 'P') ch = 'I';
X	    if ((tp = index(pc,ch)) != 0) break;
X	    bell();
X	}
X	if (ch == '\n' || ch == '\r')
X	{
X	    wputchar('\n');
X	    break;
X	}
X	piece = (tp-pc)-PIECES;
X	wprint(name = pcolman(piece));
X
X	/* Get the position */
X	wprintf("\nWhere should the %s be placed? ",name);
X    
X    case 'D':
X	if (cmd == 'D')
X	{
X	    piece = SQ;
X	    wprint("Delete\nFrom what position? ");
X	}
X	if (!pread(buf)) break;
X	col = buf[0] - 'A';
X	row = buf[1] - '1';
X	wputchar('\n');
X
X	if (cmd == 'D' && nb[row][col] == SQ)
X	{
X	    wprintf("No piece at %2.2s\n",buf);
X	    break;
X	}
X
X	/* Make the change to the board copy */
X	bc[row][col] = piece;
X
X	/* Display the new position */
X#ifndef NOTERMCAP
X	if (!scrolled && issmart)
X	{
X	    ox = cx; oy = cy;
X	    update(nb,bc);
X	    cursor(ox,oy);
X	}
X	else
X	{
X#endif NOTERMCAP
X	    disp(bc, kibitz ? WHITE : mycolor);
X	    wputchar('\n');
X#ifndef NOTERMCAP
X	}
X#endif NOTERMCAP
X	/* Make the change to the real board */
X	nb[row][col] = piece;
X	break;
X
X    case 'U':
X	wprint("Undo\n");
X	if (compare(nb,ob))
X	{
X	    wprint("No changes have been made\n");
X	    break;
X	}
X	wprint("Do you want to undo all changes? ");
X	if (!enteryn()) break;
X#ifndef NOTERMCAP
X	if (!scrolled && issmart)
X	{
X	    ox = cx; oy = cy;
X	    update(nb,ob);
X	    cursor(ox,oy);
X	}
X	else
X#endif NOTERMCAP
X	    scrolled = TRUE;
X
X	copy(ob,nb);
X	copy(ob,bc);
X	break;
X
X    case 'Q': /* Quit */
X	wprint("Quit\n");
X    case 'E': /* Exit */
X	if (cmd == 'E') wprint("Exit\n");
X#ifndef NOTERMCAP
X	if (!DL && cy == LINES) wputchar('\n');
X#endif NOTERMCAP
X	/* Make sure we got a sane board */
X	if (!(checkbd(nb,WHITE) && checkbd(nb,BLACK))) break;
X
X	/* Confirm that he is really done */
X	wprint("Are you sure you're done editing? ");
X	if (!enteryn()) break;
X	return(FALSE);
X
X    case '\014': /* Control-L redraws the screen */
X	wprint("Redraw\n");
X	scrolled = TRUE;
X	break;
X
X    case 'V':  /* Version */
X	versprint();
X	break;
X    }
X    return(TRUE);
X}
X
X
X/* CHECKBD()
X *
X * Check if an edited board is a reasonable one.  This is currently
X * a bit too strict.  It should really only check if the second player
X * is in check, or the first player is stalemated.
X */
X
Xboolean checkbd(nb,color)
Xschar nb[R_SIZE][C_SIZE];
Xschar color;
X{
Xint row,col;
Xregister int r,c;
Xschar myking = Kingpiece(color);
X
X    if (myking != SQ)
X    {
X	/* Find a King */
X	switch (piececount(nb,myking,&row,&col))
X	{
X	case 0:
X	    wprintf("No %s on board\n",pcolman(myking));
X	    return(FALSE);
X	case 2:
X	    wprintf("Too many %ss on the board\n",pcolman(myking));
X	    return(FALSE);
X	}
X
X	if (check(nb,-color,row,col))
X	{
X	    wprintf("%s is in check\n",pcolman(myking));
X	    return(FALSE);
X	}
X    }
X    else
X    {
X	/* Make sure you have at least some sort of piece */
X	for (r=0;r<=Rows;r++)
X	    for (c=0;c<=Cols;c++)
X		if (nb[r][c]*color > 0)
X		    goto ok;
X	wprintf("No %s pieces on board\n",pcol(color));
X	return(FALSE);
X    }
X
Xok: if(!canmove(nb,color,FALSE))
X    {
X	wprintf("%s cannot move\n",pcol(color));
X	return(FALSE);
X    }
X
X    return(TRUE);
X}
X
X/* PIECECOUNT
X *
X *   Return 0 if there are no pieces of the type, 1 if there is exactly one,
X *   or 2 if there are more than one.  The location of the first one found
X *	is returned in the last two.
X */
X
Xint piececount(nb,piece,row,col)
Xschar nb[R_SIZE][C_SIZE];
Xschar piece;
Xint *row,*col;
X{
Xregister int r,c,tcol;
X
X    /* Find one Piece */
X    find(nb,piece,row,col);
X    if (*row == -1)
X	return(0);
X
X    /* Any more of them? */
X    tcol = *col;
X    for (r = *row;r <= Rows;r++)
X    {
X	for (c=tcol+1; c<=Cols; c++)
X	    if (nb[r][c] == piece)
X		    return(2);
X	tcol = -1;
X    }
X    return(1);
X}
X
X/* CANCASTLE
X *
X *   If there is a sensible way to castle on the current board?
X */
X
Xcancastle(nb,color)
Xschar nb[R_SIZE][C_SIZE];
Xschar color;
X{
Xint row,col;
X
X    /* There is exactly one king of this color */
X    if (piececount(nb,color*WK,&row,&col) != 1)
X	return(FALSE);
X
X    /* There is a rook of the same color at one of the margins */
X    return (nb[row][0] == color*WR || nb[row][Cols] == color*WR);
X}
X
Xversprint()
X{
X	wprintf("Version %s %s\n",version,copyright);
X}
END_OF_init.c
if test 22583 -ne `wc -c <init.c`; then
    echo shar: \"init.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"main.c\"
else
echo shar: Extracting \"main.c\" \(25282 characters\)
sed "s/^X//" >main.c <<'END_OF_main.c'
X/*	C O R R E S P O N D E N C E   C H E S S			version 1.00
X *
X *	Play chess with another player, with notification of moves by mail.
X *
X *	(C) Copyright - Dec 1987 - Jan Dithmar Wolter.
X *	
X *	This source code may be freely used, but not for purposes of profit
X *	without the permission of the author.  This copyright notice should
X *	not be removed.
X *
X *	I would be very interested in hearing about suggestions, bug reports,
X *	and porting problems with cchess.  I can be mailed on usenet at
X *	janc@crim.eecs.umich.edu.  Better yet, dial into M-Net at
X *	(313)994-6333, give yourself an account and join the "ugames"
X *	conference.  This is a free public bbs and cchess's development site.
X *
X *	Any programmer who wishes to make improvements should be warned that
X *	this is a sadly unmodular program.  There are tons of global variables
X *	and subroutines have curious side-effects.  The arrays containing the
X *	board (b and bc) and the input buffers (mbuffer and sbuffer) are
X *	particularly strange this way, being used for just about everything.
X *	Sorry.  That's what happens when what was originally supposed to be a
X *	"quicky" project grows for five years.
X *
X *	version 0.10:
X *		First pre-release version.
X *	version 0.11:
X *		Added Unix 4.2bsd support.
X *		Rationalized version dependent signal handlers as much as
X *		  possible with three different signal handling libraries.
X *		Added Computer Kibitzing option to help make up for poor
X *		  graphics.
X *	version 0.12:
X *		Save illegal moves in kriegspeil games.
X *		Added Big Board option on Ron Theriault's suggestion.
X *		Solidified Forfiet/Draw code.  (Finally).
X *		Touched up transcripts.
X *		Added help command.
X *	version 0.13:
X *		Added support for 22 column terminals (Commodores).
X *		Pawn promotion noted on transcripts.
X *		Redraw and Version work at "Not your move prompt"
X *		Solidified Challenge/Accept code.  (Finally).
X *	version 0.14:
X *		Cosmetic changes to Exit command.
X *		Fix system() calls to protect them from dirty tricks.
X *		Let Kriegspielers replay the game after it is over.
X *		Improve castling code so it will work for halfboard games.
X *		Kriegspiel only counts some kinds of illegal moves.
X *		Time stamp added to each line of game file.
X *		Version and Redraw commands work at accept draw prompt.
X *		Replay renamed Playback, and dodraw() integrated with domove().
X *		White pieces displayed with highlighting on the big board.
X *		Divided sys.c file into sys.c and scrn.c.
X *		Fixed a bug that caused moves to get lost during playbacks.
X *	version 0.15:
X *		Fixed a pawn promotion bug that appeared in 0.14.
X *		Added Shatranj and Courier game variations.
X *		Added Karma, Rifle & Kamikazi Chess capture variations.
X *		Version 6 style ioctl() calls now understood by sys.c
X *	version 0.16
X *		Repeated position detection code kludged in.
X *		Fifty move rule enforcement installed.
X *		Game cancellation command added.
X *		Minor bug fixes to Karma chess, Kriegspiel and Scoreboard.
X *	version 0.17
X *		Big changes in the way options are represented internally
X *		   and in game files and in score file.
X *		Addition of Maharajah piece.
X *		Multiple moves for variant games.
X *		Steamroller, Double Chess and Progressive variants added.
X *		Initial board set-up specified in transcript file.
X *		O command to display current game options added.
X *		mprint() for "--More--" on Help and Options.
X *		Board editor for custom chess boards.
X *		Further generalization of castling code.
X *		No spaces allowed in transcript file names.
X *		Bug fixes to mate detection.
X *		Redraw works at "Are you sure" and "Move:" prompts.
X *		Use user defined backspace character from stty calls.
X *		Mailer is run in background.
X *		Clarification of format of comments under board.
X *	version 0.18
X *		May name a user with -g option.
X *		Speedup of -g option with lookaside buffer for passwd lookups.
X *		Auto-redraw after suspend (sort of) made to work.
X *		Addition of French and German piece names.
X *		Various small bug fixes for system V.
X *		Added -a option to move in all possible games.
X *		Fixed printing of cancellation requests in transcripts.
X *		Illegal moves optionally printed in kriegspiel transcripts.
X *		Enter kibitz mode only if you are neither of the players.
X *		Changes to allow no king, or some other mateable piece.
X *		Fixes to the computer kibitzer (rooks don't cover themselves).
X *		Bug Fixes to playback of multimove games.
X *		Broke cmd.c file into cmd.c and init.c.
X *		Added Last command to display date of last move.
X *		Redesign of challenge and accept subsystems.
X *		Maharajah and Losing chess variant games added.
X *		Many fixes to mate detection.
X *		Tab'iyat option for sped up openings.
X *	version 0.19
X *		Turned off nl to crnl mapping and fixed stuff to work that way.
X *		Rewrote directory reading to use clone of 4.2bsd readdir().
X *		Fix things so display isn't confused by R lines in gamefile.
X *		Close files when -a option is used.
X *		Fix queen moves in mate detection.
X *		Simplification of compile time definitions.
X *		Rewrite to simplify cctrans() routine.
X *		Innumerable minor fixes and clean up work all over.
X *		Conversion Chess added with thanks to Kenneth Larimer.
X *		Version numbers added to game files.
X *		Crude support of 4.3bsd windowing interupt.
X *	version 1.00
X *		Cleaned up for posting to USENET.
X */
X
X#include "cchess.h"
X
X/* String identifying current version */
Xchar *version = "0.19";
Xchar *copyright = "(c) 1987 Jan Wolter";
X
X/* Characters and Names for pieces (some foreign name sets are incomplete) */
X
Xchar pc[] = "HJDEMIRNBQK kqbnrimedjh";
Xchar *chessname[HI_NAMES+1][PIECES+1] = {
X      { "Empty Square",	"King",		"Queen",	"Bishop",
X	"Knight",	"Rook",		"Pawn",		"Minister",
X	"Elephant",	"Duke",		"Jester",	"Maharajah"},
X
X      { "Empty Square",	"Shah",		"Queen",	"Bishop",
X	"Faras",	"Rukh",		"Baidaq",	"Firz",
X	"Fil",		"Duke",		"Jester",	"Maharajah"},
X
X      { "Empty Square",	"Roi",		"Dame",		"Fou",
X	"Cavaler",	"Tour",		"Pion",		"Ministre",
X	"Elephant",	"Duc",		"Jester",	"Maharajah"},
X
X      { "Empty Square",	"Konig",	"Dame",		"Laufer",
X	"Springer",	"Turm",		"Bauer",	"Minister",
X	"Elefant",	"Herzog",	"Jester",	"Maharajah"} };
Xchar **piecename;
X
Xshort wfr,wfc,wtr,wtc;	/* last white move - used for en paussant legality */
Xshort bfr,bfc,btr,btc;	/* last black move - used for en paussant legality */
Xschar promote = 0;	/* Character to promote pawn to - 0 if no promotion */
X
X/* Have the Kings or the Rooks been moved? */
Xboolean wcck = TRUE;	/* White can castle king-side  */
Xboolean wccq = TRUE;	/* White can castle queen-side */
Xboolean bcck = TRUE;	/* Black can castle king-side  */
Xboolean bccq = TRUE;	/* Black can castle queen-side */
X
X/* Initial board layout */
X				         /* Last four columns */
Xschar ib[R_SIZE][C_SIZE] = {	         /* for Courier only. */
X	WR, WN, WB, WQ, WK, WB, WN, WR,     WB, WE, WN, WR,
X	WP, WP, WP, WP, WP, WP, WP, WP,     WP, WP, WP, WP,
X	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
X	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
X	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
X	SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ,     SQ, SQ, SQ, SQ,
X	BP, BP, BP, BP, BP, BP, BP, BP,     BP, BP, BP, BP,
X	BR, BN, BB, BQ, BK, BB, BN, BR,     BB, BE, BN, BR,
X	};
X
Xschar bc[R_SIZE][C_SIZE]; /* Copy of the board, so moves can be taken back */
Xschar b[R_SIZE][C_SIZE];  /* Main board */
Xint errcode;			/* Move error code */
X
Xint hisuid;			/* Opponent user id number */
Xint myuid;			/* Player user id number */
Xchar hisid[20];			/* Opponent login name */
Xchar myid[20];			/* Player login name */
X#ifdef COMPAT018
Xchar file_version[6] = "0.18";	/* Version of cchess that produced game file */
X				/* If no version line, assume 0.18 */
X#else
Xchar file_version[6] = "";	/* Version of cchess that produced game file */
X#endif COMPAT018
X
Xint movecnt;			/* Number of moves made so far in game */
Xint playcnt;			/* Number of moves including proposals */
Xint mvssize;			/* Number of moves on the move stack */
Xint tamemoves;			/* Number of tame moves made */
Xint consmoves;			/* Number of consecutive moves allowed */
Xint consmade;			/* Number of consecutive moves made */
X
Xchar fname[50];		/* Name of the gameboardfile */
XFILE *rfp;		/* File pointer for reading from boardfile */
XFILE *wfp;		/* File pointer for writing to boardfile */
X
X/* Game status code:
X *    0 -> No challenge made.
X *    1 -> Challenge has been sent.
X *    2 -> (not used)
X *    3 -> Ready to move.
X *    4 -> A draw has been proposed.
X *    5 -> A draw has been accepted.
X *    6 -> Player has forfeited.
X *    7 -> cancellation has been proposed.
X *    8 -> cancellation has been accepted.
X */
X
Xchar status;
X
X/* General Purpose Global Flags */
X
Xboolean newgame;		/* Are we starting a new game file? */
Xboolean moveok = TRUE;		/* Allow player to move? */
Xboolean solo;			/* Is he playing himself? */
Xboolean kibitz = FALSE;		/* Is this a kibitzing session? */
Xboolean bigboard = FALSE;	/* Display board in large format? */
Xboolean hidden = FALSE;		/* Should enemy moves be shown? */
Xboolean incheck = FALSE;	/* Is player in check (or mate)? */
Xboolean inmate = FALSE;		/* Is plater (check or stale) mated */
Xboolean repeated = FALSE;	/* Is this a thrice repeated position? */
Xboolean stripped = FALSE;	/* Have we just stripped the other player? */
Xboolean istame;			/* Was the last move a tame one? */
Xboolean interupt;		/* OK to interupt out of program? */
Xboolean eachgame = FALSE;	/* Play each playable game? */
Xboolean must_take = FALSE;	/* Allow only moves which capture? */
X
Xschar toplay=WHITE;		/* color to play next */
Xschar order;			/* -1 if other player named first, else 1 */
Xschar mycolor;			/* What color am I? */
Xschar taken;			/* Piece taken in last move.  SQ for none. */
Xlong lastday;			/* Day number on which last move was made. */
Xboolean erases=TRUE;		/* Can terminal erase properly? */
Xboolean issmart=FALSE;		/* Can address cursor and erase? */
Xboolean cleardown=FALSE;	/* Can clear screen below cursor and smart? */
Xboolean commodore=FALSE;	/* Do we have a 22 column terminal? */
Xboolean scrolled=FALSE;		/* Has the screen scrolled? */
Xint illmoves;			/* Count of illegal Kriegspiel moves */
Xint myillmoves;			/* Count of my illegal Kriegspiel moves */
Xshort cx,cy;			/* Current Cursor position (used by TERMCAP) */
Xshort msgarea = 0;		/* Line below screen where prompts begin */
Xint LINES = 0;			/* Number of lines per screen */
Xint COLS = 40;			/* Number of columns per screen */
Xchar bs_char = '\b';		/* User definable backspace character */
X#ifdef DEBUG
Xboolean debugon = FALSE;	/* Debugging flag */
X#endif DEBUG
X
X/* Names of standard variant games */
Xchar *typename[HI_GAME+1] = {
X	"Mixed", "Chess", "Kriegspiel", "Shatranj", "Courier",
X	"Halfboard Chess", "Karma Chess", "Rifle Chess", "Kamikazi Chess",
X	"Double Chess", "Steamroller", "Progressive Chess", "Maharajah",
X	"Losing Chess", "Conversion Chess"};
X
Xchar *langname[HI_NAMES+1] = { "English","Persian","French","German"};
X
X/* Names of game results */
Xchar *resltname[4] = {"Draw","Win","Lose","Continue"};
X
X/* Names of Capture rules */
Xchar *captname[HI_CAPTURE+1] =
X	{"Standard","No","Rifle","Conversion","Karma","Kamikazi"};
X
X/* Current game options */
Xchar option[OPTIONS];
X
X/* Maximum legal values for the options */
Xchar maxopt[OPTIONS] =
X      { HI_COLOR,     HI_PRIVATE,   HI_KIBITZ,    HI_GAME,
X        HI_ROWS,      HI_COLS,      HI_BOARD,     HI_NAMES,
X        HI_VISIB,     HI_CASTLE,    HI_DPAWN,     HI_STRIP,
X        HI_STALE,     HI_CAPTURE,   HI_KCAPTURE,  HI_PROMOTE,
X	HI_WIMOVES,   HI_BIMOVES,   HI_WMOVES,    HI_BMOVES,
X	HI_THRUCHECK, HI_WHITEKING, HI_BLACKKING, HI_MUSTTAKE,
X	HI_TABIYAT };
X
X/* Variant game default options */
Xchar defopt[HI_GAME+1][OPTIONS] =
X    {
X    			/* Customized game */
X      { FALSE,       FALSE,        TRUE,         TY_MIXED,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Standard Chess */
X      { FALSE,       FALSE,        TRUE,         TY_CHESS,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Kriegspiel */
X      { FALSE,       FALSE,        TRUE,         TY_KRIEGSPIEL,
X	7,           7,            FALSE,        0,
X	TRUE,        FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Shatranj */
X      { FALSE,       FALSE,        TRUE,         TY_SHATRANJ,
X	7,           7,            TRUE,         1,
X	FALSE,       TRUE,         TRUE,         RE_LOSE,
X	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_MINISTER,
X	10,	     10,	   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	TRUE },
X
X			/* Courier */
X      { FALSE,       FALSE,        TRUE,         TY_COURIER,
X	7,           11,           TRUE,         0,
X	FALSE,       TRUE,         TRUE,         RE_LOSE,
X	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_MINISTER,
X	12,	     12,	   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	TRUE },
X
X			/* Halfboard */
X      { FALSE,       FALSE,        TRUE,         TY_HALFBOARD,
X	7,           3,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Karma Chess */
X      { FALSE,       FALSE,        TRUE,         TY_KARMA,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_KARMA,     CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Rifle Chess */
X      { FALSE,       FALSE,        TRUE,         TY_RIFLE,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_RIFLE,     CA_RIFLE,     PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Kamikazi Chess */
X      { FALSE,       FALSE,        TRUE,         TY_KAMIKAZI,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_KAMIKAZI,  CA_NONE,      PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Double Move Chess */
X      { FALSE,       FALSE,        TRUE,         TY_DOUBLE,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	2,	     2,		   2,		 2,
X	TRUE,        WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Steamroller */
X      { FALSE,       FALSE,        TRUE,         TY_STEAMROLLER,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	2,	     1,		   2,		 1,
X	TRUE,        WK,           WK,		 FALSE,
X	FALSE },
X
X			/* Progressive Chess */
X      { FALSE,       FALSE,        TRUE,         TY_PROGRESSIVE,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_LOSE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     MO_PROGRESS,  MO_PROGRESS,  MO_PROGRESS,
X	FALSE,       SQ,           SQ,		 FALSE,
X	FALSE },
X
X			/* Maharajah */
X      { FALSE,       FALSE,        TRUE,         TY_MAHARAJAH,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WH,           WK,		 FALSE,
X	FALSE },
X
X			/* Losing Chess */
X      { FALSE,       FALSE,        FALSE,        TY_LOSING,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_WIN,
X	RE_WIN,      CA_NORMAL,    CA_NORMAL,    PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       SQ,           SQ,		 FALSE,
X	FALSE },
X
X			/* Conversion Chess */
X      { FALSE,       FALSE,        TRUE,         TY_CONVERSION,
X	7,           7,            FALSE,        0,
X	FALSE,       FALSE,        FALSE,        RE_NONE,
X	RE_DRAW,     CA_CONVERSION,CA_CONVERSION,PR_QRBN,
X	1,	     1,		   1,		 1,
X	FALSE,       WK,           WK,		 FALSE,
X	FALSE } };
X
Xchar cbuffer[CB_LEN+1];		/* Comment Buffer */
Xchar mb1[MB_LEN+1];		/* Move Buffer One. */
Xchar mb2[MB_LEN+1];		/* Move Buffer Two. */
Xchar *mbuffer=mb1;		/* Pointer to current move buffer */
Xchar *sbuffer=mb2;		/* Pointer to spare move buffer */
Xjmp_buf jmpenv;			/* Long jump buffer */
X
X/* Some really weird things used to sort of recover from suspends: */
X/* susp1_flg is set if susp_env contains a place to jump to after */
X/* we've been suspended.  susp2_flg is turned on if we got suspended */
X/* while there was no susp_env defined */
X#ifndef LSIGNAL
Xjmp_buf susp_env;
Xboolean susp1_flg = FALSE, susp2_flg = FALSE;
X#endif LSIGNAL
X
X/* String of spaces used when arbitary strings of spaces are needed */
Xchar blankstr[BLANK_LEN+1]	/* Must be exactly BLANK_LEN spaces */
X    = "                                                                      ";
X
X
Xchar transcript = FALSE;	/* Should we just print the transcript? */
X
Xint realuid;
Xboolean activeonly = FALSE;
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xstruct passwd *pwd;		/* Password file entry */
Xregister int players,i,j;
X
X	/* check legality of arguments */
X	players = 0;
X	for (i=1;i<argc;i++)
X	    if (argv[i][0] == '-') 
X		for (j = 1; argv[i][j]; j++)
X		    switch (argv[i][j])
X		    {
X		    case 'a':
X		        eachgame = TRUE;
X		        break;
X
X		    case 's':
X			scoreboard();
X			exit(0);
X
X		    case 'b':
X			bigboard = TRUE;
X			break;
X
X		    case 'g':
X			if (++i < argc)
X			{
X			    if ((pwd = getpwnam(argv[i])) == 0)
X			    {
X				printf("No user %s on this system\n",argv[i]);
X				exit(1);
X			    }
X			    printf("%s's games in progress\n-----------------------------\n",
X				    argv[i]);
X			    list(pwd->pw_uid);
X			}
X			else
X			{
X			    printf("Games in progress\n-----------------\n");
X			    list(-1);
X			}
X			exit(0);
X
X		    case 't':
X			transcript = TRUE;
X			break;
X#ifdef DEBUG
X		    case 'd':
X			debugon = TRUE;
X			break;
X#endif DEBUG
X		    default:
X			printf("Illegal %s option: -%c\n",argv[0],argv[i][j]);
X			usage(argv[0]);
X		    }
X	    else
X		if (++players == 1)
X		    strcpy(hisid,argv[i]);
X		else if (players == 2)
X			strcpy(myid,argv[i]);
X		    else
X		    {
X			printf("Too many options for %s\n",argv[0]);
X			usage(argv[0]);
X		    }
X
X	/* Look up the two players */
X
X	realuid = getuid();
X
X	if (players >= 1)
X	{
X		/* does opponent exist? */
X		if ((pwd = getpwnam(hisid)) == 0)
X		{
X			printf("No user %s on this system\n",hisid);
X			exit(1);
X		}
X		hisuid = pwd->pw_uid;
X	}
X	if (players == 2)
X	{
X		/* does second name exist? */
X		if ((pwd = getpwnam(myid)) == 0)
X		{
X			printf("No user %s on this system\n",myid);
X			exit(1);
X		}
X		myuid = pwd->pw_uid;
X
X		/* If one of the named players is me, ignore it */
X#ifdef DEBUG
X		if (!eachgame && !debugon)
X#else
X		if (!eachgame)
X#endif DEBUG
X		{
X			if (myuid == realuid)
X				players = 1;
X			else if (hisuid == realuid)
X			{
X				players = 1;
X				/* Swap names */
X				strcpy(myid,hisid);
X				strcpy(hisid,pwd->pw_name);
X				hisuid = myuid;
X				myuid = realuid;
X			}
X		}
X	}
X	else if (players == 1)
X	{
X		/* Get my name */
X		if ((pwd = getpwuid(realuid)) == 0)
X		{
X			printf("Panic:  Can't get your password entry\n");
X			exit(1);
X		}
X		strcpy(myid,pwd->pw_name);
X		myuid = realuid;
X	}
X
X	/* If -a flag and less than two names, do all matching games */
X	if (eachgame)
X	{
X		if (players < 2)
X		{
X			activeonly = (players == 0);
X			scangames();			/* Doesn't return */
X		}
X		else
X			eachgame = FALSE;
X	}
X
X	/* If no -a flag, must have at least one player name */
X	if (players == 0)
X	{
X		printf("Must specify name of opponent.\n");
X		usage(argv[0]);
X	}
X
X	/* Are we kibitzing? */
X	if (players == 2) kibitz = TRUE;
X
X#ifdef DEBUG
X	if (debugon)
X	{
X		if (players == 2)
X			kibitz = FALSE;
X		else
X		{
X			printf("Debug option requires two names.\n");
X			exit(1);
X		}
X	}
X#endif DEBUG
X
X	/* Get termcap, set cbreak, noecho, trap interupts */
X	initterm();
X
X	run();
X	exit(-1);
X}
X
X
X/* myid, myuid, hisid and hisuid must be set before calling this */
X/* this never returns.  It always calls done() instead.          */
X
Xrun()
X{
X	/* Initialize various globals */
X	wcck = wccq = bcck = bccq = TRUE;
X	interupt = TRUE;
X	errcode = E_OK;
X	status = 0;
X	taken = SQ;
X
X	/* As he playing himself? */
X	solo = (hisuid == myuid);
X
X	/* See if the Move File Exists */
X	order = -1;
X	sprintf(fname,"%s/%d.%d",CCDIR,hisuid,myuid);
X	
X	if ((rfp=fopen(fname,"r"))==NULL)
X	{
X		order = 1;
X		sprintf(fname,"%s/%d.%d",CCDIR,myuid,hisuid);
X
X		if ((rfp=fopen(fname,"r"))==NULL)
X		{
X			clr();
X			wprintf("No game in progress between %s and %s\n",
X				myid,hisid);
X			if (eachgame || kibitz || transcript) done(0);
X		        wprintf("Would you like to challenge %s (Y/N)? ",
X				hisid);
X			if (enterdyn(TRUE))
X			{
X				newgame = TRUE;
X				status = 0;
X				dochallenge(FALSE);
X			}
X			done(0);
X		}
X	}
X	
X	/* Open the Game file to write */
X
X	if ((wfp=fopen(fname,"a"))==NULL)
X	{
X		wprintf("Cchess error:  Unable to write to gamefile %s\n",
X			fname);
X		done(1);
X	}
X
X	/* Just print a transcript, if that option was selected */
X	if (transcript)
X	{
X		if (eachgame)
X		{
X			if (activeonly)
X			    wprintf("Transcript of game against %s? ",hisid);
X			else
X			    wprintf("Transcript of game between %s and %s? ",
X					myid,hisid);
X			if (!enterdyn(FALSE)) done(0);
X		}
X		trans(TRUE);
X		done(0);
X	}
X
X	newgame = FALSE;
X
X	/* read in the game to date */
X	ldboard();
X
X	if (solo) mycolor = toplay;
X	if (mycolor != toplay)
X		moveok = FALSE;
X	else
X		moveok = !kibitz;
X	if (eachgame)
X	{
X		if (activeonly)
X		{
X			if (mycolor == toplay)
X			{
X				wprintf("Move against %s? ",hisid);
X				if (!enterdyn(FALSE)) done(0);
X			}
X			else
X				done(0);
X		}
X		else
X		{
X			wprintf("Game between %s and %s? ",myid,hisid);
X			if (!enterdyn(FALSE)) done(0);
X		}
X	}
X
X	switch (status)
X	{
X	case 0: /* no challenge made */
X		wprintf("Cchess Error: No Challenge after load.\n");
X		done(1);
X	
X	case 1: /* challenge made */
X		doaccept();
X		/* if white accepted, let him move */
X		if (status != 3 || (mycolor != WHITE && !solo)) break;
X		toplay = WHITE;
X		if (Winitmoves == MO_PROGRESS)
X			consmoves = 1;
X		else
X			consmoves = Winitmoves;
X	
X	case 3: /* make move */
X		if (stripped)
X			domate(Stripresult,EV_FORCES);
X		else if (inmate)
X		{
X			if (incheck)
X				domate(RE_LOSE,EV_CHECKMATE);
X			else
X				domate(Staleresult,EV_STALEMATE);
X		}
X		else if (repeated)
X			domate(RE_DRAW,EV_REPEATED);
X		else
X			domove(RE_NONE);  /* Make a move */
X		break;
X	
X	case 4: /* draw proposal made */
X		if (tamemoves >= MAXTAME)
X			domate(RE_DRAW,EV_FIFTYMOVES);   /* Draw is final */
X		else
X			domove(RE_DRAW);	    /* Answer a draw proposal */
X		break;
X		
X	case 5: /* other player accepted draw */
X		domate(RE_DRAW,EV_AGREEMENT);
X		break;
X
X	case 6: /* other player forfeited */
X
X		domate(RE_WIN,EV_FORFIET);
X		break;
X
X	case 7: /* cancellation proposal made */
X		domove(RE_CANCEL);	    /* Answer a cancellation proposal */
X		break;
X
X	case 8: /* other player accepted cancellation */
X		domate(RE_CANCEL,EV_AGREEMENT);
X		break;
X
X	default:
X		wprintf("Cchess Error:  Weird status %d\n",status);
X		done(1);
X	}
X
X	done(0);
X}
X
X
X
X/*   SCANGAMES()
X *
X *   If activeonly is set, list all games the user can move in.  If activeonly
X *   is not set, list all games that hisuid is in.  For each one, prompt if
X *   he wants to move in it.  Run the program if he does.  Visual mode
X *   not used here.
X */
X   
Xscangames()
X{
Xregister struct direct *gfd;
Xregister char *pwname;
Xregister int n;
Xint uid1,uid2;
XDIR *fp;
X
X	if ((fp = opendir(CCDIR))== 0)
X	{
X		printf("Panic: unable to read %s directory\n",CCDIR);
X		exit(1);
X	}
X	n = 0;
X	igpwuid();
X
X	/* Get name and uid to search for */
X	if (activeonly)
X	{
X		if ((pwname = gpwuid(myuid = realuid)) == 0)
X		{
X			printf("Panic:  Can't get your password entry\n");
X			exit(1);
X		}
X		strcpy(myid,pwname);
X	}
X	else
X	{
X		strcpy(myid,hisid);
X		myuid = hisuid;
X		kibitz = TRUE;
X	}
X
X	while ((gfd = readdir(fp)) != NULL)
X		if (gfd->d_name[0] != '.' && sscanf(gfd->d_name,"%d.%d",&uid1,&uid2)==2)
X		{
X			/* Does this game involve me? */
X			if (uid1 == myuid)
X				hisuid = uid2;
X			else if (uid2 == myuid)
X				hisuid = uid1;
X			else
X				continue;
X
X			/* Look up the other person's id */
X			if ((pwname=gpwuid(hisuid)) == 0)
X				continue;
X			strcpy(hisid,pwname);
X
X			if (n == 0)
X			{
X				initterm();
X				clr();
X			}
X
X			/* Play the game */
X			if (!setjmp(jmpenv))
X				run();
X			n++;
X		}
X	endpwent();  /* close the password file */
X	if (n == 0)
X		printf("No games\n");
X
X	/* Turn off eachgame flag so done() will really exit us */
X	eachgame = FALSE;
X	closedir(fp);
X	done(0);
X}
X
X
X
X/* USAGE
X * 
X *  Print a rather long winded usage message.  This doesn't return.
X */
X
Xusage(name)
Xchar *name;
X{
X	printf("To play:          %s [-a] [-b] opponent\n",name);
X	printf("To peek:          %s [-b] player player\n",name);
X	printf("For transcript:   %s [-a] -t player [player]\n",name);
X	printf("For scoreboard:   %s -s\n",name);
X	printf("For game list:    %s -g [player]\n",name);
X	exit(1);
X}
END_OF_main.c
if test 25282 -ne `wc -c <main.c`; then
    echo shar: \"main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 5\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0