|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 31437 (0x7acd)
Types: TextFile
Names: »misc.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Cchess/misc.c«
/* 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");
}