diff options
Diffstat (limited to 'FICS/algcheck.c')
-rw-r--r-- | FICS/algcheck.c | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/FICS/algcheck.c b/FICS/algcheck.c new file mode 100644 index 0000000..10fad0c --- /dev/null +++ b/FICS/algcheck.c @@ -0,0 +1,465 @@ +/* algcheck.c + * + */ + +/* + fics - An internet chess server. + Copyright (C) 1993 Richard V. Nash + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* Revision history: + name email yy/mm/dd Change + Richard Nash 93/10/22 Created +*/ + +#include "stdinclude.h" + +#include "common.h" +#include "algcheck.h" +#include "movecheck.h" +#include "board.h" +#include "utils.h" + +/* Well, lets see if I can list the possibilities + * Piece moves + * Ne4 + * Nxe4 + * Nce4 + * Ncxe4 + * R2f3 + * R2xf3 + * Special pawn moves + * e4 + * ed + * exd + * exd5 + * ed5 + * Drop moves (bughouse, board edit) + * P@f7 P*f7 + * #f7 #Nf7 + * (o-o, o-o-o) Castling is handled earlier, so don't worry about that + * Of course any of these can have a + or ++ or = string on the end, just + * cut that off. + */ + +/* f - file + * r - rank + * p - piece + * x - x + * @ - drop character (bughouse) + */ +char *alg_list[] = { + "fxfr", "pxfr", /* These two get confused in case of bishop */ + "ffr", "pfr", /* These two get confused in case of bishop */ + "pffr", + "pfxfr", + "prfr", + "prxfr", + "fr", + "ff", + "fxf", + "p@fr", + "#fr", + "#pfr", + NULL +}; + +#define ALG_UNKNOWN -1 +/* #define ALG_DROP -2 IanO: this is in board.h, used in movecheck.c */ + +PRIVATE int get_move_info(char *str, int *piece, int *ff, int *fr, int *tf, int *tr, int *bishconfusion) +{ + char tmp[1024]; + char *s; + int i, j, len; + char c; + int matchVal = -1; + int lpiece, lff, lfr, ltf, ltr; + + *bishconfusion = 0; + strcpy(tmp, str); + if ((s = index(tmp, '+'))) { /* Cut off any check marks */ + *s = '\0'; + } + if ((s = index(tmp, '='))) { /* Cut off any promotion marks */ + *s = '\0'; + } + *piece = *ff = *fr = *tf = *tr = ALG_UNKNOWN; + len = strlen(tmp); + for (i = 0; alg_list[i]; i++) { + lpiece = lff = lfr = ltf = ltr = ALG_UNKNOWN; + if (strlen(alg_list[i]) != len) + continue; + for (j = len - 1; j >= 0; j--) { + switch (alg_list[i][j]) { + case 'f': + if ((tmp[j] < 'a') || (tmp[j] > 'h')) + goto nomatch; + if (ltf == ALG_UNKNOWN) + ltf = tmp[j] - 'a'; + else + lff = tmp[j] - 'a'; + break; + case 'r': + if ((tmp[j] < '1') || (tmp[j] > '8')) + goto nomatch; + if (ltr == ALG_UNKNOWN) + ltr = tmp[j] - '1'; + else + lfr = tmp[j] - '1'; + break; + case 'p': + if (isupper(tmp[j])) + c = tolower(tmp[j]); + else + c = tmp[j]; + if (c == 'k') + lpiece = KING; + else if (c == 'q') + lpiece = QUEEN; + else if (c == 'r') + lpiece = ROOK; + else if (c == 'b') + lpiece = BISHOP; + else if (c == 'n') + lpiece = KNIGHT; + else if (c == 'p') + lpiece = PAWN; + else + goto nomatch; + break; + case 'x': + if ((tmp[j] != 'x') && (tmp[j] != 'X')) + goto nomatch; + break; + case '@': + if (tmp[j] != '@' && tmp[j] != '*') + goto nomatch; + lff = lfr = ALG_DROP; + break; + case '#': + if (tmp[j] != '#') + goto nomatch; + lff = lfr = ALG_DROP; + break; + default: + fprintf(stderr, "Unknown character in algebraic parsing\n"); + break; + } + } + if (lpiece == ALG_UNKNOWN) + lpiece = PAWN; + if (lpiece == PAWN && (lfr == ALG_UNKNOWN)) { /* ffr or ff */ + if (lff != ALG_UNKNOWN) { + if (lff == ltf) + goto nomatch; + if ((lff - ltf != 1) && (ltf - lff != 1)) + goto nomatch; + } + } + *piece = lpiece; /* We have a match */ + *tf = ltf; + *tr = ltr; + *ff = lff; + *fr = lfr; + if (matchVal != -1) { + /* We have two matches, it must be that Bxc4 vs. bxc4 problem */ + /* Or it could be the Bc4 vs bc4 problem */ + *bishconfusion = 1; + } + matchVal = i; +nomatch:; + } + if (matchVal != -1) + return MS_ALG; + else + return MS_NOTMOVE; +} + +PUBLIC int alg_is_move(char *mstr) +{ + int piece, ff, fr, tf, tr, bc; + + return get_move_info(mstr, &piece, &ff, &fr, &tf, &tr, &bc); +} + +/* We already know it is algebraic, get the move squares */ +PUBLIC int alg_parse_move(char *mstr, game_state_t * gs, move_t * mt) +{ + int f, r, tmpr, posf, posr, posr2; + int piece, ff, fr, tf, tr, bc; + + if (get_move_info(mstr, &piece, &ff, &fr, &tf, &tr, &bc) != MS_ALG) { + fprintf(stderr, "FICS: Shouldn't try to algebraicly parse non-algabraic move string.\n"); + return MOVE_ILLEGAL; + } + /* Resolve ambiguities in to-ness */ + if (tf == ALG_UNKNOWN) + return MOVE_AMBIGUOUS; /* Must always know to file */ + if (tr == ALG_UNKNOWN) { + posr = posr2 = ALG_UNKNOWN; + if (piece != PAWN) + return MOVE_AMBIGUOUS; + if (ff == ALG_UNKNOWN) + return MOVE_AMBIGUOUS; + /* Need to find pawn on ff that can take to tf and fill in ranks */ + for (InitPieceLoop(gs->board, &f, &r, gs->onMove); + NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + if ((ff != ALG_UNKNOWN) && (ff != f)) + continue; + if (piecetype(gs->board[f][r]) != piece) + continue; + if (gs->onMove == WHITE) { + tmpr = r + 1; + } else { + tmpr = r - 1; + } +/* if ((gs->board[tf][tmpr] == NOPIECE) || + (iscolor(gs->board[tf][tmpr], gs->onMove))) continue;*/ +/* patch from Soso, added by Sparky 3/16/95 */ + if (gs->board[tf][tmpr] == NOPIECE) { + if ((gs->ep_possible[((gs->onMove == WHITE) ? 0 : 1)][ff]) != (tf - ff)) + continue; + } else { + if (iscolor(gs->board[tf][tmpr], gs->onMove)) + continue; + } + + if (legal_andcheck_move(gs, f, r, tf, tmpr)) { + if ((posr != ALG_UNKNOWN) && (posr2 != ALG_UNKNOWN)) + return MOVE_AMBIGUOUS; + posr = tmpr; + posr2 = r; + } + } + tr = posr; + fr = posr2; + } else if (bc) { /* Could be bxc4 or Bxc4, tr is known */ + ff = ALG_UNKNOWN; + fr = ALG_UNKNOWN; + for (InitPieceLoop(gs->board, &f, &r, gs->onMove); + NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != BISHOP)) + continue; + if (legal_andcheck_move(gs, f, r, tf, tr)) { + if ((piecetype(gs->board[f][r]) == PAWN) && (f != 1)) + continue; + if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN)) + return (MOVE_AMBIGUOUS); + ff = f; + fr = r; + } + } + } else { /* The from position is unknown */ + posf = ALG_UNKNOWN; + posr = ALG_UNKNOWN; + if ((ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) { + /* Need to find a piece that can go to tf, tr */ + for (InitPieceLoop(gs->board, &f, &r, gs->onMove); + NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + if ((ff != ALG_UNKNOWN) && (ff != f)) + continue; + if ((fr != ALG_UNKNOWN) && (fr != r)) + continue; + if (piecetype(gs->board[f][r]) != piece) + continue; + if (legal_andcheck_move(gs, f, r, tf, tr)) { + if ((posf != ALG_UNKNOWN) && (posr != ALG_UNKNOWN)) + return MOVE_AMBIGUOUS; + posf = f; + posr = r; + } + } + } else if (ff == ALG_DROP) { + if (legal_andcheck_move(gs, ALG_DROP, piece, tf, tr)) { + posf = ALG_DROP; + posr = piece; + } + } + ff = posf; + fr = posr; + } + if ((tf == ALG_UNKNOWN) || (tr == ALG_UNKNOWN) || + (ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) + return MOVE_ILLEGAL; + mt->fromFile = ff; + mt->fromRank = fr; + mt->toFile = tf; + mt->toRank = tr; + return MOVE_OK; +} + +/* A assumes the move has yet to be made on the board */ +/* this is the old stupid function, we are testing one from soso... +PUBLIC char *alg_unparse( game_state_t *gs, move_t *mt ) +{ + static char mStr[20]; + + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && + ((mt->fromFile == 4) && (mt->toFile == 6)) ) + return "o-o"; + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && + ((mt->fromFile == 4) && (mt->toFile == 2)) ) + return "o-o-o"; + + sprintf( mStr, "%c%d%c%d", mt->fromFile+'a', mt->fromRank+1, + mt->toFile+'a', mt->toRank+1 ); + return mStr; +} +*/ + + +/* A assumes the move has yet to be made on the board */ + + +/* Soso: rewrote alg_unparse function. + * Algebraic deparser - sets the mStr variable with move description + * in short notation. Used in last move report and in 'moves' command. + */ + +PUBLIC char *alg_unparse(game_state_t * gs, move_t * mt) +{ + static char mStr[20]; + char tmp[20]; + int piece, f, r; + int ambig, r_ambig, f_ambig; + game_state_t fakeMove; + + if (mt->fromFile == ALG_DROP) { + piece = mt->fromRank; + } else { + piece = piecetype(gs->board[mt->fromFile][mt->fromRank]); + } + + if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 6))) { + strcpy(mStr, "O-O"); + goto check; + } + if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 2))) { + strcpy(mStr, "O-O-O"); + goto check; + } + strcpy(mStr, ""); + switch (piece) { + case PAWN: + if (mt->fromFile == ALG_DROP) { + strcpy(mStr,"P"); + } else if (mt->fromFile != mt->toFile) { + sprintf(tmp, "%c", mt->fromFile + 'a'); + strcpy(mStr, tmp); + } + break; + case KNIGHT: + strcpy(mStr, "N"); + break; + case BISHOP: + strcpy(mStr, "B"); + break; + case ROOK: + strcpy(mStr, "R"); + break; + case QUEEN: + strcpy(mStr, "Q"); + break; + case KING: + strcpy(mStr, "K"); + break; + default: + strcpy(mStr, ""); + break; + } + + if (mt->fromFile == ALG_DROP) { + strcat(mStr, DROP_STR); + } else { + /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */ + if (piece != PAWN) { + ambig = r_ambig = f_ambig = 0; + for (r = 0; r < 8; r++) + for (f = 0; f < 8; f++) { + if ((gs->board[f][r] != NOPIECE) && iscolor(gs->board[f][r], gs->onMove) + && (piecetype(gs->board[f][r]) == piece) && + ((f != mt->fromFile) || (r != mt->fromRank))) { + if (legal_move(gs, f, r, mt->toFile, mt->toRank)) { + fakeMove = *gs; + fakeMove.board[f][r] = NOPIECE; + fakeMove.onMove = CToggle(fakeMove.onMove); + gs->onMove = CToggle(gs->onMove); + + /* New bracketing below to try to fix 'ambiguous move' bug. */ + if ((in_check(gs)) || !in_check(&fakeMove)) { + ambig++; + } + if (f == mt->fromFile) { + f_ambig++; + ambig++; + } + if (r == mt->fromRank) { + r_ambig++; + ambig++; + } + gs->onMove = CToggle(gs->onMove); + } + } + } + if (ambig > 0) { + /* Ambiguity in short notation, need to add file,rank or _both_ in + notation */ + if (f_ambig == 0) { + sprintf(tmp, "%c", mt->fromFile + 'a'); + strcat(mStr, tmp); + } else if (r_ambig == 0) { + sprintf(tmp, "%d", mt->fromRank + 1); + strcat(mStr, tmp); + } else { + sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1); + strcat(mStr, tmp); + } + } + } + if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) || + ((piece == PAWN) && (mt->fromFile != mt->toFile))) { + strcat(mStr, "x"); + } + } + sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1); + strcat(mStr, tmp); + + if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) { + strcat(mStr, "="); /* = before promoting piece */ + switch (piecetype(mt->piecePromotionTo)) { + case KNIGHT: + strcat(mStr, "N"); + break; + case BISHOP: + strcat(mStr, "B"); + break; + case ROOK: + strcat(mStr, "R"); + break; + case QUEEN: + strcat(mStr, "Q"); + break; + default: + break; + } + } +check:; + fakeMove = *gs; + execute_move(&fakeMove, mt, 0); + fakeMove.onMove = CToggle(fakeMove.onMove); + if (in_check(&fakeMove)) { + strcat(mStr, "+"); + } + return mStr; +} |