|
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"); }