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

⟦5edec6146⟧ TextFile

    Length: 31437 (0x7acd)
    Types: TextFile
    Names: »misc.c«

Derivation

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

TextFile

/* CCHESS MISCELLANEOUS STUFF. 					Version 1.00
 *   
 *   Mainly routines to display various stuff in various ways.
 *
 *   (C) Copyright Jan Wolter - Apr 1986.
 *
 */

#include "cchess.h"

static int ind;		/* Indentation of current display */
static schar botcol;	/* Color on bottom of current display */
#ifndef NOTERMCAP
extern char *CE;	/* So we can tell if there is a clear to end string */
#endif NOTERMCAP

#define usebigboard (bigboard && COLS >= 5*Cols+30)
/* SAVEMOVE()
 *
 *   Send a mail message, saying a move has been made.  Ask for a comment,
 *   and store the entry of type <ch> and with move <mv> (a five character
 *   string) in the file.
 */

savemove(ch,mv)
char ch, *mv;
{
char spc;

	/* Read in a comment */
	if (ch != 'm')
	{
#ifndef LSIGNAL
		setjmp(susp_env);
		susp1_flg = TRUE;
#endif LSIGNAL
		wprint("Comment: ");
		if (readstr(cbuffer,1,CB_LEN,FALSE))
			cbuffer[0] = ' ';
		else
			cbuffer[0] = '\000';
#ifndef LSIGNAL
		susp1_flg = FALSE;
#endif LSIGNAL
	}
	else
		cbuffer[0] = '\000';

	/* Set the space character for moves */
	spc = ' ';
	if (ch == 'M')
	{
		if (stripped)
			spc = 'F';
		else if (inmate)
		{
			if (incheck)
				spc = 'M';
			else
				spc = 'S';
		}
		else
		{
			if (incheck)
				spc = 'C';
			else if (repeated)
				spc = 'R';
		}
	}

	/* Save the move in the gamefile */
	fprintf(wfp,"%5ld:%c%c%5.5s%s\n",day(),ch,spc,mv,cbuffer);

	if ((ch == 'M' || ch == 'm') && promote)
	    fprintf(wfp,"%5ld:P %c%3.3s\n",day(),pc[PIECES-abs(promote)],mv+2);

	/* Flush the output */
	fflush(wfp);

	/* Send Mail */
	sprintf(cbuffer,"My chess move has been made.  Run \042%s %s\042.\n",
		RUN_CMD,myid);
	mesg("Cchess Move",cbuffer);
}


/* PRINTCOM()
 *
 *   Print the players comment under a board.
 */

printcom()
{
	if (mbuffer[C_CMD] != 'A' && mbuffer[C_CMD] != 'C' && 
	    mbuffer[C_FLG] == ' ')
		cprintf("\"%s\"",mbuffer+C_COM);
}



/* PRINTMOV()
 *
 *   This displays the move in <mbuf>, along with the the mate status, and
 *   all that.  This is a partly a kludge.  <Ill> is the number of illegal moves
 *   made in a kriegspiel games.
 */

short movelen = 0;
printmov(mbuf,ill,id)
char *mbuf;
int ill;
char *id;
{
char buf[40];
char tmp;
#ifndef NOTERMCAP
short n;
char bug[40];
#endif NOTERMCAP

	switch(mbuf[C_CMD])
	{
	case 'M':
	case 'm':
		if (hidden)
		{
		    if (taken == SQ)
			sprintf(buf,"%s: %d illegal moves tried",id,ill + 1);
		    else
			sprintf(buf,"%s: %d illegal moves tried - Captured %s",
				id, ill+1, pman(taken));
		}
		else
		{
			tmp = mbuf[C_FLG];
			mbuf[C_FLG] = 0;
			sprintf(buf,"%s: %s",id,mbuf+C_MOV);
			mbuf[C_FLG] = tmp;
		}
		break;
	case 'K':
		sprintf(buf,"%s proposed cancellation",id);
		break;
	case 'D':
		sprintf(buf,"%s proposed draw",id);
		break;
	case 'N':
		sprintf(buf,"%s rejected proposal",id);
		break;
	case 'Y':
		sprintf(buf,"%s accepted proposal",id);
		break;
	case 'F':
		sprintf(buf,"%s forfieted",id);
		break;
	case 'A':
	case 'C':
	case 'P':
		buf[0] = 0;
		break;
	}

	if (incheck)
		if (inmate)
			strcat(buf,(Language == LG_PERSIAN)?
				" - SHAH-MAT":" - CHECKMATE");
		else
			strcat(buf,(Language == LG_PERSIAN)?
				" - SHAH":" - CHECK");
	else
		if (inmate)
			strcat(buf," - STALEMATE");
#ifndef NOTERMCAP
	if ((n =strlen(buf)) >= movelen)
#endif NOTERMCAP
		cprint(buf);
#ifndef NOTERMCAP
	else
		if (CE)
		{
			if (cx != 1) wputchar('\n');
			cline();
			cprint(buf);
		}
		else  /* Here comes the kludge */
		{
			int i,j;
			j = (movelen - n)/2 + 1;
			for (i = 0; i < j; i++) 
				bug[i] = ' ';
			for (j = 0; buf[j] != 0; j++,i++)
				bug[i] = buf[j];
			for (j = 0; j < n; j++,i++)
				bug[i] = ' ';
			cprint(bug);
		}
	movelen = n;
#endif NOTERMCAP
}

/* PRINTOPTS()
 *
 *   Print challenge options.  Colors, Privacy, Variant.  The argument
 *   is the print routine to use.  Normally this is "printf" or
 *   "mprintf" or "wprintf".
 */

printopts(prtf)
int (*prtf)();
{
register int i;

	(*prtf)("WHITE: %-8.8s   ", (mycolor == WHITE) ? myid : hisid);
	(*prtf)("BLACK: %s\n", (mycolor == BLACK) ? myid : hisid);
	if (Private)
		(*prtf)("Privacy: Closed   ");
	else
		(*prtf)("Privacy: Open     ");

	i = Game_type;
	(*prtf)("Variant: %s",typename[i]);

	if (Kriegspiel && !defopt[i][OP_VISIB])
	    (*prtf)(" Kriegspiel");
	if (Rows != defopt[i][OP_ROWS] || Cols != defopt[i][OP_COLS])
	    (*prtf)("\nBoard: %dx%d",Cols+1,Rows+1);
	if (Oldcastle != defopt[i][OP_CASTLE])
	    (*prtf)("\nCastling: %s",Oldcastle?"Forbidden":"Permitted");
	if (Oldpawn != defopt[i][OP_DPAWN])
	    (*prtf)("\nDouble Pawn Move: %s",Oldpawn?"Forbidden":"Permitted");
	if (Stripresult != defopt[i][OP_STRIP])
	    (*prtf)("\nLoss of Forces: %s",resltname[Stripresult]);
	if (Staleresult != defopt[i][OP_STALE])
	    (*prtf)("\nStalemated: %s",resltname[Staleresult]);
	if (Capture != defopt[i][OP_CAPTURE])
	    (*prtf)("\nCapture Rule: %s",captname[Capture]);
	if (Kcapture != defopt[i][OP_KCAPTURE])
	{
	    (*prtf)("\n");
	    pkings(*prtf);
	    (*prtf)("Capture Rule: %s",captname[Kcapture]);
	}
	if (Musttake != defopt[i][OP_MUSTTAKE])
	    (*prtf)("\nCapture: %s",Musttake?"Required":"Optional");
	if (Whiteking != defopt[i][OP_WHITEKING])
	{
	    (*prtf)("\nWhite mateable piece: ");
	    if (Whiteking == SQ)
		(*prtf)("None");
	    else
		(*prtf)(pman(Whiteking));
	}
	if (Blackking != defopt[i][OP_BLACKKING])
	{
	    (*prtf)("\nBlack mateable piece: ");
	    if (Blackking == SQ)
		(*prtf)("None");
	    else
		(*prtf)(pman(Blackking));
	}
	if (Promotion != defopt[i][OP_PROMOTE])
	{
	    (*prtf)("\nPromotion: ");
	    switch(Promotion)
	    {
	    case PR_MINISTER:
		(*prtf)("%s Only",piecename[WM]);
		break;
	    case PR_QRBN:
		(*prtf)("%s, %s, %s or %s",
		    piecename[WQ],piecename[WR],piecename[WB],piecename[WN]);
		break;
	    case PR_NONE:
		(*prtf)("None");
		break;
	    }
	}
	if (Winitmoves != defopt[i][OP_WIMOVES] ||
	    Whitemoves != defopt[i][OP_WMOVES])
	{
	    (*prtf)("\nWhite Moves: ");
	    if (Whitemoves == 0 || Binitmoves == 0 || Blackmoves == 0)
		(*prtf)("Progressive (%d on first turn)",Winitmoves);
	    else
	    {
		(*prtf)("%d",Whitemoves);
		if (Winitmoves != Whitemoves)
		    (*prtf)(" (%d on first turn)",Winitmoves);
	     }
	}
	if (Binitmoves != defopt[i][OP_BIMOVES] ||
	    Blackmoves != defopt[i][OP_BMOVES])
	{
	    (*prtf)("\nBlack Moves: ");
	    if (Whitemoves == 0 || Binitmoves == 0 || Blackmoves == 0)
		(*prtf)("Progressive");
	    else
	    {
		(*prtf)("%d",Blackmoves);
		if (Binitmoves != Blackmoves)
		    (*prtf)(" (%d on first turn)",Binitmoves);
	    }
	}
	if (Tabiyat != defopt[i][OP_TABIYAT])
	    (*prtf)("\nMay %scross center on first turn",Tabiyat?"not ":"");
	if (Thrucheck != defopt[i][OP_THRUCHECK])
	{
	    (*prtf)("\n");
	    pkings(*prtf);
	    (*prtf)("may %smove thru check",Thrucheck?"":"not ");
	}
	if (Language != defopt[i][OP_NAMES])
	    (*prtf)("\nPiecenames: %s",langname[Language]);

	(*prtf)("\n");
	if (!Help_me)
	    (*prtf)("Computer Kibitzing: Off\n");
}

/* SCOREBOARD()
 *
 *   Print the score file in a slightly prettyed up format.  Variant games
 *   are listed separately from Chess games, for no special reason.  Visual
 *   mode not used here.  See the endgame() function for the format of the
 *   score file.
 */

scoreboard()
{
FILE *fp;
int n=0;
int i;

	if ((fp = fopen(GAME_LIST,"r")) != NULL)
	{
		for (i = 1; i <= HI_GAME; i++)
		{
			n += listgames(fp,i);
			rewind(fp);
		}
		n += listgames(fp,0);
		fclose(fp);
	}
	if (n == 0)
		printf("No games completed.\n");
}

listgames(fp,gametype)
FILE *fp;
char gametype;
{
char p1[10], p2[10];
char *player1=p1, *player2=p2;
char *tmp;
int count,i=0;

	while (fgetl(mbuffer,MB_LEN,fp))
		if (cti(mbuffer[26+OP_GAME]) == gametype)
		{
			sscanf(mbuffer+2,"%s %s %d",player1,player2,&count);
			setopts(mbuffer+26);
			if (++i == 1)
				printf("\n%s Games:\n-----------------------------------------------------------\n",typename[gametype]);

			if (mbuffer[0] == 'L')
			{
				tmp = player1; player1 = player2; player2 = tmp;
				mbuffer[0] = 'W';
				Firstwhite = !Firstwhite;
			}

			printf("%8s(%s) %s %s in %2d moves.\n",
			    player1,
			    (Firstwhite)?"white":"black",
			    (mbuffer[0]=='W')?"mated":"drew ",
			    player2, count);
		}
	return(i);
}

/* ENDGAME()
 *
 *   This routine wraps up a game.  The game file is removed, and the result
 *   is recorded in a scorefile.
 *
 *   The argument may be any of:  RE_WIN, RE_LOSE, RE_DRAW, RE_CANCEL
 *
 *    Scorefile entrys look like:
 *      W <name-1> <name-2> <cnt> <optlist>
 *      D <name-1> <name-2> <cnt> <optlist>
 *	^ ^        ^        ^     ^
 *      | |        |        |     |
 *      | |        |        |     +-- col 26 - Options in challenge line format.
 *      | |        |        |                  OP_COLOR is color of winner.
 *      | |        |        +-------- col 20 - Number of moves (5 digits).
 *      | |        +----------------- col 11 - Losers login name (8 columns).
 *      | +-------------------------- col  2 - Winners login name (8 columns).
 *      +---------------------------- col  0 - Win or Draw.
 */

endgame(type)
char type;
{
FILE *gp;
char tmpcolor;

	/* Remove Game file */
	unlink(fname);

	/* Make an entry in the score file */
	if (!solo && type != RE_CANCEL)
	    if ((gp=fopen(GAME_LIST,"a"))==NULL)
	    {
		printf("Cchess error:  Unable to append to scorefile %s\n",
			GAME_LIST);
	    }
	    else
	    {
		/* Temporarily change Firstcolor to Winnerscolor */
		tmpcolor = Firstwhite;
		if (type == RE_LOSE)
		{
			fprintf(gp,"W %8.8s %8.8s %5d ", hisid, myid, movecnt);
			Firstwhite = (mycolor == BLACK);
		}
		else
		{
			fprintf(gp,"%c %8.8s %8.8s %5d ",
			     (type==RE_WIN) ? 'W' : 'D',
			     myid, hisid, movecnt);
			Firstwhite = (mycolor == WHITE);
		}
		saveopts(gp);
		Firstwhite = tmpcolor;
		fclose(gp);
	    }
}

/* DISP()
 *
 *   Display the board position, with the color <col> at the bottom.
 */

static char blacksquare;

disp(bd,col)
schar bd[R_SIZE][C_SIZE];
schar col;
{
	blacksquare = (Plain) ? '-' : '*';

	/* Use the bigboard option, if selected and there is room */
	if (usebigboard)
		dispbg(bd,col);
	else
		dispsm(bd,col);
}

static char smtopline[] = "-------------------------+";

dispsm(bd,col)
schar bd[R_SIZE][C_SIZE];
schar col;
{
int r,c;
int pac,pbc;
int par,pbr;

	/* Save some numbers for showat() to use when updating board */
	ind = (COLS - 1) / 2 - Cols - 4;
	botcol = col;

	/* Top Player's Name */
	clr();
	cprintf("%s (%s)", pcapcol(-col), (mycolor == col) ? hisid : myid);
	
	pac = lside(col);		/*  0 for white;  7 for black */
	pbc = rside(col)+col;		/*  8 for white; -1 for black */
	par = bside(col)-col;		/* -1 for white;  8 for black */
	pbr = tside(col);		/*  7 for white;  0 for black */

	/* Print the Letters across the Top */
	indent(ind + 4);
	for ( c=pac ; c != pbc ; c += col)
	{
		wputchar('A'+c);
		wputchar(' ');
	}

	/* Print Top Line */
	indent(ind + 2);
	wputchar('+');
	wprint(smtopline+22-2*Cols);

	/* Print the Board */
	for ( r=pbr ; r != par ; r -= col)
	{
		indent(ind);
		wprintf("%c | ",r+'1');
		for ( c=pac ; c != pbc ; c += col)
		{
			if (bd[r][c] && (!hidden || bd[r][c]*mycolor > 0))
				piece(bd[r][c]);
			else
				wputchar(1&(r+c)?'-':blacksquare);
			wputchar(' ');
		}
		if (commodore)
			wputchar('|');
		else
			wprintf("| %c",r+'1');
	}

	/* Print Bottom Line */
	indent(ind + 2);
	wputchar('+');
	wprint(smtopline+22-2*Cols);

	/* Print the Letters across the Bottom */
	indent(ind + 4);
	for ( c=pac ; c != pbc ; c += col)
	{
		wputchar('A'+c);
		wputchar(' ');
	}

	/* Bottom Player's Name */
	cprintf("%s (%s)", pcapcol(col), (mycolor != col) ? hisid : myid);
}


dispbg(bd,col)
schar bd[R_SIZE][C_SIZE];
schar col;
{
int r,c;
int pac,pbc;
int par,pbr;

	/* Save some numbers for showat() to use when updating board */
	ind = (COLS - 5*Cols - 16) / 2;
	botcol = col;

	clr();

	pac = lside(col);		/*  0 for white;  7 for black */
	pbc = rside(col)+col;		/*  8 for white; -1 for black */
	par = bside(col)-col;		/* -1 for white;  8 for black */
	pbr = tside(col);		/*  7 for white;  0 for black */

	/* Print the Letters across the Top */
	indent(ind - 7);
	wprintf("%-8.8s  +-",(mycolor == col) ? hisid : myid);
	for ( c=pac ; c != pbc ; c += col)
		wprintf("--%c--",'A'+c);
	wprintf("-+  %8.8s", pcapcol(-col));

	indent(ind + 3);
	wputchar('|');
#ifdef NOTERMCAP
	wprint(blanks(5*Cols +7));
#else
	cursor(ind + 5*Cols + 12,cy);
#endif NOTERMCAP
	wputchar('|');

	/* Print the Board */
	for ( r=pbr ; r != par ; r -= col)
	{
		indent(ind);
		wprintf("%c  | ",r+'1');
		for ( c=pac ; c != pbc ; c += col)
		{
			if (bd[r][c] && (!hidden || bd[r][c]*mycolor > 0))
			{
				wputchar(' ');
				piece(bd[r][c]);
				wputchar(' ');
			}
			else
				wprintf("  %c  ",1&(r+c)?'-':blacksquare);
		}
		wprintf(" |  %c",r+'1');

		indent(ind + 3);
		wputchar('|');
#ifdef NOTERMCAP
		wprint(blanks(5*Cols +7));
#else
		cursor(ind + 5*Cols + 12,cy);
#endif NOTERMCAP
		wputchar('|');
	}

	/* Print Bottom Line */
	indent(ind - 7);
	wprintf("%-8.8s  +-",(mycolor != col) ? hisid : myid);
	for ( c=pac ; c != pbc ; c += col)
		wprintf("--%c--",'A'+c);
	wprintf("-+  %8.8s", pcapcol(col));

}

#ifndef NOTERMCAP
/* UPDATE()
 *
 *   Change the currently displayed board <ob> to the new board <nb>.
 *   Only smart terminals should be in this routine.
 */

update(ob,nb)
schar ob[R_SIZE][C_SIZE];
schar nb[R_SIZE][C_SIZE];
{
int r,c;
schar op,np;

	for (r = 0; r <= Rows; r++)
		for (c = 0; c <= Cols; c++)
		{
			if (hidden && !kibitz)
			{
				op = (ob[r][c]*mycolor < 0) ? SQ : ob[r][c];
				np = (nb[r][c]*mycolor < 0) ? SQ : nb[r][c];
			}
			else
			{
				op = ob[r][c];
				np = nb[r][c];
			}
			if (op != np)
				showat(r,c,np);
		}
	if (usebigboard)
		cursor(1,2*Rows+6);
	else
		cursor(1,Rows+8);
}


/* SHOWAT()
 *
 *   Show piece <p> at position <r> <c> on the currently displayed board.
 */

showat(r,c,p)
REGISTER int r,c;
schar p;
{
register int par;

	if (botcol == BLACK)
	{
		c = Cols - c;
		par = Cols;
	}
	else
	{
		r = Rows - r;
		par = Rows;
	}
	if (usebigboard)
	{
		cursor(ind + 7 + 5*c, 2*r + 3);
		if (p == SQ)
			wprintf(" %c ", 1&(r+c+par)?'-':blacksquare);
		else
			piece(p); 
	}
	else
	{
		cursor(ind + 5 + 2*c, r + 4);
		if (p == SQ)
			wputchar(1&(r+c+par)?'-':blacksquare);
		else
			piece(p); 
	}
}
#endif NOTERMCAP


/* PIECE()
 *
 *	Draw a piece for the current board, with highlighting of white pieces.
 *	We don't highlight on the small board: it looks crummy.
 */

static char bgpc[] = "  ++**<>??][..xx><##++$$";

piece(p)
{
char *c;

	if (usebigboard)
	{
		c = bgpc + 2 * abs(p);
		wputchar(*c++);
		if (p > 0) beg_so();
	}
	wputchar(pc[p+PIECES]);
	if (usebigboard)
	{
		if (p > 0) end_so();
		wputchar(*c);
	}
}


/* LIST()
 *
 *   List all existing game files.  Just reads in the directory and lists all
 *   the filenames.  Needs prettying up. Visual mode not used here.  If userid
 *   is positive, only games involving that user are printed.
 */
   
list(userid)
REGISTER int userid;
{
int uid1,uid2;
DIR *fp;
int n;
char *pwname;
register struct direct *gfd;

	if ((fp = opendir(CCDIR))== 0)
	{
		printf("Panic: unable to read %s directory\n",CCDIR);
		return;
	}
	n = 0;
	igpwuid();
	while ((gfd = readdir(fp)) != NULL)
		if (gfd->d_name[0] != '.' &&
		   sscanf(gfd->d_name,"%d.%d",&uid1,&uid2)==2 &&
		   (userid < 0 || uid1 == userid || uid2 == userid))
		{
			if ((pwname=gpwuid(uid1)) == 0)
				printf("uid %d vs ",uid1);
			else
				printf("%s vs ",pwname);
			if ((pwname=gpwuid(uid2)) == 0)
				printf("uid %d\n",uid2);
			else
				printf("%s\n",pwname);
			n++;
		}
	endpwent();  /* close the password file */
	if (n == 0) printf("None\n");
}


/*	LDBOARD
 *
 *	This routine reads in the game file and puts the board into the
 *	current position.  The first line in the file should be the version
 *	line, which looks like:
 *
 *	#####:V 0.19
 *        ^   ^  ^
 *	  |   |  |
 *	  |   |  +----- version number.
 *        |   +-------- character "V" identifies this as a version line.
 *	  +------------ Day the challenge was issued.
 *
 *	The next lines in the file should be challenge lines, which are
 *	formatted as:
 *
 *	#####:C code-string...
 *	  ^   ^      ^
 *	  |   |      |
 *	  |   |      +------- The option[] array in ascii, one character per.
 *	  |   +-------------- Challenge line code letter 'C' in column one.
 *        +------------------ Day that the challenge was issued.
 *	
 *	Only the last Challenge line before an accept line is relevant.
 *	The accept line is simply a line with the letter 'A' in column
 *	one.  After the accept line, move lines may appear.  Move lines
 *	look like:
 *
 *      #####:M fr-to comments
 *        ^   ^^^     ^
 *        |   |||     |
 *        |   |||     +------ Any comments by the player.
 *        |   ||+------------ The move in a modified algebraic notation.
 *        |   |+------------- Space.  C=Check, M=Checkmate, S=Stalemate
 *        |   |                       R=Repeated Position, F=Stripped forces.
 *        |   +-------------- The 13th letter of the alphabet.
 *	  +------------------ Day that the move was made.
 *
 *      The first move line is for the white player, and thereafter they
 *      alternate.  The single space before the comment should be there only
 *      if the comment is non-null.  Moves which place a pawn into the other
 *      player's home row should be immediately followed by a place line
 *      specifying the promotion to be made.
 *
 *	Move lines of the same format as above, but with a lower-case
 *	'm' are used in variants where multiple moves are made in one
 *	player's turn.  Only the last move has a capitol 'M'.  The rest
 *	are lower case (and normally don't have comments on them).
 *
 *      Illegal move lines are only used in Kriegspiel.  One is entered for
 *      each illegal move attempted.  Their format is similar to legal moves,
 *      but they never have comments:
 *
 *      #####:I fr-to
 *        ^   ^ ^
 *        |   | |
 *        |   | +------------ The move in a modified algebraic notation.
 *        |   +-------------- The 9th letter of the alphabet.
 *        +------------------ Day that the move was made.
 *
 *      A place line may be anywhere.  They are used to add or delete a piece
 *      from the board.  This is used in variant setups, and in pawn promotion.
 *      Place lines should never have comments or trailing spaces.
 *
 *      #####:P p-rc
 *        ^   ^ ^ ^
 *        |   | | |
 *     	  |   | | +------- The coordinates the piece is to be put at
 *     	  |   | +--------- The name of the piece (or space to delete)
 *     	  |   +----------- The 16th letter of the alphabet.
 *	  +--------------- Day that the place line was entered.
 * 
 *      Five other types of lines may appear.  A line begining with 'D' means
 *      the player has proposed a draw.  A draw line must be followed by a 'N'
 *      (reject) line if the game is to continue, or an 'Y' (accept) line if
 *      the draw is accepted.  A line begining with a 'K' means the player
 *	has proposed that the game be cancelled.  A line begining with a 'F'
 *	means the player has forfeited.  All these lines may have a comment
 *      begining in the same column as in the 'M' line's comment, and a day
 *      in the usual place.
 *
 *      Besides these, there may be reminder lines.  These have nothing to
 *	do with the game, but are inserted by cchess each time that a reminder
 *	is sent to one of the players.  They are solely for internal use.
 */

ldboard()
{
register schar corder;	/* -1 if odd number of challenges issued.  Else 1 */
int fr,fc,tr,tc;
char probuf[15];
char issetup=FALSE;
int ill;
register char *tmb;
	
    corder = 1;
    for (;;)
    {
	if (fgetl(sbuffer,MB_LEN,rfp)==NULL)
	{
		/* Was this from a compatible cchess version? */
		if (    strcmp(file_version,version)
#ifdef COMPAT018
		     && strcmp(file_version,"0.18")
#endif COMPAT018
						     )
		{
			wprint("Format error:  Unknown game file version\n");
			done(1);
		}
		return;
	}
	tmb = mbuffer; mbuffer = sbuffer; sbuffer = tmb;

	switch (mbuffer[C_CMD])
	{
	case 'V':	/* version line */
		strncpy(file_version,mbuffer+C_CMD+2,6);
		file_version[5] = '\0';
		break;
	case 'R':	/* reminder line - ignore */
		sbuffer = mbuffer; mbuffer = tmb;
		break;

	case 'C':	/* read challenge line */

		if (status > 1)
		{
			wprint("Format error:  Challenge after accept.\n");
			done(1);
		}
		status = 1;

		/* Read the challenge line options in */
		setopts(&mbuffer[C_CMD+2]);

		mycolor = (Firstwhite) ? order : -order;
		corder = -corder;
		toplay = (corder == order) ? mycolor : -mycolor;

		if (Oldcastle)
			wccq = wcck = bccq = bcck = FALSE;

		piecename = chessname[Language];

		hidden = Kriegspiel;

		/* Initialize board */
		if (!issetup)
		{
			copy(ib,b);
			issetup = TRUE;
		}

		lastday = atol(mbuffer+C_DAY);
		break;

	case 'A':	/* read accept line */
		status = 3;
		if (Private && kibitz)
		{
			wprintf("Game between %s and %s is private.\n",
				myid,hisid);
			done(0);
		}

		/* For debugging - make non-private kriegspiel visible */
		if (kibitz) hidden = FALSE;

		toplay = WHITE;
		movecnt = 0;
		playcnt = 0;
		ill = 0;

		if (Winitmoves == MO_PROGRESS || Binitmoves == MO_PROGRESS ||
		    Whitemoves == MO_PROGRESS || Blackmoves == MO_PROGRESS )
		{
			consmoves = (Winitmoves == MO_PROGRESS)?1:Winitmoves;
			Whitemoves = MO_PROGRESS;
		}
		else
			consmoves = Winitmoves;

		lastday = atol(mbuffer+C_DAY);
		break;

	case 'I':   /* Illegal move made */
		ill++;
		break;

	case 'M':   /* Move made */
	case 'm':
		if (status != 3)
		{
			wprint("Format error:  Move out of sequence.\n");
			done(1);
		}
		if (mconv(mbuffer+C_MOV,&fr,&fc,&tr,&tc))
		{
			makemove(b,toplay,fr,fc,tr,tc,TRUE);
			if (istame)
				tamemoves++;
			else
				tamemoves = 0;
			if (promote)
			{
				if (fgetl(probuf,14,rfp)==NULL)
				{
				      wprint("Format error:  No promotion.\n");
				      done(1);
			        }
				b[tr][tc] = promote =
				  toplay*(PIECES-(index(pc,probuf[C_MOV])-pc));
			}
		}
		else
		{
			wprint("Format error:  Bad move syntax.\n");
			done(1);
		}
		incheck = (mbuffer[C_MAT] == 'C' || mbuffer[C_MAT] == 'M');
		inmate  = (mbuffer[C_MAT] == 'M' || mbuffer[C_MAT] == 'S');
		repeated = (mbuffer[C_MAT] == 'R');
		stripped = (mbuffer[C_MAT] == 'F');
		if (mbuffer[C_CMD] == 'M')
		{
			playcnt++;
			movecnt++;
			toplay = -toplay;	/* Other color plays next */

			if (Whitemoves == MO_PROGRESS)
				consmoves++;
			else if (movecnt == 1)
				consmoves = Binitmoves;
			else if (toplay == WHITE)
				consmoves = Whitemoves;
			else
				consmoves = Blackmoves;

			consmade = 0;

			illmoves = ill;
			ill = 0;
		}
		else
			consmade++;
		lastday = atol(mbuffer+C_DAY);
		break;

	case 'P':  /* Place Piece */
		issetup = FALSE;
		if (!place(b,mbuffer[C_MOV],mbuffer+C_MOV+2))
		{
			wprint("Format error:  Bad place syntax.\n");
			done(1);
		}
		break;

	case 'D':  /* Draw Proposed */
		if (status != 3)
		{
			wprint("Format error:  Draw at strange time.\n");
			done(1);
		}
		status = 4;
		playcnt++;
		toplay = -toplay;
		lastday = atol(mbuffer+C_DAY);
		break;

	case 'K':  /* Cancellation Proposed */
		if (status != 3)
		{
		    wprint("Format error:  Cancellation at strange time.\n");
		    done(1);
		}
		status = 7;
		toplay = -toplay;
		playcnt++;
		lastday = atol(mbuffer+C_DAY);
		break;

	case 'N':  /* Draw or Cancellation Rejected */
		if (status != 4 && status != 7)
		{
			wprint("Format error:  Unproposed draw rejected.\n");
			done(1);
		}
		status = 3;
		playcnt++;
		toplay = -toplay;
		lastday = atol(mbuffer+C_DAY);
		break;

	case 'Y':  /* Draw or Cancellation Accepted */
		if (status != 4 && status != 7)
		{
			wprint("Format error:  Unproposed draw accepted.\n");
			done(1);
		}
		status = status + 1;
		playcnt++;
		toplay = -toplay;
		lastday = atol(mbuffer+C_DAY);
		break;

	case 'F':  /* Forfeit */
		if (status != 3 )
		{
			wprint("Format error:  Forfeit out of sequence.\n");
			done(1);
		}
		status = 6;
		playcnt++;
		toplay = -toplay;
		lastday = atol(mbuffer+C_DAY);
		break;
	default:
		wprint("Format error:  Weird line.\n");
	}
    }
}

/*  PLACEBOARD
 *
 * Find the differences between the initial board and the board <bd>
 * and add place lines to the gamefile to make it.
 */

placeboard(bd)
schar bd[R_SIZE][C_SIZE];
{
int i,j;

	for (i=0; i <= Rows; i++)
		for (j=0; j <= Cols; j++)
			if (bd[i][j] != ib[i][j])
				fprintf(wfp,"%5ld:P %c-%c%c\n", day(),
				    pc[PIECES+bd[i][j]], j+'A', i+'1');
}

/* SETOPTS()
 *
 *    Set the game options based on the given string.  If the string ends
 *    prematurely, try to recover by using the default options for that
 *    game for the rest of the string.
 */

setopts(s)
char *s;
{
int i;

	for (i=0; i<OPTIONS; i++,s++)
	{
		option[i] = cti(*s);
		
		if (option[i] < 0 || option[i] > maxopt[i])
			/*
			 * If we reached the end of the line, then use the
			 * default options for the rest.  This is so options
			 * can be added in the future without having to fix
			 * old game files.  Otherwise, print an error message.
			 */
			if (i > OP_GAME && (*s == '\0' || *s == '\n'))
			{
				for (; i<OPTIONS; i++)
					option[i] = defopt[option[OP_GAME]][i];
				break;
			}
			else
			{
				printf("Error - Option %d out of range\r\n",i);
				done(1);
			}
	}
#ifdef COMPAT018
	if (!strcmp(file_version,"0.18") && Capture > 2) Capture++;
#endif COMPAT018
}

/* SAVEOPTS
 *
 *    Write the current options to the file <fp>.  One character is used
 *    for each option and a newline is written last.
 */

saveopts(fp)
FILE *fp;
{
int i;
char ch;

	for (i=0; i<OPTIONS; i++)
	{
		if (option[i] < 10)
			ch = '0' + option[i];
		else
			ch = 'A' + option[i] - 10;
		putc(ch,fp);
	}
	putc('\n',fp);
}

cti(c)
char c;
{
	if (c <= '9')
		return(c-'0');
	else
		return(c-'A'+10);
}


/* PLACE()
 *
 *   Place a piece.  return TRUE if syntax is ok.
 */

boolean place(bd,type,coord)
schar bd[R_SIZE][C_SIZE];
char type;
char *coord;
{
int i,r,c;

	for (i=0; pc[i] != 0 && pc[i] != type; i++);
	if (pc[i] == 0) return (FALSE);

	c = coord[0] - ((coord[0] >= 'a') ? 'a' : 'A');
	r = coord[1] - '1';

	if ( r < 0 || c < 0 || r > Rows || c > Cols ) return(FALSE);

	bd[r][c] = i - PIECES;
	return(TRUE);
}


/* MCONV()
 *
 *   Convert a character string <buf> to a move.
 *   Return FALSE if the syntax is bad.
 */

mconv(buf,fr,fc,tr,tc)
char *buf;
int *fr,*fc,*tr,*tc;		/* from (row, column) to (row, column) */
{
	if (buf[0] >= 'a')
		*fc = buf[0] - 'a';
	else	*fc = buf[0] - 'A';
	*fr = buf[1] - '1';
	if (buf[3] >= 'a')
		*tc = buf[3] - 'a';
	else	*tc = buf[3] - 'A';
	*tr = (buf[4] - '1');

	if ( (*fr > Rows) || (*tr > Rows) || (*tc > Cols) || (*fc > Cols) ||
	     (*fr < 0) || (*tr < 0) || (*tc < 0) || (*fc < 0) )
	{
		errcode = E_SY;
		return(FALSE);
	}
	
	return(TRUE);
}


/* CCTRANS()
 *
 *   Print a cchess style transcript of the game to the output device
 *   <tfp>.  Include comments if the flag <comments> is TRUE.  ttymodes
 *   should be normal when this is called.
 */

static char tbuf[81];		/* Buffer for transcript line */
static int fc;			/* Field counter 1=white, 2=black, 3=comment */
static int omovecnt;		/* Last move printed */

cctrans(tfp,comments,masked)
FILE *tfp;
boolean comments,masked;
{
boolean private,illegal = FALSE;

    fc = 0;
    omovecnt = movecnt = -1;
    rewind(rfp);

    while (fgetl(mbuffer,MB_LEN,rfp)!=NULL)

	switch (mbuffer[C_CMD])
	{
	case 'C':	/* read challenge line */

		if (cti(mbuffer[C_MOV+OP_COLOR]))
			mycolor = order * WHITE;
		else
			mycolor = order * BLACK;

		piecename = chessname[cti(mbuffer[C_MOV+OP_NAMES])];
		private = (boolean) cti(mbuffer[C_MOV+OP_PRIVATE]);
		illegal = (boolean) cti(mbuffer[C_MOV+OP_VISIB]);
		hidden = illegal && masked;

		break;

	case 'A':	/* read accept line */

		/* Ask if illegal moves should be printed */
		if (illegal)
		{
			wprint("Do you want illegal moves included? ");
			illegal = enterdyn(FALSE);
			
		}
		clr();
		if (private && kibitz)
		{
			wprint("Sorry, that is a private game.\n");
			return;
		}

		/* Return to normal tty modes */
		resetty();

		fprintf(tfp,"     WHITE    BLACK\n     %-8s %-8s\n",
			mycolor==WHITE ? myid:hisid,
			mycolor==BLACK ? myid:hisid);
		if (comments)
			fprintf(tfp,"------------------------------------------------------------------------------\n");
		else
			fprintf(tfp,"---------------------\n");
			
		toplay = WHITE;
	        movecnt = 0;
		break;

	case 'P':
		if (movecnt >= 0)
		{
			sprintf(sbuffer,"(Pawn promoted to %s)",
			    piecename[PIECES-(index(pc,mbuffer[C_MOV])-pc)]);
			ptfcom(tfp,sbuffer);
		}
		break;

	case 'M':
		/* Don't show other player moves in kriegspiel */
		if (hidden && !kibitz && toplay != mycolor)
		{
			mbuffer[C_MOV+0] = '?'; mbuffer[C_MOV+1] = '?';
			mbuffer[C_MOV+3] = '?'; mbuffer[C_MOV+4] = '?';
		}
	case 'F':
	case 'D':
	case 'Y':
	case 'N':
	case 'K':
		if (!comments) mbuffer[C_FLG] = '\0';

		ptfmove(tfp,toplay,mbuffer+C_MOV,FALSE);

		if (mbuffer[C_FLG] != '\0')
			ptfcom(tfp,mbuffer+C_COM);

		++movecnt;
		toplay = -toplay;	/* Other color plays next */
		break;
	case 'I':
		if (!illegal || (hidden && !kibitz && toplay != mycolor))
			break;
	case 'm':
		/* Don't show other player moves in kriegspiel */
		if (hidden && !kibitz && toplay != mycolor)
		{
			mbuffer[C_MOV+0] = '?'; mbuffer[C_MOV+1] = '?';
			mbuffer[C_MOV+3] = '?'; mbuffer[C_MOV+4] = '?';
		}
		/* Print the move */
		ptfmove(tfp,toplay,mbuffer+C_MOV,mbuffer[C_CMD] == 'I');
		break;
	}
	/* Flush last line out */
	if (fc > 0)
		fprintf(tfp,"%s\n",tbuf);
}

ptfmove(tfp,co,mv,ill)
FILE *tfp;
schar co;
char *mv;
boolean ill;
{
char *c;

	/* Print previous line if new field doesn't fit on */
	if (fc > (co == BLACK))
	{
		fprintf(tfp,"%s\n",tbuf);
		fc = 0;
	}

	if (co == WHITE)
	{
		/* Print number if different from last number printed */
		if (movecnt != omovecnt)
			sprintf(tbuf,"%3d:",(omovecnt = movecnt)/2+1);
		else
			strcpy(tbuf,blanks(4));

		c = tbuf+4;
		fc = 1;
	}
	else
	{
		/* Pad with blanks if necessary */
		if (fc < 1)
			strcpy(tbuf,blanks(11));
		tbuf[11] = tbuf[12] = ' ';
		c = tbuf+13;
		fc = 2;
	}
	/* punch the move into the buffer */
	sprintf(c, ill ? "(%5.5s)" : " %5.5s ", mv);
}

ptfcom(tfp,com)
FILE *tfp;
char *com;
{
register int i,j;

	/* Print previous line if new field doesn't fit on */
	if (fc > 2)
	{
		fprintf(tfp,"%s\n",tbuf);
		fc = 0;
	}

	/* Pad up to comments column with blanks */
	i = (fc == 0) ? 22 : ((fc == 1) ? 11 : 2);
	strcpy(tbuf+22-i,blanks(i));
	fc = 3;

	/* Put the comment in place */
	if (strlen(com) > 56)
	{
		for (i = 56; i > 0 && com[i] != ' '; i--)
			;
		if (i == 0)
		{
			i = 56;
			j = 0;
		}
		else
			j = 1;
		strncpy(tbuf+22,com,i);
		tbuf[23+i] = '\0';
		ptfcom(tfp,com+i+j);
	}
	else
		strcpy(tbuf+22,com);
}

/* PCOL(), PMAN(), PCOLMAN()
 *
 * These are routines to write out the names of colors and men.
 */

char *pcol(p)
schar p;
{
	if (p == 0)
		return("");
	else
		return((p > 0)?"White":"Black");
}

char *pcapcol(p)
schar p;
{
	if (p == 0)
		return("");
	else
		return((p > 0)?"white":"BLACK");
}

char *pman(p)
schar p;
{
	return (piecename[abs(p)]);
}

char *pcolman(p)
schar p;
{
static char buf[18];

	if (p == 0) return(piecename[p]);
	sprintf(buf,"%s %s", ((p > 0)?"White":"Black"), piecename[abs(p)]);
	return(buf);
}

char *yorn(f)
boolean f;
{
	return(f?"Yes":"No");
}