games-request@tekred.TEK.COM (03/02/88)
Submitted by: Jan Wolter <janc@crim.eecs.umich.edu> Comp.sources.games: Volume 3, Issue 87 Archive-name: cchess/Part02 #! /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 2 (of 5)." # Contents: cmd.c play.c # Wrapped by billr@tekred on Tue Jan 12 12:09:52 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f cmd.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cmd.c\" else echo shar: Extracting \"cmd.c\" \(24364 characters\) sed "s/^X//" >cmd.c <<'END_OF_cmd.c' X/* CCHESS USER INTERFACE version 1.00 X * X * (C) Copyright - Jan D. Wolter - Apr 1986 X * X * Mostly routines to talk to the user. X */ X X#include "cchess.h" X X#ifndef NOTERMCAP Xextern char *DL; X#endif NOTERMCAP X Xint mredraw; /* flag used for redrawing while reading in move */ X X/* DOMOVE() X * X * This is the move mode driver. Show board and command menu. Accept X * move, forfiet, draw, and playback commands. This is the real center of X * the program. X * X * If <drawp> is RE_DRAW, then a draw has been proposed, and the options are X * to accept or reject the draw. If <drawp> is RE_CANCEL, then a cancelation X * has been proposed, and the same commands are available. X */ X Xdomove(drawp) Xint drawp; X{ Xint fr,fc,tr,tc; Xint row,col; Xchar new_move[15]; Xchar ch; Xschar took,p; Xboolean thru,himcheck,checked,firsttime=TRUE; Xint i; X X new_move[C_CMD] = 'M'; X new_move[C_MAT] = ' '; X X myillmoves = 0; X scrolled = TRUE; X mredraw = 0; X must_take = Musttake && canmove(b,mycolor,TRUE); X X /* Loop until he is satisfied with a command */ X for (;;) X { X#ifndef NOTERMCAP X /* make sure there is room for an error message */ X if (moveok && errcode != E_OK && errcode != E_SY) X { X if (!DL && cy == LINES) X wputchar('\n'); X } X else X errcode = E_OK; X#endif NOTERMCAP X X /* draw board - "scrolled" basically just tells us to do so */ X if (scrolled) X { X disp(b,kibitz?WHITE:mycolor); X printmov(mbuffer,illmoves,(mycolor == toplay) ? hisid : myid); X printcom(); X wputchar('\n'); X if (cy >= LINES) X msgarea = LINES - 1; X else X msgarea = cy; X } X X /* Prompt for a command */ X if (!moveok) X { X /* Not allowed to move - Playback or nothing */ X if (!kibitz) wprint("It's not your turn to move.\n"); X wprint("Do you want a playback? "); X ch = xenter("YNVOL\014"); X if (ch == 'Y') X { X ch = 'P'; X wprint("Yes\n"); X } X if (ch == 'N') X { X ch = 'Z'; X wprint("No\n"); X } X } X else if (drawp == RE_NONE) X { X /* Normal case - Get a move command */ X if (errcode != E_OK) X { X prterror(); X wputchar('\n'); X } X errcode = E_OK; X if (firsttime) X { X if (movecnt < 2) X wprint("Help, "); X else if (tamemoves >= MAXTAME) X wprint("Under the 50-move rule, you may unilaterally declare a draw.\n"); X firsttime = FALSE; X } X wprint("Move, Playback, Forfeit or Draw? "); X if (mredraw > 0) X ch = 'M'; X else X ch = xenter("MPFDECQVH?OL\014"); X } X else X { X /* A draw or cancellation has been proposed */ X if (drawp == RE_DRAW) X wprint("A draw"); X else X wprint("A cancellation"); X wprint(" has been proposed.\nAccept or Reject? "); X ch = xenter("PARVEQOL\014"); X } X X switch (ch) X { X case 'H': X case '?': X wprint("Help\n"); X X initmore(); X mprint("Move - Enter a chess move\n"); X mprint("Playback - View a replay of previous moves\n"); X mprint("Forfeit - Admit that the other player won\n"); X mprint("Draw - Propose that the game be a draw\n"); X mprint("Last - Display date of last move made\n"); X mprint("Options - Display the current game options\n"); X mprint("^L - Redraw the screen\n"); X mprint("Exit - Exit the program without moving\n"); X mprint("Cancel - Propose that the game be abandoned\n"); X break; X X case 'L': X wprintf("Last move made on %s\n", cday(lastday)); X break; X X case 'O': X wprint("Options\n"); X initmore(); X printopts(mprintf); X break; X X case 'M': X wprint("Move\n"); X ++consmade; X took = taken; X checked = incheck; X X /* Get his move */ X mget(mycolor,new_move+C_MOV,&fr,&fc,&tr,&tc); X if (mredraw > 0) X { X scrolled = TRUE; X --consmade; X break; X } X X /* If it's an illegal move, give it up */ X if (!(thru = (errcode==E_MC && consmade < consmoves && Thrucheck))) X { X if (errcode == E_OK) X wputchar('\n'); X else X { X consmade--; X break; X } X } X X /* Test if other player is in check */ X if (Kingpiece(-mycolor) != SQ) X { X find(bc,Kingpiece(-mycolor),&row,&col); X himcheck = check(bc,mycolor,row,col); X } X else X himcheck = FALSE; X X /* Has enemy been stripped of all forces? */ X if (Stripresult != RE_NONE && taken != SQ && !forces(-mycolor,bc)) X { X stripped = TRUE; X wprint("Capture of all enemy pieces "); X switch (Stripresult) X { X case RE_LOSE: X wprintf("is a win for you.\n"); X break; X case RE_WIN: X wprintf("is a win for the other player.\n"); X break; X case RE_DRAW: X wprintf("forces a draw.\n"); X break; X } X } X else if (consmade < consmoves) X { X /* May not apply check until last move */ X if (himcheck) X { X errcode = E_MM; X consmade--; X break; X } X repeated = inmate = FALSE; X incheck = thru; X } X else X { X /* Test if other player is in mate */ X incheck = himcheck; X inmate = !canmove(bc,-mycolor,FALSE); X X /* How often has this position has occured? */ X if (inmate || !istame || tamemoves >= MAXTAME-1) X repeated = FALSE; X else X repeated = isrepeat(b,bc); X } X Xdispnew: /* Display the new position */ X#ifndef NOTERMCAP X if (!scrolled && issmart && (!Kriegspiel || !inmate)) X doupdate(b,bc,new_move,TRUE); X else X { X#endif NOTERMCAP X if (inmate) hidden = FALSE; X disp(bc, kibitz ? WHITE : mycolor); X printmov(new_move,myillmoves,hisid); X printcom(); X wputchar('\n'); X#ifndef NOTERMCAP X } X#endif NOTERMCAP X /* Warn him about effects of stalemate */ X if (inmate && !incheck) X { X wprint("Stalemate "); X switch(Staleresult) X { X case RE_WIN: X wprint("is a win for the other player.\n"); X break; X case RE_LOSE: X wprint("is a win for you.\n"); X break; X case RE_DRAW: X wprint("forces a draw.\n"); X break; X } X } X X /* Let him declare a draw under fifty move rule */ X if (repeated) X { X wprint("This position has occurred twice before.\n"); X wprint("Would you like to declare a draw?"); X repeated = (enteryn()); X } X X /* Give him a chance to change his mind */ X if (!Kriegspiel) X { X if (Help_me && (consmade == consmoves) && X (p = compkib(bc,mycolor)) != SQ) X wprintf("Your %s may be at risk.\n", piecename[p]); X X wprint("Are you sure? "); X if ((ch = enter("YN\014")) == '\014') X { X /* Redraw the screen */ X scrolled = TRUE; X goto dispnew; X } X if (ch == 'N') X { X /* Don't make this move after all */ X wprint("o\n"); X taken = took; X incheck = checked; X consmade--; X inmate = FALSE; X stripped = FALSE; X errcode = E_OK; X#ifndef NOTERMCAP X if (issmart) X doupdate(bc,b,mbuffer,FALSE); X else X#endif NOTERMCAP X scrolled = TRUE; X break; X } X else X wprint("es\n"); X } X X savemove((consmoves == consmade || stripped)?'M':'m', X new_move+C_MOV); X X /* Finish off ended games */ X if (inmate || repeated || stripped) X { X copy(bc,b); /* So playbacks will work right */ X if (incheck && inmate) X askplayback(RE_WIN,EV_CHECKMATE); X else if (inmate) X askplayback(flip(Staleresult),EV_STALEMATE); X else if (stripped) X askplayback(flip(Stripresult),EV_FORCES); X else X askplayback(RE_DRAW,EV_REPEATED); X asktrans(); X return; X } X if (consmoves == consmade) X return; X else X { X /* Multi-move game: ask him for another */ X errcode = E_OK; X copy(bc,b); X must_take = Musttake && canmove(b,mycolor,TRUE); X break; X } X X case 'F': X wprint("Forfeit\nDo you want to forfeit? "); X if (!enteryn()) break; X X if (Kriegspiel) X { X hidden = FALSE; X disp(bc, kibitz ? WHITE : mycolor); X printmov(new_move,myillmoves,hisid); X printcom(); X wputchar('\n'); X } X X savemove('F',"forf "); X askplayback(RE_LOSE,EV_FORFIET); X asktrans(); X return; X X case 'D': /* Propose Draw */ X wprintf("Draw\nDo you want to %s a draw? ", X (tamemoves >= MAXTAME)?"declare":"propose"); X if (!enteryn()) break; X X savemove('D',"draw?"); X X /* Unilateral if more than fifty moves have been made */ X if (tamemoves >= MAXTAME) X { X askplayback(RE_DRAW,EV_FIFTYMOVES); X asktrans(); X } X return; X X case 'C': /* Propose Cancelation */ X wprint("Cancel\n"); X wprint("Do you want to propose that this game be discarded? "); X if (!enteryn()) break; X savemove('K',"canc?"); X return; X X case 'A': /* Accept Draw or Cancellation */ X wprint("Accept\n"); X savemove('Y',"yes "); X askplayback(drawp,EV_AGREEMENT); X asktrans(); X return; X X case 'R': /* Reject Draw or Cancellation */ X wprint("Reject\n"); X savemove('N',"no "); X return; X X case 'Q': /* Quit */ X wprint("Quit\n"); X case 'E': /* Exit */ X if (ch == 'E') wprint("Exit\n"); X if (!interupt) X { X wprint("Sorry, not until you've moved..."); X break; X } X wprint("Do you really want to "); X if (eachgame) X wprint("skip to the next game? "); X else X wprint("exit the program? "); X if (!enteryn()) break; X X case 'Z': /* Exit without asking for confirmation */ X return; X X case 'P': /* Playback previous positions */ X if (moveok) wprint("Playback\n"); X if (playcnt == 0) X { X wprint("No moves to Playback.\n"); X break; X } X X wprintf("How many moves (1-%d) do you want replayed? ", X playcnt+(consmade > 0)); X if ((i=readint(playcnt + (consmade > 0))) > 0) X { X if (!issmart) wputchar('\n'); X playback(playcnt - i + (consmade > 0)); X } X X wputchar('\n'); X /* If move arrives during replay...experiment */ X if (!moveok && !kibitz && mycolor == toplay) X { X moveok = TRUE; X fseek(wfp,0L,2); X } X break; 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 } X} X X X X/* DOMATE() X * X * End a game. There has been a checkmate, or the game has been drawn. X * X * <what> is RE_WIN, RE_LOSE, RE_DRAW, or RE_CANCEL depending on what X * became of the current player. X * X * <why> is EV_CHECKMATE, EV_STALEMATE, EV_FORCES, EV_FIFTYMOVES, EV_REPEATED, X * or EV_AGREEMENT depending on why the game ended. X */ X Xdomate(what,why) Xchar what,why; X{ X disp(b,kibitz?WHITE:mycolor); X printmov(mbuffer,illmoves,(mycolor == toplay) ? hisid : myid); X printcom(); X X wputchar('\n'); X askplayback(what,why); X X if (moveok) X { X /* MUST do the endgame *before* the transcript, */ X /* curious though it seems. */ X endgame(what); X asktrans(); X } X} X X/* ASKPLAYBACK() X * X * Ask the player for a playback, and keep asking him until he doesn't want one. X * Print the message before asking each time. It displays both sides, even if X * the game is kriegspiel. It is only meant to be called after a game is over. X * X * <what> is RE_WIN, RE_LOSE, RE_DRAW, or RE_CANCEL depending on what X * became of the current player. X * X * <why> is EV_CHECKMATE, EV_STALEMATE, EV_FORCES, EV_FIFTYMOVES, EV_REPEATED, X * or EV_AGREEMENT depending on why the game ended. X */ X Xaskplayback(what,why) Xchar what,why; X{ Xstatic char tbuf[70]; Xboolean flag; Xint i; X X if (hidden) scrolled = TRUE; X hidden = FALSE; /* No reason to hide moves anymore */ X X switch (what) X { X case RE_WIN: X if (solo && !kibitz) X strcpy(tbuf,"Congratulations!\nYou have won"); X else X sprintf(tbuf,"%s has won", X (mycolor == toplay) ? myid : hisid); X break; X case RE_LOSE: X if (solo && !kibitz) X strcpy(tbuf,"You have lost"); X else X sprintf(tbuf,"%s has won", X (mycolor != toplay) ? myid : hisid); X break; X case RE_DRAW: X strcpy(tbuf,"The game is drawn"); X break; X case RE_CANCEL: X strcpy(tbuf,"The game is canceled"); X break; X } X switch (why) X { X case EV_CHECKMATE: X strcat(tbuf," by a checkmate."); X break; X case EV_STALEMATE: X strcat(tbuf," by a stalemate."); X break; X case EV_FORCES: X strcat(tbuf," by lose of forces."); X break; X case EV_FIFTYMOVES: X strcat(tbuf," under the fifty move rule."); X break; X case EV_REPEATED: X strcat(tbuf," because of repeated positions."); X break; X case EV_AGREEMENT: X strcat(tbuf," by mutual agreement."); X break; X case EV_FORFIET: X strcat(tbuf," by a forfieting."); X break; X } X X do X { X wprint(tbuf); X if (playcnt == 0 && consmade == 0) X { X wputchar('\n'); X return; X } X wprint("\nDo you want a playback? "); X if (flag = enteryn()) X { X wprintf("How many moves (1-%d) do you want replayed? ", X playcnt+(consmade > 0)); X if ((i=readint(playcnt + (consmade > 0))) > 0) X { X if (!issmart) wputchar('\n'); X playback(playcnt - i + (consmade > 0)); X wputchar('\n'); X } X } X } while (flag); X} X X#ifndef NOTERMCAP X/* DOUPDATE() X * X *Update() plus update the labels on the display. X * X */ X Xdoupdate(bo,bn,move,mine) Xschar bo[R_SIZE][C_SIZE], bn[R_SIZE][C_SIZE]; Xchar *move; Xboolean mine; X{ Xshort ox=cx, oy=cy; X X update(bo,bn); X printmov(move,mine?myillmoves:illmoves,mine?myid:hisid); X cursor(ox,oy); X} X#endif NOTERMCAP X X/* MGET() X * X * Read a possibly illegal move from the player. Set the error code if he X * Gave an illegal response. Note that E_SY can only result if he hits X * return prematurely. It is not really an error; it is used as a command X * cancellation. X */ X Xmget(co,buffer,fr,fc,tr,tc) Xchar *buffer; Xint *fr,*fc,*tr,*tc; /* from (row, column) to (row, column) */ Xint co; X{ Xchar ch; X X if (consmoves > 1) X wprintf("Enter your move (%d of %d): ",consmade,consmoves); X else X wprint("Enter your move: "); X if (mread(buffer)) X if (mconv(buffer,fr,fc,tr,tc) && X legal(co,*fr,*fc,*tr,*tc)) X { X if (promote) X { X /* Patch up pawn promotion */ X if (Promotion == PR_MINISTER) X /* Only Ministers can be promoted to */ X bc[*tr][*tc] = promote = WM*co; X else if (Promotion == PR_NONE) X /* Can't Promote */ X bc[*tr][*tc] = promote = WP*co; X else X { X /* Ask the player what to promote to */ X for(;;) X { X wputchar('\n'); X wprint("Promote pawn to: "); X if ((ch = xenter("QRBNK\014"))=='\014') X { X errcode = E_OK; X mredraw = 5; X return; X } X promote = PIECES-(index(pc,ch)-pc); X wprint(piecename[promote]); X if (promote != Kingtype(co)) X break; X wprint("\nCan't promote to mateable piece"); X } X X bc[*tr][*tc] = promote *= co; X } X } X errcode = E_OK; X return; X } X else /* Illegal move */ X { X /* Unless he should have know better, record it */ X if (Kriegspiel && X ( (errcode == E_CP) || (errcode == E_CT) || X (errcode == E_PI) || (errcode == E_QB) || X (errcode == E_BB) || (errcode == E_BR) || X (errcode == E_MC) || (errcode == E_MM) ) ) X { X interupt = FALSE; X myillmoves++; X fprintf(wfp,"%5ld:I %5.5s\n",day(),buffer); X } X wputchar('\n'); X } X else X if (mredraw == 0) X errcode = E_SY; X return; X} X X/* PERROR() X * X * Print error messages. Current error is given by the global errcode. X */ X X/* Three common messages */ Xstatic char kierrmsg[] = "Illegal Move."; Xstatic char kcerrmsg[] = "Can't Castle."; Xstatic char scerrmsg[] = "Castling has not been invented."; X Xprterror() X{ X /* If no error, do nothing */ X if (errcode == E_OK) return; X X wprint("Error: "); X X switch (errcode) X { X case E_MT: /* move from empty square */ X wprint("No friendly piece in starting square."); X break; X case E_AF: /* attack on friendly piece */ X wprint("Can't capture your own pieces."); X break; X case E_EQ: /* source and destination square are equal */ X wprint("Null move."); X break; X case E_SY: /* Move syntax error */ X wprint("Command syntax unrecognizable."); X break; X case E_CR: X wprint("Must capture if possible."); X break; X case E_NC: X wprint("Piece may not capture."); X break; X case E_CP: X if (Oldcastle) X wprint(scerrmsg); X else if (hidden) X wprint(kcerrmsg); X else X wprint("Not in position to castle."); X break; X case E_CM: X if (Oldcastle) X wprint(scerrmsg); X else X wprint("Can't castle after moving king or rook."); X break; X case E_CT: X if (Oldcastle) X wprint(scerrmsg); X else if (hidden) X wprint(kcerrmsg); X else X wprint("Can't castle through or out of check."); X break; X case E_MC: /* Move into Check */ X if (hidden) X wprint(kierrmsg); X else X wprint("Move leaves you in check."); X break; X case E_MM: /* No Check on Multi-Moves */ X if (hidden) X wprint(kierrmsg); X else X wprint("Can't apply check until last move."); X break; X case E_CC: /* Ta'biyat violation */ X wprint("Can't cross center on first turn."); X break; X case E_IL: /* Illegal move */ X wprint(kierrmsg); X break; X case E_KI: /* Illegal move of King or Jester */ X case E_JI: X wprintf("%s moves only to adjacent squares.", X piecename[errcode & 033]); X break; X case E_QI: /* Illegal move of Queen */ X wprintf("%s moves only along rows, columns and diagonals.", X piecename[WQ]); X break; X case E_BI: /* Illegal move of Bishop */ X wprintf("%s moves only along diagonals.",piecename[WB]); X break; X case E_NI: /* Illegal move of Knight */ X wprintf("%s moves two squares straight and one to the side.", X piecename[WN]); X break; X case E_RI: /* Illegal move of Rook */ X wprintf("%s moves only along rows or columns.",piecename[WR]); X break; X case E_PI: /* Illegal move of Pawn */ X if (hidden) X wprint(kierrmsg); X else X wprintf("%s moves forward or captures diagonally.", X piecename[WP]); X break; X case E_MI: /* Illegal move of Minister */ X wprintf("%s moves only to diagonally adjacent squares.", X piecename[WM]); X break; X case E_EI: /* Illegal move of Elephant */ X wprintf("%s moves two squares diagonally.",piecename[WE]); X break; X case E_DI: /* Illegal move of Duke */ X wprintf("%s moves only to orthogonally adjacent squares.", X piecename[WD]); X break; X case E_HI: /* Illegal move of Maharajah */ X wprintf("%s moves like knight or like queen.",piecename[WH]); X break; X case E_KB: /* Blocked move of Kamikazi King */ X if (hidden) X wprint(kierrmsg); X else X wprintf("%s can't capture in this version of chess.", X piecename[WK]); X break; X case E_QB: /* Blocked move of Queen */ X case E_BB: /* Blocked move of Bishop */ X case E_BR: /* Blocked move of Rook */ X case E_BH: /* Blocked move of Maharajah */ X if (hidden) X wprint(kierrmsg); X else X wprintf("%s can't jump over other pieces.", X piecename[errcode & 033]); X break; X default: X wprintf("Weird Error %d.",errcode); X } X} X X/* MREAD() X * X * Read a move from the terminal, return FALSE if player chickens out X * or asks for a redraw. In the latter case, mredraw is set. Supports X * backspaces. Sorry Edsger. X */ X Xchar nums[] = "87654321\b\n\014"; Xchar lets[] = "LKJIHGFEDCBA\b\n\014"; X Xmread(buffer) XREGISTER char *buffer; X{ Xregister int m; Xshort ox=cx; X X if (mredraw > 0) X { X m = mredraw; X mredraw = 0; X if (m == 1) goto n0; X wputchar(buffer[0]); X if (m == 2) goto n1; X wputchar(buffer[1]); X wputchar('-'); X if (m == 3) goto n2; X wputchar(buffer[3]); X if (m == 4) goto n3; X wputchar(buffer[4]); X return(TRUE); X } X Xn0: buffer[0] = enter(&lets[C_SIZE-1-Cols]); X switch (buffer[0]) X { X case '\b': X bell(); X wputchar(' '); X goto n0; X case '\014': X mredraw = 1; X case '\n': X return (FALSE); X } X Xn1: buffer[1] = enter(&nums[R_SIZE-1-Rows]); X switch (buffer[1]) X { X case '\b': X if (erases) X { X wputchar(' '); X backspace(); X } X else X indent(ox-1); X goto n0; X case '\014': X mredraw = 2; X case '\n': X return (FALSE); X } X X buffer[2] = '-'; X wputchar('-'); X Xn2: buffer[3] = enter(&lets[C_SIZE-1-Cols]); X switch (buffer[3]) X { X case '\b': X if (erases) X { X backspace(); X wprint(blanks(2)); X backspace(); X backspace(); X } X else X { X indent(ox-1); X wputchar(buffer[0]); X } X goto n1; X case '\014': X mredraw = 3; X case '\n': X return (FALSE); X } X Xn3: buffer[4] = enter(&nums[R_SIZE-1-Rows]); X switch (buffer[4]) X { X case '\b': X if (erases) X { X wputchar(' '); X backspace(); X } X else X { X indent(ox-1); X wputchar(buffer[0]); X wputchar(buffer[1]); X wputchar(buffer[2]); X } X goto n2; X case '\014': X mredraw = 4; X case '\n': X return (FALSE); X } X X return(TRUE); X} X X X/* PREAD() X * X * Read a position from the terminal, return FALSE if player chickens out. X * Supports backspaces. Sorry Edsger. X */ X Xpread(buffer) Xchar *buffer; X{ Xshort ox=cx; X Xn0: buffer[0] = enter(&lets[C_SIZE-1-Cols]); X if (buffer[0] == '\b') X { X bell(); X wputchar(' '); X goto n0; X } X if (buffer[0] == '\n') return (FALSE); X X buffer[1] = enter(&nums[R_SIZE-1-Rows]); X if (buffer[1] == '\n') return (FALSE); X if (buffer[1] == '\b') X { X if (erases) X { X wputchar(' '); X backspace(); X } X else X indent(ox-1); X goto n0; X } X return(TRUE); X} X X X/* PLAYBACK() X * X * Display a playback of the game. X */ X Xplayback(n) XREGISTER int n; X{ Xint fr,fc,tr,tc; Xregister int cnt,subcnt=0; Xint ill = 0; Xboolean wasmoveok; Xchar probuf[15]; Xchar c; Xboolean prompt = FALSE; Xboolean didmove = FALSE; X X if (n < 0) X { X wputchar('\n'); X return; X } X rewind(rfp); X wasmoveok = moveok; X moveok = FALSE; X /* Read in the initial placement */ X do X { X if (fgetl(mbuffer,MB_LEN,rfp)==NULL) X { X printf("Panic: No accept line\n"); X done(1); X } X if (mbuffer[C_CMD] == 'C') X copy(ib,bc); X else if (mbuffer[C_CMD] == 'P') X place(bc,mbuffer[C_MOV],mbuffer+C_MOV+2); X } while (mbuffer[C_CMD] != 'A'); X X cnt = 0; X toplay = WHITE; X for (;;) X { X /* Prompt the user */ X if (prompt) X { X cprint("*Hit return for next board:"); X c=xenter("\nQ\014"); X if (!issmart) wputchar('\n'); X if (c != '\n') X if (c == 'Q') X { X /* No more updates or prompts */ X n = playcnt + (consmade > 0); X prompt = FALSE; X } X else X { X /* Redraw the screen */ X disp(b,kibitz?WHITE:mycolor); X wprint("\n\n"); X continue; X } X } X X /* Display the position */ X if (cnt >= n || (cnt == playcnt && consmade == subcnt)) X { X#ifndef NOTERMCAP X if (cleardown && !scrolled) X { X update(b,bc); X if (didmove) X printmov(mbuffer,ill, X toplay == mycolor ? hisid : myid); X clbot(); X } X else X { X#endif NOTERMCAP X disp(bc,kibitz?WHITE:mycolor); X if (didmove) X printmov(mbuffer,ill, X toplay == mycolor ? hisid : myid); X#ifndef NOTERMCAP X } X#endif NOTERMCAP X prompt = TRUE; /* Prompt after a redraw */ X copy(bc,b); X if (cnt != 0) X printcom(); X else X wputchar('\n'); X } X X ill = 0; X /* Read until we find a move line */ X for( ; ; ) X { X if (fgetl(mbuffer,MB_LEN,rfp)==NULL) X { X moveok = wasmoveok; X return; X } X if (mbuffer[C_CMD] == 'I') X ill++; X else if (mbuffer[C_CMD] != 'R') X break; X } X didmove = TRUE; X X if (mbuffer[C_CMD] == 'm' || mbuffer[C_CMD] == 'M') X { X /* Checked or Mated? */ X incheck = (mbuffer[C_MAT] == 'C' || mbuffer[C_MAT] == 'M'); X inmate = (mbuffer[C_MAT] == 'M' || mbuffer[C_MAT] == 'S'); X X /* Play it on the board */ X if (mconv(mbuffer+C_MOV,&fr,&fc,&tr,&tc)) X { X makemove(bc,toplay,fr,fc,tr,tc,FALSE); X if (promote) X { X fgetl(probuf,14,rfp); X bc[tr][tc] = promote = X toplay*(PIECES-(index(pc,probuf[C_MOV])-pc)); X } X } X else X { X wprint("Format error: Bad move syntax.\n"); X done(1); X } X } X if (mbuffer[C_CMD] != 'm') X { X cnt++; X subcnt = 0; X toplay = -toplay; X } X else X subcnt++; X } X} X X/* ASKTRANS() X * X * Give him a transcript, if he wants one. X */ X Xasktrans() X{ X wprint("Do you want a transcript of the game? "); X if (enteryn()) trans(hidden); X} X X/* TRANS() X * X * Ask what sort of transcript he wants. In visual mode. X * If <masked> is true, don't print the other players moves. X */ X Xtrans(masked) X{ XFILE *tfp; Xchar tfile[80]; Xboolean comments; X X clr(); X wprintf("Printing transcript for game between %s and %s\n", X myid,hisid); X X /* Revert to self so output files can be opened */ X /* Note: Can't open game files any more after this */ X setuid(getuid()); X setgid(getgid()); X X /* Get output device */ X for (;;) X { X wprint("\nDo you want it in a file? "); X if (!enteryn()) X { X tfp = stdout; X break; X } X else X { X wprint("Enter the filename: "); X if (!readstr(tfile,0,79,TRUE)) continue; X if ((tfp = fopen(tfile,"w")) == NULL) X wprintf("Cannot open %s\n",tfile); X else X break; X } X } X X wprint("Do you want comments included? "); X comments = enteryn(); X X /* In the future, ask about format */ X X cctrans(tfp,comments,masked); X} END_OF_cmd.c if test 24364 -ne `wc -c <cmd.c`; then echo shar: \"cmd.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f play.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"play.c\" else echo shar: Extracting \"play.c\" \(26495 characters\) sed "s/^X//" >play.c <<'END_OF_play.c' X/* CCHESS CHESS PLAYING ROUTINES. Version 1.00 X * X * Routines to enforce rules and test for mate and such fun stuff. These X * routines could be integrated much more, I think, but too much time elapsed X * between phases of development for me to do things right. X * X * (C) Copyright Jan Wolter - Apr 1986. X */ X X#include "cchess.h" X X/* Values of pieces ( ,K,Q,B,N,R,P,M,E,D,J,H) */ Xchar value[PIECES+1] = {0,7,6,4,4,5,1,2,2,2,3,7}; X X/* Number of pieces relocated in last move */ Xstatic int ndiff; X Xboolean xcheck(); Xint mcheck(); X X/* MAKEMOVE() X * X * Make a move, assuming it is legal. Handle promotion, en passeunt, and X * castling. If <record> is true, note rook and king moves for future X * castle legality checking, and also save the move on the stack for X * repeated position testing. X */ X Xmakemove(bd,co,fr,fc,tr,tc,record) Xschar bd[R_SIZE][C_SIZE]; XREGISTER int fr,fc,tr,tc; Xschar co; Xboolean record; X{ Xschar p; Xint wastaken = taken; Xint caprule; X X p = bd[fr][fc]; /* Piece moved */ X taken = bd[tr][tc]; /* Piece taken */ X promote = 0; /* No promotion */ X ndiff = 1; /* One piece changed */ X caprule = (p == Whiteking || p == -Blackking) ? Kcapture : Capture; X X switch (p) X { X case WP: X case BP: X /* Whenever a pawn moves, we can flush the stack */ X X /* Pawn Promotion - for now to goofy piece - Fix up later */ X if (tr == tside(co) && (taken == SQ || X (caprule != CA_RIFLE && caprule != CA_CONVERSION))) X promote = p = co * XX; X X /* En passeunt capture */ X if ((fc != tc) && (taken == SQ)) X { X taken = bd[fr][tc]; X bd[fr][tc] = SQ; X } X break; X case WK: X case BK: X /* Castling - Move the rook too */ X if (fc == tc + 2) X { X bd[fr][tc+1] = bd[fr][0]; X bd[fr][0] = SQ; X ndiff = 2; X if (record) pushmove(fr,0,fr,tc+1); X } X if (fc == tc - 2) X { X bd[fr][tc-1] = bd[fr][Cols]; X bd[fr][Cols] = SQ; X ndiff = 2; X if (record) pushmove(fr,Cols,fr,tc-1); X } X /* After any king move, can never castle again */ X if (record) X { X if (co == WHITE) X wcck = wccq = FALSE; X else X bcck = bccq = FALSE; X } X break; X case WR: X /* Rook moves may make future castling impossible */ X if (record) X { X if (fc == 0) wccq = FALSE; X if (fc == Cols) wcck = FALSE; X } X break; X case BR: X /* Rook moves may make future castling impossible */ X if (record) X { X if (fc == 0) bccq = FALSE; X if (fc == Cols) bcck = FALSE; X } X break; X } X X /* Move the piece */ X bd[tr][tc] = p; X bd[fr][fc] = SQ; X X if (taken == SQ) X /* If not a capture or pawn move, it is a tame move */ X istame = (p != WP && p != BP); X else X { X istame = FALSE; X X /* Handle kamikazi, karma, rifle and conversion captures */ X switch ((p == Whiteking || p == -Blackking) ? X Kcapture : Capture) X { X case CA_KARMA: X /* Capturing piece takes rank of captured one */ X bd[tr][tc] = -taken; X break; X case CA_KAMIKAZI: X /* Capturing piece destroyed */ X bd[tr][tc] = SQ; X break; X case CA_RIFLE: X /* Capturing piece stays where it came from */ X bd[fr][fc] = bd[tr][tc]; X bd[tr][tc] = SQ; X break; X case CA_CONVERSION: X /* Capturing piece stays where it came from */ X bd[fr][fc] = bd[tr][tc]; X /* Captured piece changes sides if not a traitor */ X bd[tr][tc] = (wastaken != SQ && X ((co==WHITE && btr==tr && btc==tc) || X (co==BLACK && wtr==tr && wtc==tc))) X ? SQ : -taken; X break; X } X } X X /* Put tame moves on the stack, flush the stack after others */ X if (record) X { X if (istame) X pushmove(fr,fc,tr,tc); X else X flushmoves(); X } X X /* Record last move for en passaunt legality checking */ X if (co == WHITE) { wfr = fr; wfc = fc; wtr = tr; wtc = tc; } X else { bfr = fr; bfc = fc; btr = tr; btc = tc; } X} X X X/* CHECK() X * X * Is there any piece of color "co" which can attack a square? X * Normally, the square in question is the king's location, so this X * is a check detector. Note that it doesn't test if the move leaves X * co's king in check. This would have to be done, if we used it for X * checking anything other than attacks on kings. However, the only X * place it is used that way is by the computer kibitzer, which needn't X * be that smart. X */ X Xboolean check(bd,co,r,c) Xschar bd[R_SIZE][C_SIZE]; Xschar co; XREGISTER int r,c; X{ Xregister int x,y; X X /* If piece is off board, it can't be checked. */ X if (r < 0 || c < 0 || r > Rows || c > Cols) return(FALSE); X X for (x=0;x<=Rows;x++) X for (y=0;y<=Cols;y++) X if (xcheck(bd,co,r,c,x,y)) return(TRUE); X return(FALSE); X} X X/* Can bd[x][y] attack bd[r][c]? */ X Xboolean xcheck(bd,co,r,c,x,y) Xschar bd[R_SIZE][C_SIZE]; Xschar co; XREGISTER int r,c; XREGISTER int x,y; X{ Xregister schar p; X X /* Spaces can't attack, and you can't attack yourself */ X if ((p = co*bd[x][y]) == SQ || (r == x && c == y)) X return(FALSE); X X if ((p = co*bd[x][y]) == Kingtype(co)) X { X /* If king can't capture, that's it for it */ X if (Kcapture == CA_NONE) X return(FALSE); X } X else X { X /* If piece can't capture other pieces, that's that */ X if (Capture == CA_NONE && abs(b[r][c]) != Kingtype(-co)) X return(FALSE); X } X X switch (p) X { X case WK: /* Enemy King */ X if ((abs(x-r) <= 1) && (abs(y-c) <= 1)) return (TRUE); X break; X X case WQ: /* Enemy Queen */ X if (cart(bd,x,y,r,c) || diag(bd,x,y,r,c)) return(TRUE); X break; X X case WN: /* Enemy Knight */ X if (((abs(x-r) == 2) && (abs(y-c) == 1)) || X ((abs(x-r) == 1) && (abs(y-c) == 2))) return(TRUE); X break; X X case WB: /* Enemy Bishop */ X if (diag(bd,x,y,r,c)) return(TRUE); X break; X X case WR: /* Enemy Rook */ X if (cart(bd,x,y,r,c)) return(TRUE); X break; X X case WP: /* Enemy Pawn */ X if ((r==x+co) && (abs(y-c)==1)) return(TRUE); X break; X X case WM: /* Enemy Minister */ X if ((abs(x-r) == 1) && (abs(y-c) == 1)) return(TRUE); X break; X X case WE: /* Enemy Elephant */ X if ((abs(x-r) == 2) && (abs(y-c) == 2)) return(TRUE); X break; X X case WD: /* Enemy Duke */ X if ((abs(x-r) + abs(y-c) == 1)) return(TRUE); X break; X X case WJ: /* Enemy Jester */ X if ((abs(x-r) <= 1) && (abs(y-c) <= 1)) return(TRUE); X break; X X case WH: /* Enemy Maharajah */ X if (((abs(x-r) == 1) && (abs(y-c) == 2)) || X ((abs(x-r) == 2) && (abs(y-c) == 1)) || X cart(bd,x,y,r,c) || diag(bd,x,y,r,c)) return(TRUE); X break; X X default: /* Friendly or Blank */ X break; X } X return(FALSE); X} X X/* COMPKIB() X * X * Computer Kibbitzer. This is delibrately stupid. It is ignorant of X * pinned pieces and fancy combinations. It returns the piece code X * of the first piece it finds that looks like it may be in danger. If X * it finds none, it returns the code for an empty space. "co" is the X * player we are kibbitzing for. This implementation is a little boneheaded X * too, but not as bad as it looks at first glance. X * X * The Computer Kibbitzer finds major pieces which can be taken but are X * uncovered or which can be taken by a less valuable piece. It doesn't X * worry about any piece that is no more valuable than the one you took X * this turn, since you are probably making a reasonable exchange. X */ X Xschar compkib(bd,co) Xschar bd[R_SIZE][C_SIZE]; Xschar co; X{ Xregister int x,y; Xregister int x1,y1; Xregister schar p; X X /* Look for a major friendly piece */ X for (x=0;x<=Rows;x++) X for (y=0;y<=Cols;y++) X if ((p = bd[x][y]*co) > 0 && p != WP && p != Kingtype(co) X && value[p] > value[abs(taken)]) X { X /* can it be attacked? */ X for (x1=0;x1<=Rows;x1++) X for (y1=0;y1<=Cols;y1++) X if (xcheck(bd,-co,x,y,x1,y1)) X { X /* Does it need cover? */ X if (value[p] > value[-bd[x1][y1]*co]) X return(p); X else X /* Is it covered? */ X if (!check(bd,co,x,y)) X return(p); X } X } X return(SQ); X} X X X/* LEGAL() X * X * Is a move legal? Return FALSE if not, and set error code. X * Board "b" gives current position. If move is legal, board bc has X * the new position. If the global must_take is set, only captures X * are considered legal. X */ X Xboolean legal(co,fr,fc,tr,tc) Xint co; /* player's color */ XREGISTER int fr,fc,tr,tc; /* from (row, column) to (row, column) */ X{ Xint r,c; Xint pf, pt; X X pt = b[tr][tc]; X pf = b[fr][fc]; X X /* Is there a friendly piece at start? */ X if (pf*co <= 0) X { X errcode = E_MT; X return(FALSE); X } X X /* Is there any motion? */ X if ((fr == tr) && (fc == tc)) X { X errcode = E_EQ; X return(FALSE); X } X X /* Is the move legal? */ X switch (pf) X { X case WK: /* Kings */ X case BK: X /* Castling Queen Side */ X if (tc == fc-2) X { X /* Is there a rook in position? */ X if (fc <= 2 || b[fr][0] != co*WR) X { X errcode = E_KI; X return (FALSE); X } X /* Has King or Rook been Previously moved? */ X if (!((co+1)?wccq:bccq)) X { X errcode = E_CM; X return (FALSE); X } X /* Are there any Intervening pieces */ X if (!cart(b,fr,0,fr,fc)) X { X errcode = E_CP; X return (FALSE); X } X /* Is intervening square under attack? */ X if ((!Thrucheck || consmoves == consmade) && X (incheck || check(b,-co,fr,fc-1))) X { X errcode = E_CT; X return (FALSE); X } X break; X } X X /* Castling King Side */ X if (tc == fc + 2) X { X /* Is there a rook in position? */ X if (fc >= Cols - 2 || b[fr][Cols] != co*WR) X { X errcode = E_KI; X return (FALSE); X } X /* Are King and Rook in their original squares? */ X if (!((co+1)?wcck:bcck)) X { X errcode = E_CM; X return (FALSE); X } X /* Are intervening squares clear? */ X if (!cart(b,fr,fc,fr,Cols)) X { X errcode = E_CP; X return (FALSE); X } X /* Is intervening square under attack? */ X if ((!Thrucheck || consmoves == consmade) && X (incheck || check(b,-co,fr,fc+1))) X { X errcode = E_CT; X return (FALSE); X } X break; X } X X case WJ: X case BJ: X /* Ordinary King Move */ X if ((abs(fr-tr) > 1) || (abs(fc-tc) > 1)) X { X errcode = E_IL | abs(pf); X return (FALSE); X } X break; X X case WQ: /* Queens */ X case BQ: X errcode = WQ; X if (cart(b,fr,fc,tr,tc) || diag(b,fr,fc,tr,tc)) X break; X else X return(FALSE); X X case WB: /* Bishops */ X case BB: X errcode = WB; X if (diag(b,fr,fc,tr,tc)) X break; X else X return(FALSE); X X case WN: /* Knights */ X case BN: X if (((abs(fr-tr) == 2) && (abs(fc-tc) == 1)) || X ((abs(fr-tr) == 1) && (abs(fc-tc) == 2))) X break; X else X { X errcode = E_NI; X return(FALSE); X } X X case WR: /* Rooks */ X case BR: X errcode = WR; X if (cart(b,fr,fc,tr,tc)) X break; X else X return(FALSE); X X case WP: /* White Pawns */ X X errcode = E_PI; X if (fc == tc) /* move */ X if ((pt==SQ) && ((tr==fr+1) || X ((!Oldpawn)&&(fr==1)&&(tr==3)&&(b[fr+1][fc]==SQ)))) X break; X else X return(FALSE); X X if (pt==SQ) /* capture en-passeunt */ X if ((btr==fr) && (btc==tc) && (bfr==btr+2) && X (b[btr][btc]==BP) && (tr==fr+1) && (abs(fc-tc)==1)) X break; X else X return(FALSE); X X if ((tr==fr+1) && (abs(fc-tc)==1)) /* capture */ X break; X else X return(FALSE); X X case BP: /* Black Pawns */ X X errcode = E_PI; X if (fc == tc) /* move */ X if ((pt == SQ) && ((tr==fr-1) || X ((!Oldpawn)&&(fr==Rows-1)&&(tr==Rows-3)&&(b[fr-1][fc]==SQ)))) X break; X else X return(FALSE); X X if (pt==SQ) /* capture en-passeunt */ X if ((wtr==fr) && (wtc==tc) && (wfr==wtr-2) && X (b[wtr][wtc]==WP) && (tr==fr-1) && (abs(fc-tc)==1)) X break; X else X return(FALSE); X X if ((tr==fr-1) && (abs(fc-tc)==1)) /* capture */ X break; X else X return(FALSE); X X case WM: /* Ministers */ X case BM: X if ((abs(fr-tr) == 1) && (abs(fc-tc) == 1)) X break; X else X { X errcode = E_MI; X return(FALSE); X } X X case WE: /* Elephants */ X case BE: X if ((abs(fr-tr) == 2) && (abs(fc-tc) == 2)) X break; X else X { X errcode = E_EI; X return(FALSE); X } X X case WD: /* Dukes */ X case BD: X if ((abs(fr-tr) + abs(fc-tc) == 1)) X break; X else X { X errcode = E_DI; X return(FALSE); X } X X case WH: /* Maharajahs */ X case BH: X errcode = WR; X if (((abs(fr-tr) == 1) && (abs(fc-tc) == 2)) || X ((abs(fr-tr) == 2) && (abs(fc-tc) == 1)) || X cart(b,fr,fc,tr,tc) || diag(b,fr,fc,tr,tc)) X break; X else X { X if (errcode == WR) X errcode = E_HI; X return(FALSE); X } X } X X /* Is there an friendly piece at the destination? */ X if (pt*co > 0) X { X errcode = E_AF; X return(FALSE); X } X X /* Is the piece forbidden to capture? */ X if (pt*co < 0 && ((pf==Kingpiece(co)) ? Kcapture : Capture) == CA_NONE) X { X errcode = E_NC; X return(FALSE); X } X X /* May we cross the center? */ X if (Tabiyat && movecnt <= 1 && X ((co == WHITE && tr >= (Rows+1)/2) || X (co == BLACK && tr <= Rows/2))) X { X errcode = E_CC; X return(FALSE); X } X X /* Should it have been a capture? */ X if (must_take && pt == SQ) X { X errcode = E_CR; X return(FALSE); X } X X copy(b,bc); X makemove(bc,co,fr,fc,tr,tc,FALSE); X X /* Does this move leave me in check? */ X if (Kingpiece(co) != SQ) X { X find(bc,Kingpiece(co),&r,&c); /* find the friendly king. */ X if (check(bc,-co,r,c)) /* can an enemy attack him? */ X { X errcode = E_MC; X return (FALSE); X } X } X return(TRUE); X} X X/* CART() X * X * Can a legal cartesian (rook) move be made between the two positions? X */ X Xboolean cart(bd,r1,c1,r2,c2) Xschar bd[R_SIZE][C_SIZE]; Xint r1,c1,r2,c2; X{ Xregister int i,x,y; X X if (r1 == r2) X { X x = ((c1 < c2) ? c1 : c2) + 1; X y = ((c1 < c2) ? c2 : c1) - 1; X for (i = x; i<=y; i++) X if (bd[r1][i] != SQ) X { X errcode |= E_MB; X return(FALSE); X } X } X X else if (c1 == c2) X { X x = ((r1 < r2) ? r1 : r2) + 1; X y = ((r1 < r2) ? r2 : r1) - 1; X for (i = x; i<=y; i++) X if (bd[i][c1] != SQ) X { X errcode |= E_MB; X return(FALSE); X } X } X X else X { X errcode |= E_IL; X return(FALSE); X } X X return(TRUE); X} X X/* DIAG() X * X * Can a legal diagonal (bishop) move be made between the two positions? X */ X Xboolean diag(bd,r1,c1,r2,c2) Xschar bd[R_SIZE][C_SIZE]; Xint r1,c1,r2,c2; X{ Xregister int i,x,y,n; X X if (r1+c1 == r2+c2) X { X x = ((r1 < r2) ? r1 : r2) + 1; X y = ((r1 < r2) ? c1 : c2) - 1; X n = abs(r1-r2) - 1; X for (i=0; i<n; i++) X if (bd[x+i][y-i] != SQ) X { X errcode |= E_MB; X return(FALSE); X } X } X else if (r1-c1 == r2-c2) X { X x = ((r1 < r2) ? r1 : r2) + 1; X y = ((r1 < r2) ? c1 : c2) + 1; X n = abs(r1-r2) - 1; X for (i=0; i<n; i++) X if (bd[x+i][y+i] != SQ) X { X errcode |= E_MB; X return(FALSE); X } X } X else X { X errcode |= E_IL; X return(FALSE); X } X return(TRUE); X} X X/* MCHECK() X * X * Is it Ok for a piece of color co to move from bd[fr][fc] to bd[tr][tc]? X * Return one of the following: X * 0 = move legal X * 1 = check - move doesn't block check (check before move) X * 2 = check - piece was pinned (no check before move) X * 3 = move blocked or off board X * This is for use by the canmove() routine. It assumes that the move is X * of a type that is legal for the piece (e.g. along a diagonal for a X * bishop). If <cap> is set, only captures are considered legal, and 1 X * is returned for legal moves which are not captures. X */ X Xmcheck(bd,co,fr,fc,tr,tc,cap) Xschar bd[R_SIZE][C_SIZE]; Xschar co; XREGISTER int fr,fc,tr,tc; Xboolean cap; X{ Xregister schar t,f; Xboolean flag; Xint kr,kc; Xschar king = Kingpiece(co); X X /* Check if destination is legal */ X if (tr < 0 || tc < 0 || tr > Rows || tc > Cols || (t=bd[tr][tc])*co > 0) X return (3); X X /* Make move */ X f = bd[tr][tc] = bd[fr][fc]; X bd[fr][fc] = SQ; X X /* Fix up capture in funny Capture modes */ X /* What type of friendly piece is in a square doesn't matter */ X if (t*co != SQ) X switch ((f == king) ? Kcapture : Capture) X { X case CA_NONE: X bd[tr][tc] = t; /* Unmake move and abort */ X bd[fr][fc] = f; X return(3); X case CA_RIFLE: X bd[fr][fc] = f; X /* no break here! */ X case CA_KAMIKAZI: X bd[tr][tc] = SQ; X break; X case CA_CONVERSION: X bd[fr][fc] = f; X if (taken != SQ && X ((co==WHITE && btr==tr && btc==tc) || X (co==BLACK && wtr==tr && wtc==tc))) X bd[tr][tc] = SQ; X break; X } X X /* Check if move leaves you in check */ X if (king != SQ) X { X if (f != king) X { X find(bd,king,&kr,&kc); X flag = check(bd,-co,kr,kc); X } X else X { X flag = check(bd,-co,tr,tc); X if (flag && t != SQ) X { X bd[tr][tc] = t; X bd[fr][fc] = f; X return(3); X } X } X } X else X flag = FALSE; X X /* Unmake move */ X bd[tr][tc] = t; X bd[fr][fc] = f; X X if (flag) X return (incheck ? 1 : 2); X else X return((cap && t==SQ) ? 1 : 0); X} X X/* CANMOVE() X * X * Can any piece of color <co> move on board <bd>? For Mate detection. X * incheck should be set first using the check detection routine. X * if <cap> is set, only captures are considered. X */ X Xboolean canmove(bd,co,cap) Xschar bd[R_SIZE][C_SIZE]; Xschar co; Xboolean cap; X{ Xregister int r,c; Xregister int tr,tc; Xint sr,sc; Xint code; X X/* This bit of weirdness with the return statement is for debugging */ X#define Return(a,b,c,d) return(TRUE); X/* #define Return(a,b,c,d) {printf("canmove: from %x %x to %x %x\r\n",a,b,c,d);return(TRUE);} */ X X for (c=0; c <= Cols; c++) X for (r=0; r <= Rows; r++) X switch (co*bd[r][c]) X { X case WK: /* Kings and Jesters */ X case WJ: X for (tr = r-1; tr <= r+1; tr++) X for (tc = c-1; tc <= c+1; tc++) X if (mcheck(bd,co,r,c,tr,tc,cap)==0) X Return (r,c,tr,tc) X break; X X case WQ: /* Rooks and Queens and Maharajahs */ X case WR: X case WH: X for (tr = r-1; tr >= 0; tr--) X { X if ((code = mcheck(bd,co,r,c,tr,c,cap))==0) X Return(r,c,tr,c) X else X if (code != 1) break; X } X X for (tr = r+1; tr <= Rows; tr++) X { X if ((code = mcheck(bd,co,r,c,tr,c,cap))==0) X Return(r,c,tr,c) X else X if (code != 1) break; X } X X for (tc = c-1; tc >= 0; tc--) X { X if ((code = mcheck(bd,co,r,c,r,tc,cap))==0) X Return(r,c,r,tc) X else X if (code != 1) break; X } X X for (tr = c+1; tc <= Cols; tc++) X { X if ((code = mcheck(bd,co,r,c,r,tc,cap))==0) X Return(r,c,r,tc) X else X if (code != 1) break; X } X X if (bd[r][c]*co == WR) break; X X case WB: /* Bishops and Queens and Maharajahs */ X for (sr = -1; sr <= 1; sr += 2) X for (sc = -1; sc <= 1; sc += 2) X for (tr = 1; tr <= Rows; tr++) X { X if ((code = mcheck(bd,co,r,c, X r+sr*tr,c+sc*tr,cap))==0) X Return(r,c,r+sr*tr,c+sc*tr) X else X if (code != 1) break; X } X X if (bd[r][c]*co != WH) break; X X case WN: /* Knights and Maharajahs */ X if ((code = mcheck(bd,co,r,c,r+1,c+2,cap)) == 0) X Return(r,c,r+1,c+2) X else if (code == 2) break; X X X if ((code = mcheck(bd,co,r,c,r-1,c-2,cap)) == 0) X Return(r,c,r-1,c-2) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r-2,c+1,cap)) == 0) X Return(r,c,r-2,c+1) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r+2,c-1,cap)) == 0) X Return(r,c,r+2,c-1) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r-1,c+2,cap)) == 0) X Return(r,c,r-1,c+2) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r+1,c-2,cap)) == 0) X Return(r,c,r+1,c-2) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r-2,c-1,cap)) == 0) X Return(r,c,r-2,c-1) X else if (code == 2) break; X X if ((code = mcheck(bd,co,r,c,r+2,c+1,cap)) == 0) X Return(r,c,r+2,c+1) X break; X X case WP: /* White Pawns */ X if (co == WHITE) X { X if (bd[r+1][c] == SQ && !cap) X { X if ((code = mcheck(bd,co,r,c,r+1,c,cap)) == 0) X Return(r,c,r+1,c) X else X if (!Oldpawn && code == 1 && r == 1 && X bd[3][c]==SQ && X mcheck(bd,co,1,c,3,c,cap) == 0) X Return(1,c,3,c) X } X if (c > 0) X if (bd[r+1][c-1] < 0) X if (mcheck(bd,co,r,c,r+1,c-1,cap) == 0) X Return(r,c,r+1,c-1) X else /* En Passaunt out of check? That's a new one. */ X if (r == btr && c-1 == btc && bfr == btr + 2 && X bd[btr][btc] == BP) X { X bd[btr][btc] = SQ; X code = mcheck(bd,co,r,c,r+1,c-1,cap); X bd[btr][btc] = BP; X if (code == 0) Return (r,c,r+1,c-1) X } X if (c < Cols) X if (bd[r+1][c+1] < 0) X if (mcheck(bd,co,r,c,r+1,c+1,cap) == 0) X Return(r,c,r+1,c+1) X else /* En Passaunt, would you believe? */ X if (r == btr && c+1 == btc && bfr == btr + 2 && X bd[btr][btc] == BP) X { X bd[btr][btc] = SQ; X code = mcheck(bd,co,r,c,r+1,c+1,cap); X bd[btr][btc] = BP; X if (code == 0) Return (r,c,r+1,c+1) X } X } X X else /* Black Pawns */ X { X if (bd[r-1][c] == SQ && !cap) X if ((code = mcheck(bd,co,r,c,r-1,c,cap)) == 0) X Return(r,c,r-1,c) X else X if (!Oldpawn && code == 1 && r == Rows-1 && X bd[Rows-3][c]==SQ && X mcheck(bd,co,Rows-1,c,Rows-3,c,cap) == 0) X Return(Rows-1,c,Rows-3,c) X if (c > 0) X if (bd[r-1][c-1] > 0) X if (mcheck(bd,co,r,c,r-1,c-1,cap) == 0) X Return(r,c,r-1,c-1) X else /* En Passaunt out of check? That's a new one. */ X if (r == wtr && c-1 == wtc && wfr == wtr - 2 && X bd[wtr][wtc] == WP) X { X bd[wtr][wtc] = SQ; X code = mcheck(bd,co,r,c,r-1,c-1,cap); X bd[wtr][wtc] = WP; X if (code == 0) Return (r,c,r-1,c-1) X } X if (c < Cols) X if (bd[r-1][c+1] > 0) X if (mcheck(bd,co,r,c,r-1,c+1,cap) == 0) X Return(r,c,r-1,c+1) X else /* En Passaunt, would you believe? */ X if (r == btr && c+1 == wtc && wfr == wtr - 2 && X bd[wtr][wtc] == WP) X { X bd[wtr][wtc] = SQ; X code = mcheck(bd,co,r,c,r-1,c+1,cap); X bd[wtr][wtc] = WP; X if (code == 0) Return (r,c,r-1,c+1) X } X } X break; X X case WM: /* Ministers */ X for (tr = r-1; tr <= r+1; tr+=2) X for (tc = c-1; tc <= c+1; tc+=2) X if (mcheck(bd,co,r,c,tr,tc,cap)==0) X Return (r,c,tr,tc) X break; X X case WE: /* Elephants */ X for (tr = r-2; tr <= r+2; tr+=4) X for (tc = c-2; tc <= c+2; tc+=4) X if (mcheck(bd,co,r,c,tr,tc,cap)==0) X Return (r,c,tr,tc) X break; X X case WD: /* Dukes */ X if (mcheck(bd,co,r,c,r+1,c,cap)==0) Return(r,c,r+1,c) X if (mcheck(bd,co,r,c,r-1,c,cap)==0) Return(r,c,r-1,c) X if (mcheck(bd,co,r,c,r,c+1,cap)==0) Return(r,c,r,c+1) X if (mcheck(bd,co,r,c,r,c-1,cap)==0) Return(r,c,r,c-1) X break; X } X return(FALSE); X} X X X/* COPY() X * X * Copy board <b1> into board <b2> X */ X Xcopy(b1,b2) Xschar b1[R_SIZE][C_SIZE], b2[R_SIZE][C_SIZE]; X{ Xint x,y; X X for (x=0;x<=Rows;x++) X for (y=0; y<=Cols; y++) X b2[x][y] = b1[x][y]; X} X X/* COMPARE() X * X * Compare board <b1> to board <b2> and return true if they are equal X */ X Xboolean compare(b1,b2) Xschar b1[R_SIZE][C_SIZE], b2[R_SIZE][C_SIZE]; X{ Xint x,y; X X for (x=0;x<=Rows;x++) X for (y=0; y<=Cols; y++) X if (b2[x][y] != b1[x][y]) X return(FALSE); X return(TRUE); X} X X X/* FIND() X * X * Find a piece of type <man> on the board. Mostly used to locate kings. X * return -1,-1 if not on board. X */ X Xfind(bd,man,r,c) Xschar bd[R_SIZE][C_SIZE]; Xschar man; Xint *r, *c; X{ X for (*r=0;*r<=Rows;(*r)++) X for (*c=0; *c<=Cols; (*c)++) X if (bd[*r][*c] == man) return; X *r = *c = -1; X} X X/* FORCES() X * X * Does the player of color <co> have any forces left on <bd> beside his king? X * This is used in shatranj and courier only. X */ X Xboolean forces(co,bd) Xschar co; Xschar bd[R_SIZE][C_SIZE]; X{ Xint r,c; X for (r=0; r<=Rows; r++) X for (c=0; c<=Cols; c++) X if ( bd[r][c]*co > 0 && bd[r][c] != Kingpiece(co)) X return(TRUE); X return(FALSE); X} X X/* FLUSHMOVES() X * X * The move stack is used to detect repeated positions. It starts out X * empty and is flushed every time a pawn is moved or a piece is captured. X * The global variable mvssize gives the number of moves currently on this X * stack. Note that when a castling move is made, both the move of the X * king and the move of the rook should be pushed on the stack. X * X * The call flushmoves() empties the stack. X * X * The call pushmove() adds a move to the stack. At most 50 moves are put X * on the stack, since beyond that point the 50-move rule dominates anyways. X * X * The call isrepeat() returns true if the current position has occured X * twice before. It doesn't count beyond 2, since that's all that matters. X * Isrepeat() should be called before the new move is placed on the stack. X * There should be a call to makemove() between any two calls to isrepeat(), X * since makemove() initializes the ndiffs variable. X */ X Xstatic struct stackamoves { X char fr,fc,tr,tc; X } mvstack[MAXTAME+2]; /* Two extra slots for castling */ X Xflushmoves() X{ X mvssize = 0; X} X Xpushmove(fr,fc,tr,tc) Xint fr,fc,tr,tc; X{ X if (mvssize < MAXTAME+2) X { X mvstack[mvssize].fr = (char) fr; X mvstack[mvssize].fc = (char) fc; X mvstack[mvssize].tr = (char) tr; X mvstack[mvssize].tc = (char) tc; X } X mvssize++; X} X Xboolean isrepeat(bd,nbd) Xschar bd[R_SIZE][C_SIZE]; /* Board before current move */ Xschar nbd[R_SIZE][C_SIZE]; /* Current after current move */ X{ Xschar obd[R_SIZE][C_SIZE]; /* Previous board */ Xschar p; Xint mvs; Xint nreps; /* Number of times this position has been repeated */ X X /* X * If I haven't moved since last flush, this is no repeat. X * If the game is stale, just return any old thing. X */ X if (mvssize < 1 || mvssize >= MAXTAME+2) X return(FALSE); X X /* Each piece on the board was where it is */ X copy(bd,obd); X X /* X * Back through the stack, unmaking the moves on the old board, X * and counting the number of pieces out of place. This X * is easy, since none of the moves on the stack are captures. X */ X nreps = 0; /* ndiff initialized by makemove() */ X mvs = mvssize; X while (mvs-- >= 0) X { X /* Unmake the move on the old board */ X p = obd[mvstack[mvs].tr][mvstack[mvs].tc]; X obd[mvstack[mvs].fr][mvstack[mvs].fc] = p; X X /* Does this make or break any similarities? */ X if (nbd[mvstack[mvs].tr][mvstack[mvs].tc] == p) X ndiff++; X else if (nbd[mvstack[mvs].fr][mvstack[mvs].fc] == p) X ndiff--; X X /* If there are no differences, count a repeat */ X if (ndiff == 0) X if (++nreps == 2) X return(TRUE); X } X return(FALSE); X} X X X/* SETUP() X * X * Make the default initial setup for various variants games. X * The default initial setup is returned in <bd>. X */ X Xsetup(bd) Xschar bd[R_SIZE][C_SIZE]; X{ X copy(ib,bd); X X switch (Game_type) X { X case TY_SHATRANJ: X bd[0][2] = bd[0][5] = WE; X bd[0][3] = WM; X bd[7][2] = bd[7][5] = BE; X bd[7][3] = BM; X break; X X case TY_COURIER: X bd[7][2] = -(bd[0][2] = WE); X bd[7][3] = -(bd[0][3] = WB); X bd[7][4] = -(bd[0][4] = WJ); X bd[7][5] = -(bd[0][5] = WK); X bd[7][6] = -(bd[0][6] = WM); X bd[7][7] = -(bd[0][7] = WD); X break; X X case TY_HALFBOARD: X bd[0][3] = WK; X bd[7][3] = BK; X break; X X case TY_MAHARAJAH: X bd[0][4] = WH; X bd[1][2] = bd[1][3] = bd[1][4] = bd[1][5] = SQ; X case TY_STEAMROLLER: X bd[0][0] = bd[0][1] = bd[0][2] = bd[0][3] = X bd[0][5] = bd[0][6] = bd[0][7] = X bd[1][0] = bd[1][1] = bd[1][6] = bd[1][7] = SQ; X break; X } X} END_OF_play.c if test 26495 -ne `wc -c <play.c`; then echo shar: \"play.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 2 \(of 5\). cp /dev/null ark2isdone 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