From 754e9f069f9a937fe98bb392f425381e5ce04c0b Mon Sep 17 00:00:00 2001 From: Markus Uhlin Date: Sat, 13 Apr 2024 13:14:37 +0200 Subject: Checked out files by tag 1.0 --- FICS/algcheck.c | 854 ++++++++++------------- FICS/algcheck.h | 12 +- FICS/movecheck.c | 2050 ++++++++++++++++++++++++------------------------------ FICS/movecheck.h | 48 +- 4 files changed, 1315 insertions(+), 1649 deletions(-) diff --git a/FICS/algcheck.c b/FICS/algcheck.c index 67609b1..10fad0c 100644 --- a/FICS/algcheck.c +++ b/FICS/algcheck.c @@ -19,25 +19,17 @@ /* Revision history: name email yy/mm/dd Change - Richard Nash 93/10/22 Created - Markus Uhlin 24/01/04 Reformatted functions - Markus Uhlin 24/01/06 Switched to usage of strlcpy, - strlcat and snprintf. Also added - truncation checks. + Richard Nash 93/10/22 Created */ #include "stdinclude.h" -#include "common.h" +#include "common.h" #include "algcheck.h" -#include "board.h" #include "movecheck.h" +#include "board.h" #include "utils.h" -#if __linux__ -#include -#endif - /* Well, lets see if I can list the possibilities * Piece moves * Ne4 @@ -66,484 +58,408 @@ * x - x * @ - drop character (bughouse) */ -PRIVATE 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 +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 }; -PRIVATE int -get_move_info(char *str, int *piece, int *ff, int *fr, int *tf, int *tr, - int *bishconfusion) -{ - char *s; - char c; - char tmp[1024] = { '\0' }; - int i, j, len; - int lpiece, lff, lfr, ltf, ltr; - int matchVal = -1; - - *bishconfusion = 0; - strlcpy(tmp, str, sizeof tmp); - - if ((s = strchr(tmp, '+')) != NULL) { // Cut off any check marks - *s = '\0'; - } - if ((s = strchr(tmp, '=')) != NULL) { // 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; - } +#define ALG_UNKNOWN -1 +/* #define ALG_DROP -2 IanO: this is in board.h, used in movecheck.c */ - matchVal = i; - - nomatch:; - } - - if (matchVal != -1) - return MS_ALG; +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 - return MS_NOTMOVE; + 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) +PUBLIC int alg_is_move(char *mstr) { - int piece, ff, fr, tf, tr, bc; + int piece, ff, fr, tf, tr, bc; - return get_move_info(mstr, &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) +/* 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 algebraically parse " - "non-algebraic move string.\n"); - return MOVE_ILLEGAL; - } - - 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) { - const int is_black = (gs->onMove == WHITE ? - 0 : 1); - - if (gs->ep_possible[is_black][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; + 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; } - - 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; + } + } 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; } -PRIVATE void -not_pawn(game_state_t *gs, move_t *mt, game_state_t *fakeMove, const int piece, - char *tmp, char *mStr, size_t tmp_size, size_t mStr_size) +/* 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 ) { - int ambig, r_ambig, f_ambig; - - ambig = r_ambig = f_ambig = 0; - - for (int r = 0; r < 8; r++) { - for (int 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); - } - } - } /* for */ - } /* for */ - - if (ambig > 0) { - /* - * Ambiguity in short notation. Need to add file, rank - * or _both_ in notation. - */ - - if (f_ambig == 0) { - snprintf(tmp, tmp_size, "%c", (mt->fromFile + 'a')); - strlcat(mStr, tmp, mStr_size); - } else if (r_ambig == 0) { - snprintf(tmp, tmp_size, "%d", (mt->fromRank + 1)); - strlcat(mStr, tmp, mStr_size); - } else { - snprintf(tmp, tmp_size, "%c%d", - (mt->fromFile + 'a'), - (mt->fromRank + 1)); - strlcat(mStr, tmp, mStr_size); - } - } + 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; } +*/ -/* - * 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) -{ - char tmp[20] = { '\0' }; - game_state_t fakeMove; - int piece; - size_t ret = 0; - static char mStr[20] = { '\0' }; - - 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)) { - strlcpy(mStr, "O-O", sizeof mStr); - goto check; - } - - if (piece == KING && (mt->fromFile == 4 && mt->toFile == 2)) { - strlcpy(mStr, "O-O-O", sizeof mStr); - goto check; - } - - mStr[0] = '\0'; - - switch (piece) { - case PAWN: - if (mt->fromFile == ALG_DROP) { - strlcpy(mStr, "P", sizeof mStr); - } else if (mt->fromFile != mt->toFile) { - snprintf(tmp, sizeof tmp, "%c", (mt->fromFile + 'a')); - strlcpy(mStr, tmp, sizeof mStr); - } - break; - case KNIGHT: - strlcpy(mStr, "N", sizeof mStr); - break; - case BISHOP: - strlcpy(mStr, "B", sizeof mStr); - break; - case ROOK: - strlcpy(mStr, "R", sizeof mStr); - break; - case QUEEN: - strlcpy(mStr, "Q", sizeof mStr); - break; - case KING: - strlcpy(mStr, "K", sizeof mStr); - break; - default: - strlcpy(mStr, "", sizeof mStr); - break; - } /* switch */ - - if (mt->fromFile == ALG_DROP) { - strlcat(mStr, DROP_STR, sizeof mStr); - } else { - /* - * Checks for ambiguity in short notation (Ncb3, R8e8 - * or so.) - */ - - if (piece != PAWN) { - not_pawn(gs, mt, &fakeMove, piece, &tmp[0], &mStr[0], - sizeof tmp, sizeof mStr); - } /* not pawn */ - - if (gs->board[mt->toFile][mt->toRank] != NOPIECE || - (piece == PAWN && mt->fromFile != mt->toFile)) - strlcat(mStr, "x", sizeof mStr); - } - - snprintf(tmp, sizeof tmp, "%c%d", (mt->toFile + 'a'), (mt->toRank + 1)); - ret = strlcat(mStr, tmp, sizeof mStr); - - if (ret >= sizeof mStr) { - fprintf(stderr, "FICS: %s (line %d): warning: " - "strlcat() truncated\n", __func__, __LINE__); - } - - if (piece == PAWN && mt->piecePromotionTo != NOPIECE) { - strlcat(mStr, "=", sizeof mStr); /* = before promoting piece */ - - switch (piecetype(mt->piecePromotionTo)) { - case KNIGHT: - strlcat(mStr, "N", sizeof mStr); - break; - case BISHOP: - strlcat(mStr, "B", sizeof mStr); - break; - case ROOK: - strlcat(mStr, "R", sizeof mStr); - break; - case QUEEN: - strlcat(mStr, "Q", sizeof mStr); - break; - default: - break; - } - } - check:; +/* A assumes the move has yet to be made on the board */ - fakeMove = *gs; - execute_move(&fakeMove, mt, 0); - fakeMove.onMove = CToggle(fakeMove.onMove); - if (in_check(&fakeMove)) { - ret = strlcat(mStr, "+", sizeof mStr); +/* 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. + */ - if (ret >= sizeof mStr) { - fprintf(stderr, "FICS: %s (line %d): warning: " - "strlcat() truncated\n", __func__, __LINE__); - } +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); + } } - - return mStr; + } + 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; } diff --git a/FICS/algcheck.h b/FICS/algcheck.h index 8f7bda7..60d971b 100644 --- a/FICS/algcheck.h +++ b/FICS/algcheck.h @@ -29,13 +29,13 @@ #include "board.h" #endif -#define ALG_UNKNOWN -1 +#define DROP_CHAR '@' /* used by algcheck.c and movecheck.c */ +#define DROP_STR "@" -#define DROP_CHAR '@' /* used by algcheck.c and movecheck.c */ -#define DROP_STR "@" +extern int alg_is_move(char *); +extern int alg_parse_move(char *, game_state_t *, move_t *); +extern char *alg_unparse(game_state_t *, move_t *); -extern char *alg_unparse(game_state_t *, move_t *); -extern int alg_is_move(char *); -extern int alg_parse_move(char *, game_state_t *, move_t *); +/* extern int tolower(); */ #endif /* _ALGCHECK_H */ diff --git a/FICS/movecheck.c b/FICS/movecheck.c index 872814a..3cb109f 100644 --- a/FICS/movecheck.c +++ b/FICS/movecheck.c @@ -23,760 +23,631 @@ Markus Uhlin 23/12/14 Fixed compiler warnings Markus Uhlin 23/12/17 Fixed compiler warnings Markus Uhlin 23/12/24 Fixed dead assignment - Markus Uhlin 24/03/16 Refactored and reformatted - functions. - Markus Uhlin 24/03/17 Replaced sprintf() calls */ #include "stdinclude.h" -#include "common.h" #include "algcheck.h" #include "board.h" +#include "common.h" #include "gamedb.h" #include "movecheck.h" #include "network.h" #include "playerdb.h" #include "utils.h" -#if __linux__ -#include -#endif - -/* - * Simply tests if the input string is a move or not. If it matches - * patterns below. Add to this list as you improve the move parser. - * - * - MS_COMP e2e4 - * - MS_COMPDASH e2-e4 - * - MS_CASTLE o-o, o-o-o - * - * Not done yet - * MS_ALG e4, Nd5 Ncd5 - */ -PUBLIC int -is_move(char *mstr) +/* Simply tests if the input string is a move or not. */ +/* If it matches patterns below */ +/* Add to this list as you improve the move parser */ +/* MS_COMP e2e4 */ +/* MS_COMPDASH e2-e4 */ +/* MS_CASTLE o-o, o-o-o */ +/* Not done yet */ +/* MS_ALG e4, Nd5 Ncd5 */ +PUBLIC int is_move(char *mstr) { - int len = strlen(mstr); - - if (len > 3 && mstr[len - 2] == '=') - len -= 2; - - if (len == 4) { // Test for e2e4 - if (isfile(mstr[0]) && isrank(mstr[1]) && - isfile(mstr[2]) && isrank(mstr[3])) - return MS_COMP; - } - - if (len == 5) { // Test for e2-e4 - if (isfile(mstr[0]) && - isrank(mstr[1]) && - mstr[2] == '-' && - isfile(mstr[3]) && - isrank(mstr[4])) - return MS_COMPDASH; - } - - if (len == 3) { // Test for o-o - if (mstr[0] == 'o' && mstr[1] == '-' && mstr[2] == 'o') - return MS_KCASTLE; - if (mstr[0] == 'O' && mstr[1] == '-' && mstr[2] == 'O') - return MS_KCASTLE; - if (mstr[0] == '0' && mstr[1] == '-' && mstr[2] == '0') - return MS_KCASTLE; - } - - if (len == 2) { // Test for oo - if (mstr[0] == 'o' && mstr[1] == 'o') - return MS_KCASTLE; - if (mstr[0] == 'O' && mstr[1] == 'O') - return MS_KCASTLE; - if (mstr[0] == '0' && mstr[1] == '0') - return MS_KCASTLE; - } - - if (len == 5) { // Test for o-o-o - if (mstr[0] == 'o' && mstr[1] == '-' && mstr[2] == 'o' && - mstr[3] == '-' && mstr[4] == 'o') - return MS_QCASTLE; - if (mstr[0] == 'O' && mstr[1] == '-' && mstr[2] == 'O' && - mstr[3] == '-' && mstr[4] == 'O') - return MS_QCASTLE; - if (mstr[0] == '0' && mstr[1] == '-' && mstr[2] == '0' && - mstr[3] == '-' && mstr[4] == '0') - return MS_QCASTLE; - } - - if (len == 3) { // Test for ooo - if (mstr[0] == 'o' && mstr[1] == 'o' && mstr[2] == 'o') - return MS_QCASTLE; - if (mstr[0] == 'O' && mstr[1] == 'O' && mstr[2] == 'O') - return MS_QCASTLE; - if (mstr[0] == '0' && mstr[1] == '0' && mstr[2] == '0') - return MS_QCASTLE; - } - - return alg_is_move(mstr); + int len = strlen(mstr); + if ((len > 3) && (mstr[len - 2] == '=')) + len -= 2; + + if (len == 4) { /* Test for e2e4 */ + if (isfile(mstr[0]) && isrank(mstr[1]) && + isfile(mstr[2]) && isrank(mstr[3])) { + return MS_COMP; + } + } + if (len == 5) { /* Test for e2-e4 */ + if (isfile(mstr[0]) && isrank(mstr[1]) && + (mstr[2] == '-') && + isfile(mstr[3]) && isrank(mstr[4])) { + return MS_COMPDASH; + } + } + if (len == 3) { /* Test for o-o */ + if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o')) { + return MS_KCASTLE; + } + if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O')) { + return MS_KCASTLE; + } + if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0')) { + return MS_KCASTLE; + } + } + if (len == 2) { /* Test for oo */ + if ((mstr[0] == 'o') && (mstr[1] == 'o')) { + return MS_KCASTLE; + } + if ((mstr[0] == 'O') && (mstr[1] == 'O')) { + return MS_KCASTLE; + } + if ((mstr[0] == '0') && (mstr[1] == '0')) { + return MS_KCASTLE; + } + } + if (len == 5) { /* Test for o-o-o */ + if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o') && (mstr[3] == '-') && (mstr[4] == 'o')) { + return MS_QCASTLE; + } + if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O') && (mstr[3] == '-') && (mstr[4] == 'O')) { + return MS_QCASTLE; + } + if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0') && (mstr[3] == '-') && (mstr[4] == '0')) { + return MS_QCASTLE; + } + } + if (len == 3) { /* Test for ooo */ + if ((mstr[0] == 'o') && (mstr[1] == 'o') && (mstr[2] == 'o')) { + return MS_QCASTLE; + } + if ((mstr[0] == 'O') && (mstr[1] == 'O') && (mstr[2] == 'O')) { + return MS_QCASTLE; + } + if ((mstr[0] == '0') && (mstr[1] == '0') && (mstr[2] == '0')) { + return MS_QCASTLE; + } + } + return alg_is_move(mstr); } -PUBLIC int -NextPieceLoop(board_t b, int *f, int *r, int color) -{ - while (1) { - (*r) = (*r) + 1; - - if (*r > 7) { - *r = 0; - *f = *f + 1; - - if (*f > 7) - break; - } - if (b[*f][*r] != NOPIECE && iscolor(b[*f][*r], color)) - return 1; - } - - return 0; +PUBLIC int NextPieceLoop(board_t b, int *f, int *r, int color) +{ + while (1) { + (*r) = (*r) + 1; + if (*r > 7) { + *r = 0; + *f = *f + 1; + if (*f > 7) + break; + } + if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color)) + return 1; + } + return 0; } -PUBLIC int -InitPieceLoop(board_t b, int *f, int *r, int color) +PUBLIC int InitPieceLoop(board_t b, int *f, int *r, int color) { - *f = 0; - *r = -1; - - /* XXX: not referenced */ - (void) b; - (void) color; - return 1; + *f = 0; + *r = -1; + return 1; } -/* - * All of the routines assume that the obvious problems have been - * checked. See legal_move(). - */ -PRIVATE int -legal_pawn_move(game_state_t *gs, int ff, int fr, int tf, int tr) +/* All of the routines assume that the obvious problems have been checked */ +/* See legal_move() */ +PRIVATE int legal_pawn_move( game_state_t *gs, int ff, int fr, int tf, int tr ) { - if (ff == tf) { - if (gs->board[tf][tr] != NOPIECE) - return 0; - - if (gs->onMove == WHITE) { - if (tr - fr == 1) - return 1; - if (fr == 1 && - (tr - fr) == 2 && - gs->board[ff][2] == NOPIECE) - return 1; - } else { - if (fr - tr == 1) - return 1; - if (fr == 6 && - (fr - tr) == 2 && - gs->board[ff][5] == NOPIECE) - return 1; - } - - return 0; - } - - if (ff != tf) { // Capture ? - if ((ff - tf) != 1 && (tf - ff) != 1) - return 0; - if ((fr - tr) != 1 && (tr - fr) != 1) - return 0; - - if (gs->onMove == WHITE) { - if (fr > tr) - return 0; - if (gs->board[tf][tr] != NOPIECE && - iscolor(gs->board[tf][tr], BLACK)) - return 1; - - if (gs->ep_possible[0][ff] == 1) { - if (tf == (ff + 1) && gs->board[ff + 1][fr] == - B_PAWN) - return 1; - } else if (gs->ep_possible[0][ff] == -1) { - if (tf == (ff - 1) && gs->board[ff - 1][fr] == - B_PAWN) - return 1; - } - } else { - if (tr > fr) - return 0; - if (gs->board[tf][tr] != NOPIECE && - iscolor(gs->board[tf][tr], WHITE)) - return 1; - - if (gs->ep_possible[1][ff] == 1) { - if (tf == (ff + 1) && gs->board[ff + 1][fr] == - W_PAWN) - return 1; - } else if (gs->ep_possible[1][ff] == -1) { - if (tf == (ff - 1) && gs->board[ff - 1][fr] == - W_PAWN) - return 1; - } - } - } - - return 0; + if (ff == tf) { + if (gs->board[tf][tr] != NOPIECE) return 0; + if (gs->onMove == WHITE) { + if (tr - fr == 1) return 1; + if ((fr == 1) && (tr - fr == 2) && gs->board[ff][2]==NOPIECE) return 1; + } else { + if (fr - tr == 1) return 1; + if ((fr == 6) && (fr - tr == 2) && gs->board[ff][5]==NOPIECE) return 1; + } + return 0; + } + if (ff != tf) { /* Capture ? */ + if ((ff - tf != 1) && (tf - ff != 1)) return 0; + if ((fr - tr != 1) && (tr - fr != 1)) return 0; + if (gs->onMove == WHITE) { + if (fr > tr) return 0; + if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK)) + return 1; + if (gs->ep_possible[0][ff] == 1) { + if ((tf==ff+1) && (gs->board[ff+1][fr] == B_PAWN)) return 1; + } else if (gs->ep_possible[0][ff] == -1) { + if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1; + } + } else { + if (tr > fr) return 0; + if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE)) + return 1; + if (gs->ep_possible[1][ff] == 1) { + if ((tf==ff+1) && (gs->board[ff+1][fr] == W_PAWN)) return 1; + } else if (gs->ep_possible[1][ff] == -1) { + if ((tf==ff-1) && (gs->board[ff-1][fr] == W_PAWN)) return 1; + } + } + } + return 0; } -PRIVATE int -legal_knight_move(game_state_t *gs, int ff, int fr, int tf, int tr) +PRIVATE int legal_knight_move(game_state_t * gs, int ff, int fr, int tf, int tr) { - int dx, dy; - - dx = ff - tf; - dy = fr - tr; - - if (dx == 2 || dx == -2) { - if (dy == -1 || dy == 1) - return 1; - } - if (dy == 2 || dy == -2) { - if (dx == -1 || dx == 1) - return 1; - } - - return 0; + int dx, dy; + + dx = ff - tf; + dy = fr - tr; + if ((dx == 2) || (dx == -2)) { + if ((dy == -1) || (dy == 1)) + return 1; + } + if ((dy == 2) || (dy == -2)) { + if ((dx == -1) || (dx == 1)) + return 1; + } + return 0; } -PRIVATE int -legal_bishop_move(game_state_t *gs, int ff, int fr, int tf, int tr) +PRIVATE int legal_bishop_move(game_state_t * gs, int ff, int fr, int tf, int tr) { - int count; - int dx, dy, x, y; - int incx, incy; - int startx, starty; - - if (ff > tf) { - dx = ff - tf; - incx = -1; - } else { - dx = tf - ff; - incx = 1; - } - - startx = ff + incx; - - if (fr > tr) { - dy = fr - tr; - incy = -1; - } else { - dy = tr - fr; - incy = 1; - } - - starty = fr + incy; - - if (dx != dy) - return 0; // Not diagonal - if (dx == 1) - return 1; // One square, ok. - - count = dx - 1; - x = startx; - y = starty; - - while (count) { - if (gs->board[x][y] != NOPIECE) - return 0; - x += incx; - y += incy; - count--; - } - - return 1; + int dx, dy, x, y; + int startx, starty; + int count; + int incx, incy; + + if (ff > tf) { + dx = ff - tf; + incx = -1; + } else { + dx = tf - ff; + incx = 1; + } + startx = ff + incx; + if (fr > tr) { + dy = fr - tr; + incy = -1; + } else { + dy = tr - fr; + incy = 1; + } + starty = fr + incy; + if (dx != dy) + return 0; /* Not diagonal */ + if (dx == 1) + return 1; /* One square, ok */ + count = dx - 1; + for (x = startx, y = starty; count; x += incx, y += incy, count--) { + if (gs->board[x][y] != NOPIECE) + return 0; + } + return 1; } -PRIVATE int -legal_rook_move(game_state_t *gs, int ff, int fr, int tf, int tr) +PRIVATE int legal_rook_move(game_state_t * gs, int ff, int fr, int tf, int tr) { - int i; - int start, stop; - - if (ff == tf) { - if ((fr - tr) == 1 || (tr - fr) == 1) - return 1; - if (fr < tr) { - start = fr + 1; - stop = tr - 1; - } else { - start = tr + 1; - stop = fr - 1; - } - - for (i = start; i <= stop; i++) { - if (gs->board[ff][i] != NOPIECE) - return 0; - } - - return 1; - } else if (fr == tr) { - if ((ff - tf) == 1 || (tf - ff) == 1) - return 1; - if (ff < tf) { - start = ff + 1; - stop = tf - 1; - } else { - start = tf + 1; - stop = ff - 1; - } - - for (i = start; i <= stop; i++) { - if (gs->board[i][fr] != NOPIECE) - return 0; - } - - return 1; - } - + int i; + int start, stop; + + if (ff == tf) { + if (((fr - tr) == 1) || ((tr - fr) == 1)) + return 1; + if (fr < tr) { + start = fr + 1; + stop = tr - 1; + } else { + start = tr + 1; + stop = fr - 1; + } + for (i = start; i <= stop; i++) { + if (gs->board[ff][i] != NOPIECE) + return 0; + } + return 1; + } else if (fr == tr) { + if (((ff - tf) == 1) || ((tf - ff) == 1)) + return 1; + if (ff < tf) { + start = ff + 1; + stop = tf - 1; + } else { + start = tf + 1; + stop = ff - 1; + } + for (i = start; i <= stop; i++) { + if (gs->board[i][fr] != NOPIECE) return 0; + } + return 1; + } else { + return 0; + } } -PRIVATE int -legal_queen_move(game_state_t *gs, int ff, int fr, int tf, int tr) +PRIVATE int legal_queen_move(game_state_t * gs, int ff, int fr, int tf, int tr) { - return (legal_rook_move(gs, ff, fr, tf, tr) || - legal_bishop_move(gs, ff, fr, tf, tr)); + return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr); } -PRIVATE int -is_square_attacked(game_state_t *gs, int kf, int kr) -{ - game_state_t fakeMove; - - fakeMove = *gs; - fakeMove.board[4][kr] = NOPIECE; - fakeMove.board[kf][kr] = (KING | fakeMove.onMove); - fakeMove.onMove = CToggle(fakeMove.onMove); +/* Ckeck, if square (kf,kr) is attacked by enemy piece. + * Used in castling from/through check testing. + */ - if (in_check(&fakeMove)) - return 1; - return 0; +/* new one from soso: */ +PRIVATE int is_square_attacked (game_state_t *gs, int kf, int kr) +{ + game_state_t fakeMove; + + fakeMove = *gs; + fakeMove.board[4][kr] = NOPIECE; + fakeMove.board[kf][kr] = KING | fakeMove.onMove; + fakeMove.onMove = CToggle (fakeMove.onMove); + if (in_check(&fakeMove)) return 1; + else return 0; } -PRIVATE int -legal_king_move(game_state_t *gs, int ff, int fr, int tf, int tr) +/* old one: +PRIVATE int is_square_attacked(game_state_t * gs, int kf, int kr) { - if (gs->onMove == WHITE) { - /* King side castling */ - if (fr == 0 && tr == 0 && ff == 4 && tf == 6 && - !gs->wkmoved && - !gs->wkrmoved && - gs->board[5][0] == NOPIECE && - gs->board[6][0] == NOPIECE && - gs->board[7][0] == W_ROOK && - !is_square_attacked(gs, 4, 0) && - !is_square_attacked(gs, 5, 0)) - return 1; - - /* Queen side castling */ - if (fr == 0 && tr == 0 && ff == 4 && tf == 2 && - !gs->wkmoved && - !gs->wqrmoved && - gs->board[3][0] == NOPIECE && - gs->board[2][0] == NOPIECE && - gs->board[1][0] == NOPIECE && - gs->board[0][0] == W_ROOK && - !is_square_attacked(gs, 4, 0) && - !is_square_attacked(gs, 3, 0)) - return 1; - } else { /* Black */ - /* King side castling */ - if (fr == 7 && tr == 7 && ff == 4 && tf == 6 && - !gs->bkmoved && - !gs->bkrmoved && - gs->board[5][7] == NOPIECE && - gs->board[6][7] == NOPIECE && - gs->board[7][7] == B_ROOK && - !is_square_attacked(gs, 4, 7) && - !is_square_attacked(gs, 5, 7)) - return 1; - - /* Queen side castling */ - if (fr == 7 && tr == 7 && ff == 4 && tf == 2 && - !gs->bkmoved && - !gs->bqrmoved && - gs->board[3][7] == NOPIECE && - gs->board[2][7] == NOPIECE && - gs->board[1][7] == NOPIECE && - gs->board[0][7] == B_ROOK && - !is_square_attacked(gs, 4, 7) && - !is_square_attacked(gs, 3, 7)) - return 1; - } - - if ((ff - tf) > 1 || - (tf - ff) > 1) - return 0; - if ((fr - tr) > 1 || - (tr - fr) > 1) - return 0; - - return 1; + int f, r; + gs->onMove = CToggle(gs->onMove); + + for (InitPieceLoop(gs->board, &f, &r, gs->onMove); + NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + if (legal_move(gs, f, r, kf, kr)) { + gs->onMove = CToggle(gs->onMove); + return 1; + } + } + gs->onMove = CToggle(gs->onMove); + return 0; } +*/ -PRIVATE void -add_pos(int tof, int tor, int *posf, int *posr, int *numpos) +PRIVATE int legal_king_move(game_state_t * gs, int ff, int fr, int tf, int tr) { - posf[*numpos] = tof; - posr[*numpos] = tor; - (*numpos)++; + if (gs->onMove == WHITE) { + /* King side castling */ + if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && !gs->wkmoved + && (!gs->wkrmoved) && (gs->board[5][0] == NOPIECE) && + (gs->board[6][0] == NOPIECE) && (gs->board[7][0] == W_ROOK) && + (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) { + return 1; + } + /* Queen side castling */ + if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && !gs->wkmoved + && (!gs->wqrmoved) && (gs->board[3][0] == NOPIECE) && + (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) && + (gs->board[0][0] == W_ROOK) && + (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) { + return 1; + } + } else { /* Black */ + /* King side castling */ + if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && !gs->bkmoved + && (!gs->bkrmoved) && (gs->board[5][7] == NOPIECE) && + (gs->board[6][7] == NOPIECE) && (gs->board[7][7] == B_ROOK) && + (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) { + return 1; + } + /* Queen side castling */ + if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && (!gs->bkmoved) + && (!gs->bqrmoved) && (gs->board[3][7] == NOPIECE) && + (gs->board[2][7] == NOPIECE) && (gs->board[1][7] == NOPIECE) && + (gs->board[0][7] == B_ROOK) && + (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) { + return 1; + } + } + if (((ff - tf) > 1) || ((tf - ff) > 1)) + return 0; + if (((fr - tr) > 1) || ((tr - fr) > 1)) + return 0; + return 1; } -PRIVATE void -possible_pawn_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void add_pos(int tof, int tor, int *posf, int *posr, int *numpos) { - if (gs->onMove == WHITE) { - if (gs->board[onf][onr + 1] == NOPIECE) { - add_pos(onf, onr + 1, posf, posr, numpos); - - if (onr == 1 && gs->board[onf][onr + 2] == NOPIECE) - add_pos(onf, onr + 2, posf, posr, numpos); - } - - if (onf > 0 && - gs->board[onf - 1][onr + 1] != NOPIECE && - iscolor(gs->board[onf - 1][onr + 1], BLACK)) - add_pos(onf - 1, onr + 1, posf, posr, numpos); - if (onf < 7 && - gs->board[onf + 1][onr + 1] != NOPIECE && - iscolor(gs->board[onf + 1][onr + 1], BLACK)) - add_pos(onf + 1, onr + 1, posf, posr, numpos); - - if (gs->ep_possible[0][onf] == -1) - add_pos(onf - 1, onr + 1, posf, posr, numpos); - if (gs->ep_possible[0][onf] == 1) - add_pos(onf + 1, onr + 1, posf, posr, numpos); - } else { - if (gs->board[onf][onr - 1] == NOPIECE) { - add_pos(onf, onr - 1, posf, posr, numpos); - - if (onr == 6 && gs->board[onf][onr - 2] == NOPIECE) - add_pos(onf, onr - 2, posf, posr, numpos); - } - - if (onf > 0 && - gs->board[onf - 1][onr - 1] != NOPIECE && - iscolor(gs->board[onf - 1][onr - 1], WHITE)) - add_pos(onf - 1, onr - 1, posf, posr, numpos); - if (onf < 7 && - gs->board[onf + 1][onr - 1] != NOPIECE && - iscolor(gs->board[onf + 1][onr - 1], WHITE)) - add_pos(onf + 1, onr - 1, posf, posr, numpos); - - if (gs->ep_possible[1][onf] == -1) - add_pos(onf - 1, onr - 1, posf, posr, numpos); - if (gs->ep_possible[1][onf] == 1) - add_pos(onf + 1, onr - 1, posf, posr, numpos); - } + posf[*numpos] = tof; + posr[*numpos] = tor; + (*numpos)++; } -PRIVATE void -possible_knight_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void possible_pawn_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) { - int f, r; - int j; - static int knightJumps[8][2] = { - {-1, 2}, {1, 2}, {2, -1}, {2, 1}, {-1, -2}, {1, -2}, {-2, 1}, - {-2, -1} - }; - - for (j = 0; j < 8; j++) { - f = knightJumps[j][0] + onf; - r = knightJumps[j][1] + onr; - - if (f < 0 || f > 7) - continue; - if (r < 0 || r > 7) - continue; - - if (gs->board[f][r] == NOPIECE || iscolor(gs->board[f][r], - CToggle(gs->onMove))) - add_pos(f, r, posf, posr, numpos); - } + if (gs->onMove == WHITE) { + if (gs->board[onf][onr + 1] == NOPIECE) { + add_pos(onf, onr + 1, posf, posr, numpos); + if ((onr == 1) && (gs->board[onf][onr + 2] == NOPIECE)) + add_pos(onf, onr + 2, posf, posr, numpos); + } + if ((onf > 0) && (gs->board[onf - 1][onr + 1] != NOPIECE) && + (iscolor(gs->board[onf - 1][onr + 1], BLACK))) + add_pos(onf - 1, onr + 1, posf, posr, numpos); + if ((onf < 7) && (gs->board[onf + 1][onr + 1] != NOPIECE) && + (iscolor(gs->board[onf + 1][onr + 1], BLACK))) + add_pos(onf + 1, onr + 1, posf, posr, numpos); + if (gs->ep_possible[0][onf] == -1) + add_pos(onf - 1, onr + 1, posf, posr, numpos); + if (gs->ep_possible[0][onf] == 1) + add_pos(onf + 1, onr + 1, posf, posr, numpos); + } else { + if (gs->board[onf][onr - 1] == NOPIECE) { + add_pos(onf, onr - 1, posf, posr, numpos); + if ((onr == 6) && (gs->board[onf][onr - 2] == NOPIECE)) + add_pos(onf, onr - 2, posf, posr, numpos); + } + if ((onf > 0) && (gs->board[onf - 1][onr - 1] != NOPIECE) && + (iscolor(gs->board[onf - 1][onr - 1], WHITE))) + add_pos(onf - 1, onr - 1, posf, posr, numpos); +/* loon: changed what looks like a typo, here's the original line: + add_pos(onf - 1, onr + 1, posf, posr, numpos); +*/ + if ((onf < 7) && (gs->board[onf + 1][onr - 1] != NOPIECE) && + (iscolor(gs->board[onf + 1][onr - 1], WHITE))) + add_pos(onf + 1, onr - 1, posf, posr, numpos); + if (gs->ep_possible[1][onf] == -1) + add_pos(onf - 1, onr - 1, posf, posr, numpos); + if (gs->ep_possible[1][onf] == 1) + add_pos(onf + 1, onr - 1, posf, posr, numpos); + } } -PRIVATE void -possible_bishop_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void possible_knight_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) { - int f, r; - - /* Up Left */ - f = onf; - r = onr; - while (1) { - f--; - r++; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Up Right */ - f = onf; - r = onr; - while (1) { - f++; - r++; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Down Left */ - f = onf; - r = onr; - while (1) { - f--; - r--; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Down Right */ - f = onf; - r = onr; - while (1) { - f++; - r--; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } + static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1}, + {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}}; + int f, r; + int j; + + for (j = 0; j < 8; j++) { + f = knightJumps[j][0] + onf; + r = knightJumps[j][1] + onr; + if ((f < 0) || (f > 7)) + continue; + if ((r < 0) || (r > 7)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } } -PRIVATE void -possible_rook_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void possible_bishop_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) { - int f, r; - - /* Left */ - f = onf; - r = onr; - while (1) { - f--; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Right */ - f = onf; - r = onr; - while (1) { - f++; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Up */ - f = onf; - r = onr; - while (1) { - r++; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); - - if (gs->board[f][r] != NOPIECE) - break; - } - - /* Down */ - f = onf; - r = onr; - while (1) { - r--; - - if (f < 0 || f > 7) - break; - if (r < 0 || r > 7) - break; - if (gs->board[f][r] != NOPIECE && iscolor(gs->board[f][r], - gs->onMove)) - break; - - add_pos(f, r, posf, posr, numpos); + int f, r; + + /* Up Left */ + f = onf; + r = onr; + while (1) { + f--; + r++; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Up Right */ + f = onf; + r = onr; + while (1) { + f++; + r++; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down Left */ + f = onf; + r = onr; + while (1) { + f--; + r--; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down Right */ + f = onf; + r = onr; + while (1) { + f++; + r--; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } +} - if (gs->board[f][r] != NOPIECE) - break; - } +PRIVATE void possible_rook_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + int f, r; + + /* Left */ + f = onf; + r = onr; + while (1) { + f--; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Right */ + f = onf; + r = onr; + while (1) { + f++; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Up */ + f = onf; + r = onr; + while (1) { + r++; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down */ + f = onf; + r = onr; + while (1) { + r--; + if ((f < 0) || (f > 7)) + break; + if ((r < 0) || (r > 7)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } } -PRIVATE void -possible_queen_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void possible_queen_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) { - possible_rook_moves(gs, onf, onr, posf, posr, numpos); - possible_bishop_moves(gs, onf, onr, posf, posr, numpos); + possible_rook_moves(gs, onf, onr, posf, posr, numpos); + possible_bishop_moves(gs, onf, onr, posf, posr, numpos); } -PRIVATE void -possible_king_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, - int *numpos) +PRIVATE void possible_king_moves(game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) { - int f, r; - int j; - static int kingJumps[8][2] = { - {-1, -1}, {0, -1}, {1, -1}, {-1, 1}, {0, 1}, {1, 1}, {-1, 0}, - {1, 0} - }; - - for (j = 0; j < 8; j++) { - f = kingJumps[j][0] + onf; - r = kingJumps[j][1] + onr; - - if (f < 0 || f > 7) - continue; - if (r < 0 || r > 7) - continue; - - if (gs->board[f][r] == NOPIECE || iscolor(gs->board[f][r], - CToggle(gs->onMove))) - add_pos(f, r, posf, posr, numpos); - } + static int kingJumps[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 1}, + {0, 1}, {1, 1}, {-1, 0}, {1, 0}}; + int f, r; + int j; + + for (j = 0; j < 8; j++) { + f = kingJumps[j][0] + onf; + r = kingJumps[j][1] + onr; + if ((f < 0) || (f > 7)) + continue; + if ((r < 0) || (r > 7)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } } /* Doesn't check for check */ -PUBLIC int -legal_move(game_state_t *gs, - int fFile, int fRank, - int tFile, int tRank) +PUBLIC int legal_move(game_state_t * gs, + int fFile, int fRank, + int tFile, int tRank) { - int legal; - int move_piece; - - if (fFile == ALG_DROP) { - if ((move_piece = fRank) == KING) - return 0; - if (gs->holding[gs->onMove == WHITE ? 0 : 1][move_piece - 1] - == 0) - return 0; - if (gs->board[tFile][tRank] != NOPIECE) - return 0; - if (move_piece == PAWN && (tRank == 0 || tRank == 7)) - return 0; - return 1; - } else { - move_piece = piecetype(gs->board[fFile][fRank]); - } - - if (gs->board[fFile][fRank] == NOPIECE) - return 0; - if (!iscolor(gs->board[fFile][fRank], gs->onMove)) // Wrong color - return 0; - if (gs->board[tFile][tRank] != NOPIECE && - iscolor(gs->board[tFile][tRank], gs->onMove)) // Can't capture own - return 0; - if (fFile == tFile && fRank == tRank) // Same square - return 0; - - switch (move_piece) { - case PAWN: - legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank); - break; - case KNIGHT: - legal = legal_knight_move(gs, fFile, fRank, tFile, tRank); - break; - case BISHOP: - legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank); - break; - case ROOK: - legal = legal_rook_move(gs, fFile, fRank, tFile, tRank); - break; - case QUEEN: - legal = legal_queen_move(gs, fFile, fRank, tFile, tRank); - break; - case KING: - legal = legal_king_move(gs, fFile, fRank, tFile, tRank); - break; - default: - return 0; - } - - return legal; + int move_piece; + int legal; + + if (fFile == ALG_DROP) { + move_piece = fRank; + if (move_piece == KING) + return 0; + if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0) + return 0; + if (gs->board[tFile][tRank] != NOPIECE) + return 0; + if (move_piece == PAWN && (tRank == 0 || tRank == 7)) + return 0; + return 1; + } else { + move_piece = piecetype(gs->board[fFile][fRank]); + } + if (gs->board[fFile][fRank] == NOPIECE) + return 0; + if (!iscolor(gs->board[fFile][fRank], gs->onMove)) /* Wrong color */ + return 0; + if ((gs->board[tFile][tRank] != NOPIECE) && + iscolor(gs->board[tFile][tRank], gs->onMove)) /* Can't capture own */ + return 0; + if ((fFile == tFile) && (fRank == tRank)) /* Same square */ + return 0; + switch (move_piece) { + case PAWN: + legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank); + break; + case KNIGHT: + legal = legal_knight_move(gs, fFile, fRank, tFile, tRank); + break; + case BISHOP: + legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank); + break; + case ROOK: + legal = legal_rook_move(gs, fFile, fRank, tFile, tRank); + break; + case QUEEN: + legal = legal_queen_move(gs, fFile, fRank, tFile, tRank); + break; + case KING: + legal = legal_king_move(gs, fFile, fRank, tFile, tRank); + break; + default: + return 0; + break; + } + return legal; } + /* * This fills in the rest of the mt structure once it is determined * that. (Returns 'MOVE_ILLEGAL' if move leaves you in check.) @@ -827,11 +698,11 @@ move_calculate(game_state_t *gs, move_t *mt, int promote) if (piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING && mt->fromFile == 4 && mt->toFile == 2) { - strlcpy(mt->moveString, "o-o-o", sizeof mt->moveString); + sprintf(mt->moveString, "o-o-o"); } else if (piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING && mt->fromFile == 4 && mt->toFile == 6) { - strlcpy(mt->moveString, "o-o", sizeof mt->moveString); + sprintf(mt->moveString, "o-o"); } else { ret = snprintf(mt->moveString, sizeof mt->moveString, "%s/%c%d-%c%d", @@ -864,65 +735,57 @@ move_calculate(game_state_t *gs, move_t *mt, int promote) return MOVE_OK; } -PUBLIC int -legal_andcheck_move(game_state_t *gs, int fFile, int fRank, - int tFile, int tRank) +PUBLIC int legal_andcheck_move(game_state_t * gs, + int fFile, int fRank, + int tFile, int tRank) { - move_t mt; - - if (!legal_move(gs, fFile, fRank, tFile, tRank)) - return 0; - - mt.color = gs->onMove; - mt.fromFile = fFile; - mt.fromRank = fRank; - mt.toFile = tFile; - mt.toRank = tRank; - - if (move_calculate(gs, &mt, QUEEN) == MOVE_OK) - return 1; - return 0; + move_t mt; + if (!legal_move(gs, fFile, fRank, tFile, tRank)) + return 0; + mt.color = gs->onMove; + mt.fromFile = fFile; + mt.fromRank = fRank; + mt.toFile = tFile; + mt.toRank = tRank; + /* This should take into account a pawn promoting to another piece */ + if (move_calculate(gs, &mt, QUEEN) == MOVE_OK) + return 1; + else + return 0; } -PUBLIC int -in_check(game_state_t *gs) +PUBLIC int in_check(game_state_t * gs) { - int f, r; - int kf = -1, kr = -1; - - /* Find the king */ - if (gs->onMove == WHITE) { - for (f = 0; f < 8 && kf < 0; f++) { - for (r = 0; r < 8 && kf < 0; r++) { - if (gs->board[f][r] == B_KING) { - kf = f; - kr = r; - } - } - } - } else { - for (f = 0; f < 8 && kf < 0; f++) { - for (r = 0; r < 8 && kf < 0; r++) { - if (gs->board[f][r] == W_KING) { - kf = f; - kr = r; - } - } - } + int f, r; + int kf = -1, kr = -1; + + /* Find the king */ + if (gs->onMove == WHITE) { + for (f = 0; f < 8 && kf < 0; f++) + for (r = 0; r < 8 && kf < 0; r++) + if (gs->board[f][r] == B_KING) { + kf = f; + kr = r; } - - if (kf < 0) { - fprintf(stderr, "FICS: Error game with no king!\n"); - return 0; + } else { + for (f = 0; f < 8 && kf < 0; f++) + for (r = 0; r < 8 && kf < 0; r++) + if (gs->board[f][r] == W_KING) { + kf = f; + kr = r; } - - for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { - if (legal_move(gs, f, r, kf, kr)) // In Check? - return 1; - } - - return 0; + } + if (kf < 0) { + fprintf(stderr, "FICS: Error game with no king!\n"); + return 0; + } + for (InitPieceLoop(gs->board, &f, &r, gs->onMove); + NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + if (legal_move(gs, f, r, kf, kr)) { /* In Check? */ + return 1; + } + } + return 0; } PRIVATE int @@ -1010,68 +873,64 @@ has_legal_move(game_state_t *gs) return 0; } -PUBLIC int -parse_move(char *mstr, game_state_t *gs, move_t *mt, int promote) +/* This will end up being a very complicated function */ +PUBLIC int parse_move(char *mstr, game_state_t * gs, move_t * mt, int promote) { - int result; - int type = is_move(mstr); - - mt->color = gs->onMove; - - switch (type) { - case MS_NOTMOVE: - return MOVE_ILLEGAL; - case MS_COMP: - mt->fromFile = mstr[0] - 'a'; - mt->fromRank = mstr[1] - '1'; - mt->toFile = mstr[2] - 'a'; - mt->toRank = mstr[3] - '1'; - break; - case MS_COMPDASH: - mt->fromFile = mstr[0] - 'a'; - mt->fromRank = mstr[1] - '1'; - mt->toFile = mstr[3] - 'a'; - mt->toRank = mstr[4] - '1'; - break; - case MS_KCASTLE: - mt->fromFile = 4; - mt->toFile = 6; - - if (gs->onMove == WHITE) { - mt->fromRank = 0; - mt->toRank = 0; - } else { - mt->fromRank = 7; - mt->toRank = 7; - } - - break; - case MS_QCASTLE: - mt->fromFile = 4; - mt->toFile = 2; - - if (gs->onMove == WHITE) { - mt->fromRank = 0; - mt->toRank = 0; - } else { - mt->fromRank = 7; - mt->toRank = 7; - } - - break; - case MS_ALG: - /* Fills in the mt structure */ - if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK) - return result; - break; - default: - return MOVE_ILLEGAL; - } - - if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) - return MOVE_ILLEGAL; - - return move_calculate(gs, mt, promote); + int type = is_move(mstr); + int result; + + mt->color = gs->onMove; + switch (type) { + case MS_NOTMOVE: + return MOVE_ILLEGAL; + break; + case MS_COMP: + mt->fromFile = mstr[0] - 'a'; + mt->fromRank = mstr[1] - '1'; + mt->toFile = mstr[2] - 'a'; + mt->toRank = mstr[3] - '1'; + break; + case MS_COMPDASH: + mt->fromFile = mstr[0] - 'a'; + mt->fromRank = mstr[1] - '1'; + mt->toFile = mstr[3] - 'a'; + mt->toRank = mstr[4] - '1'; + break; + case MS_KCASTLE: + mt->fromFile = 4; + mt->toFile = 6; + if (gs->onMove == WHITE) { + mt->fromRank = 0; + mt->toRank = 0; + } else { + mt->fromRank = 7; + mt->toRank = 7; + } + break; + case MS_QCASTLE: + mt->fromFile = 4; + mt->toFile = 2; + if (gs->onMove == WHITE) { + mt->fromRank = 0; + mt->toRank = 0; + } else { + mt->fromRank = 7; + mt->toRank = 7; + } + break; + case MS_ALG: + /* Fills in the mt structure */ + if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK) + return result; + break; + default: + return MOVE_ILLEGAL; + break; + } + if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) { + return MOVE_ILLEGAL; + } + return move_calculate(gs, mt, promote); } /* @@ -1266,369 +1125,260 @@ execute_move(game_state_t *gs, move_t *mt, int check_game_status) return MOVE_OK; } -PRIVATE void -piecetype_rook(int g, int mode, game_state_t *gs, move_t *m, move_t **m1) +PUBLIC int backup_move(int g, int mode) { - int i; - - if (m->color == WHITE) { - if (m->fromFile == 0 && m->fromRank == 0) { - for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { - *m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if ((*m1)->fromFile == 0 && - (*m1)->fromRank == 0) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->wqrmoved = 0; - } - - if (m->fromFile == 7 && m->fromRank == 0) { - for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { - *m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if ((*m1)->fromFile == 7 && - (*m1)->fromRank == 0) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->wkrmoved = 0; - } - } else { - if (m->fromFile == 0 && m->fromRank == 7) { - for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { - *m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if ((*m1)->fromFile == 0 && - (*m1)->fromRank == 0) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->bqrmoved = 0; - } - - if (m->fromFile == 7 && m->fromRank == 7) { - for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { - *m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if ((*m1)->fromFile == 7 && - (*m1)->fromRank == 0) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->bkrmoved = 0; - } + game_state_t *gs; + move_t *m, *m1; + int now, i; + + if (garray[g].link >= 0) /*IanO: not implemented for bughouse yet */ + return MOVE_ILLEGAL; + if (garray[g].numHalfMoves < 1) + return MOVE_ILLEGAL; + gs = &garray[g].game_state; + m = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : + &garray[g].examMoveList[garray[g].numHalfMoves - 1]; + if (m->toFile < 0) { + return MOVE_ILLEGAL; + } + gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank]; + if (m->piecePromotionTo != NOPIECE) { + gs->board[m->fromFile][m->fromRank] = PAWN | + colorval(gs->board[m->fromFile][m->fromRank]); + } + /****************** + When takeback a _first_ move of rook, the ??rmoved variable + must be cleared . To check, if the move is first, we should + scan moveList. + *******************/ + if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) { + if (m->color == WHITE) { + if ((m->fromFile == 0) && (m->fromRank == 0)) { + for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 0) && (m1->fromRank == 0)) + break; } -} - -#ifdef TIMESEAL -PRIVATE void -backup_move_timeseal_block(int g, move_t *m) -{ - if (m->color == WHITE) { - if (con[parray[garray[g].white].socket].timeseal) { - garray[g].wRealTime += (m->tookTime * 100); - garray[g].wRealTime -= (garray[g].wIncrement * 100); - garray[g].wTime = (garray[g].wRealTime / 100); - - if (con[parray[garray[g].black].socket].timeseal) { - garray[g].bTime = (garray[g].bRealTime / 100); - } else { // Opp has no timeseal - garray[g].bTime += (garray[g].lastDecTime - - garray[g].lastMoveTime); - } - } else { // White has no timeseal - garray[g].wTime += m->tookTime; - garray[g].wTime -= garray[g].wIncrement; - - if (con[parray[garray[g].black].socket].timeseal) { - garray[g].bTime = (garray[g].bRealTime / 100); - } else { // Opp has no timeseal - garray[g].bTime += (garray[g].lastDecTime - - garray[g].lastMoveTime); - } - } - } else { - if (con[parray[garray[g].black].socket].timeseal) { - garray[g].bRealTime += (m->tookTime * 100); - garray[g].bRealTime -= (garray[g].wIncrement * 100); - garray[g].bTime = (garray[g].bRealTime / 100); - - if (con[parray[garray[g].white].socket].timeseal) { - garray[g].wTime = (garray[g].wRealTime / 100); - } else { // Opp has no timeseal - garray[g].wTime += (garray[g].lastDecTime - - garray[g].lastMoveTime); - } - } else { // Black has no timeseal - garray[g].bTime += m->tookTime; - - if (!garray[g].bIncrement) - garray[g].bTime -= garray[g].wIncrement; - else - garray[g].bTime -= garray[g].bIncrement; - - if (con[parray[garray[g].white].socket].timeseal) { - garray[g].wTime = (garray[g].wRealTime / 100); - } else { // Opp has no timeseal - garray[g].wTime += (garray[g].lastDecTime - - garray[g].lastMoveTime); - } - } + if (i == garray[g].numHalfMoves - 1) + gs->wqrmoved = 0; + } + if ((m->fromFile == 7) && (m->fromRank == 0)) { + for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 7) && (m1->fromRank == 0)) + break; } -} -#endif // TIMESEAL - -PRIVATE void -update_enpassant_array(int g, int mode, game_state_t *gs) -{ - move_t *m1; - - if (!(garray[g].numHalfMoves > 0)) - return; - - m1 = ((mode == REL_GAME) - ? &garray[g].moveList[garray[g].numHalfMoves - 1] - : &garray[g].examMoveList[garray[g].numHalfMoves - 1]); - - if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) { - if ((m1->toRank - m1->fromRank) == 2) { - if (m1->toFile < 7 && - gs->board[m1->toFile + 1][3] == B_PAWN) - gs->ep_possible[1][m1->toFile + 1] = -1; - if (m1->toFile - 1 >= 0 && - gs->board[m1->toFile - 1][3] == B_PAWN) - gs->ep_possible[1][m1->toFile - 1] = 1; - } - - if ((m1->toRank - m1->fromRank) == -2) { - if (m1->toFile < 7 && - gs->board[m1->toFile + 1][4] == W_PAWN) - gs->ep_possible[0][m1->toFile + 1] = -1; - if (m1->toFile - 1 >= 0 && - gs->board[m1->toFile - 1][4] == W_PAWN) - gs->ep_possible[0][m1->toFile - 1] = 1; - } + if (i == garray[g].numHalfMoves - 1) + gs->wkrmoved = 0; + } + } else { + if ((m->fromFile == 0) && (m->fromRank == 7)) { + for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 0) && (m1->fromRank == 0)) + break; } -} - -PRIVATE void -clean_up_doit(int g, int mode, game_state_t *gs, move_t *m) -{ - unsigned int now; - - if (garray[g].status != GAME_EXAMINE) - game_update_time(g); - - garray[g].numHalfMoves--; + if (i == garray[g].numHalfMoves - 1) + gs->bqrmoved = 0; + } + if ((m->fromFile == 7) && (m->fromRank == 7)) { + for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 7) && (m1->fromRank == 0)) + break; + } + if (i == garray[g].numHalfMoves - 1) + gs->bkrmoved = 0; + } + } + } + if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) { + gs->board[m->toFile][m->toRank] = m->pieceCaptured; + + if (m->toFile - m->fromFile == 2) { + gs->board[7][m->fromRank] = ROOK | + colorval(gs->board[m->fromFile][m->fromRank]); + gs->board[5][m->fromRank] = NOPIECE; + + /******** + If takeback a castling, the appropriates ??moved variables + must be cleared + ********/ + if (m->color == WHITE) { + gs->wkmoved = 0; + gs->wkrmoved = 0; + } else { + gs->bkmoved = 0; + gs->bkrmoved = 0; + } + goto cleanupMove; + } + if (m->fromFile - m->toFile == 2) { + gs->board[0][m->fromRank] = ROOK | + colorval(gs->board[m->fromFile][m->fromRank]); + gs->board[3][m->fromRank] = NOPIECE; + + /********** + If takeback a castling, the appropriate ??moved variables + must be cleared + ***********/ + if (m->color == WHITE) { + gs->wkmoved = 0; + gs->wqrmoved = 0; + } else { + gs->bkmoved = 0; + gs->bqrmoved = 0; + } + goto cleanupMove; + } + /****************** + When takeback a _first_ move of king (not the castling), + the ?kmoved variable must be cleared . To check, if the move is first, + we should scan moveList. + *******************/ + + if (m->color == WHITE) { + + if ((m->fromFile == 4) && (m->fromRank == 0)) { + for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 4) && (m1->fromRank == 0)) + break; + } + if (i == garray[g].numHalfMoves - 1) + gs->wkmoved = 0; + } + } else { + if ((m->fromFile == 4) && (m->fromRank == 7)) { + for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; + if ((m1->fromFile == 4) && (m1->fromRank == 7)) + break; + } + if (i == garray[g].numHalfMoves - 1) + gs->bkmoved = 0; + } + } + } + if (m->enPassant) { /* Do enPassant */ + gs->board[m->toFile][m->fromRank] = PAWN | + (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE); + gs->board[m->toFile][m->toRank] = NOPIECE; + /* Should set the enpassant array, but I don't care right now */ + goto cleanupMove; + } + gs->board[m->toFile][m->toRank] = m->pieceCaptured; +cleanupMove: + if (garray[g].status != GAME_EXAMINE) { + game_update_time(g); + } + garray[g].numHalfMoves--; + if (garray[g].status != GAME_EXAMINE) { + if (garray[g].wInitTime) { /* Don't update times in untimed games */ + now = tenth_secs(); - if (garray[g].status != GAME_EXAMINE) { - if (garray[g].wInitTime) { // Don't update times in untimed - // games. - now = tenth_secs(); #ifdef TIMESEAL - backup_move_timeseal_block(g, m); -#else - if (m->color == WHITE) { - garray[g].wTime += m->tookTime; - garray[g].wTime = (garray[g].wTime - - garray[g].wIncrement); - garray[g].bTime += - (garray[g].lastDecTime - - garray[g].lastMoveTime); - } else { - garray[g].bTime += m->tookTime; - - if (!garray[g].bIncrement) { - garray[g].bTime = - (garray[g].bTime - - garray[g].wIncrement); - } else { - garray[g].bTime = - (garray[g].bTime - - garray[g].bIncrement); - } - garray[g].wTime += (garray[g].lastDecTime - - garray[g].lastMoveTime); - } -#endif - - if (garray[g].numHalfMoves == 0) - garray[g].timeOfStart = now; - garray[g].lastMoveTime = now; - garray[g].lastDecTime = now; - } + if (m->color == WHITE) { + if (con[parray[garray[g].white].socket].timeseal) { /* white uses timeseal? */ + garray[g].wRealTime += (m->tookTime * 100); + garray[g].wRealTime -= (garray[g].wIncrement * 100); + garray[g].wTime = garray[g].wRealTime / 100; + if (con[parray[garray[g].black].socket].timeseal) { /* opp uses timeseal? */ + garray[g].bTime = garray[g].bRealTime / 100; + } else { /* opp has no timeseal */ + garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } + } else { /* white has no timeseal */ + garray[g].wTime += m->tookTime; + garray[g].wTime -= garray[g].wIncrement; + if (con[parray[garray[g].black].socket].timeseal) { /* opp uses timeseal? */ + garray[g].bTime = garray[g].bRealTime / 100; + } else { /* opp has no timeseal */ + garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } } - - if (gs->onMove == BLACK) { - gs->onMove = WHITE; - } else { - gs->onMove = BLACK; - gs->moveNum--; + } else { + if (con[parray[garray[g].black].socket].timeseal) { /* black uses timeseal? */ + garray[g].bRealTime += (m->tookTime * 100); + garray[g].bRealTime -= (garray[g].wIncrement * 100); + garray[g].bTime = garray[g].bRealTime / 100; + if (con[parray[garray[g].white].socket].timeseal) { /* opp uses timeseal? */ + garray[g].wTime = garray[g].wRealTime / 100; + } else { /* opp has no timeseal */ + garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } + } else { /* black has no timeseal */ + garray[g].bTime += m->tookTime; + if (!garray[g].bIncrement) + garray[g].bTime -= garray[g].wIncrement; + else + garray[g].bTime -= garray[g].bIncrement; + if (con[parray[garray[g].white].socket].timeseal) { /* opp uses timeseal? */ + garray[g].wTime = garray[g].wRealTime / 100; + } else { /* opp has no timeseal */ + garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } } + } - /* - * takeback of last move is done already. It's time to update - * enpassant array... - */ - update_enpassant_array(g, mode, gs); -} - -PUBLIC int -backup_move(int g, int mode) -{ - game_state_t *gs; - int i; - move_t *m, *m1; - - if (garray[g].link >= 0) // Not implemented for bughouse yet. - return MOVE_ILLEGAL; - if (garray[g].numHalfMoves < 1) - return MOVE_ILLEGAL; - - gs = &garray[g].game_state; - m = ((mode == REL_GAME) - ? &garray[g].moveList[garray[g].numHalfMoves - 1] - : &garray[g].examMoveList[garray[g].numHalfMoves - 1]); +#else - if (m->toFile < 0) - return MOVE_ILLEGAL; + if (m->color == WHITE) { + garray[g].wTime += m->tookTime; + garray[g].wTime = garray[g].wTime - garray[g].wIncrement; + garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } else { + garray[g].bTime += m->tookTime; + if (!garray[g].bIncrement) + garray[g].bTime = garray[g].bTime - garray[g].wIncrement; + else + garray[g].bTime = garray[g].bTime - garray[g].bIncrement; + garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime); + } - gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank]; +#endif - if (m->piecePromotionTo != NOPIECE) { - gs->board[m->fromFile][m->fromRank] = (PAWN | - colorval(gs->board[m->fromFile][m->fromRank])); + if (garray[g].numHalfMoves == 0) + garray[g].timeOfStart = now; + garray[g].lastMoveTime = now; + garray[g].lastDecTime = now; + } + } + if (gs->onMove == BLACK) + gs->onMove = WHITE; + else { + gs->onMove = BLACK; + gs->moveNum--; + } + + /******* Here begins the patch : ******************************** + Takeback of last move is done already, it's time to update enpassant + array. (patch from Soso, added by Sparky 3/17/95) + ********/ + + if (garray[g].numHalfMoves > 0) { + m1 = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : + &garray[g].examMoveList[garray[g].numHalfMoves - 1]; + if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) { + if ((m1->toRank - m1->fromRank) == 2) { + if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) { + gs->ep_possible[1][m1->toFile + 1] = -1; } - - /* - * When takeback a _first_ move of rook, the ??rmoved - * variable must be cleared. To check if the move is first we - * should the scan move list. - */ - if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) - piecetype_rook(g, mode, gs, m, &m1); - - if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) { - gs->board[m->toFile][m->toRank] = m->pieceCaptured; - - if (m->toFile - m->fromFile == 2) { - gs->board[7][m->fromRank] = (ROOK | - colorval(gs->board[m->fromFile][m->fromRank])); - gs->board[5][m->fromRank] = NOPIECE; - - /* - * If takeback a castling, the appropriates - * ??moved variables must be cleared. - */ - if (m->color == WHITE) { - gs->wkmoved = 0; - gs->wkrmoved = 0; - } else { - gs->bkmoved = 0; - gs->bkrmoved = 0; - } - - goto cleanupMove; - } - - if (m->fromFile - m->toFile == 2) { - gs->board[0][m->fromRank] = (ROOK | - colorval(gs->board[m->fromFile][m->fromRank])); - gs->board[3][m->fromRank] = NOPIECE; - - /* - * If takeback a castling, the appropriate - * ??moved variables must be cleared. - */ - if (m->color == WHITE) { - gs->wkmoved = 0; - gs->wqrmoved = 0; - } else { - gs->bkmoved = 0; - gs->bqrmoved = 0; - } - - goto cleanupMove; - } - - /* - * When takeback a _first_ move of king (not the - * castling), the ?kmoved variable must be cleared. To - * check if the move is first we should scan the move - * list. - */ - if (m->color == WHITE) { - if (m->fromFile == 4 && m->fromRank == 0) { - for (i = 2; - i < garray[g].numHalfMoves - 1; - i += 2) { - m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if (m1->fromFile == 4 && - m1->fromRank == 0) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->wkmoved = 0; - } - } else { - if (m->fromFile == 4 && m->fromRank == 7) { - for (i = 3; - i < garray[g].numHalfMoves - 1; - i += 2) { - m1 = ((mode == REL_GAME) - ? &garray[g].moveList[i] - : &garray[g].examMoveList[i]); - - if (m1->fromFile == 4 && - m1->fromRank == 7) - break; - } - - if (i == (garray[g].numHalfMoves - 1)) - gs->bkmoved = 0; - } - } + if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) { + gs->ep_possible[1][m1->toFile - 1] = 1; } - - if (m->enPassant) { - if (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE) - gs->board[m->toFile][m->fromRank] = (PAWN | BLACK); - else - gs->board[m->toFile][m->fromRank] = (PAWN | WHITE); - - gs->board[m->toFile][m->toRank] = NOPIECE; - - /* - * Should set the enpassant array. But I don't care - * right now. - */ - goto cleanupMove; + } + if ((m1->toRank - m1->fromRank) == -2) { + if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) { + gs->ep_possible[0][m1->toFile + 1] = -1; } - - gs->board[m->toFile][m->toRank] = m->pieceCaptured; - - cleanupMove: - - clean_up_doit(g, mode, gs, m); - - return MOVE_OK; + if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) { + gs->ep_possible[0][m1->toFile - 1] = 1; + } + } + } + } + /************** and here's the end **************/ + return MOVE_OK; } diff --git a/FICS/movecheck.h b/FICS/movecheck.h index 9cd65c8..53a1712 100644 --- a/FICS/movecheck.h +++ b/FICS/movecheck.h @@ -19,26 +19,25 @@ /* Revision history: name email yy/mm/dd Change - Richard Nash 93/10/22 Created - Markus Uhlin 24/03/17 Revised + Richard Nash 93/10/22 Created */ #ifndef _MOVECHECK_H #define _MOVECHECK_H -#define MOVE_OK 0 -#define MOVE_ILLEGAL 1 -#define MOVE_STALEMATE 2 -#define MOVE_CHECKMATE 3 -#define MOVE_AMBIGUOUS 4 -#define MOVE_NOMATERIAL 5 +#define MOVE_OK 0 +#define MOVE_ILLEGAL 1 +#define MOVE_STALEMATE 2 +#define MOVE_CHECKMATE 3 +#define MOVE_AMBIGUOUS 4 +#define MOVE_NOMATERIAL 5 -#define MS_NOTMOVE 0 -#define MS_COMP 1 -#define MS_COMPDASH 2 -#define MS_ALG 3 -#define MS_KCASTLE 4 -#define MS_QCASTLE 5 +#define MS_NOTMOVE 0 +#define MS_COMP 1 +#define MS_COMPDASH 2 +#define MS_ALG 3 +#define MS_KCASTLE 4 +#define MS_QCASTLE 5 #define isrank(c) (((c) <= '8') && ((c) >= '1')) #define isfile(c) (((c) >= 'a') && ((c) <= 'h')) @@ -47,15 +46,16 @@ #include "board.h" #endif -extern int InitPieceLoop(board_t, int *, int *, int); -extern int NextPieceLoop(board_t, int *, int *, int); - -extern int backup_move(int, int); -extern int execute_move(game_state_t *, move_t *, int); -extern int in_check(game_state_t *); -extern int is_move(char *); -extern int legal_andcheck_move(game_state_t *, int, int, int, int); -extern int legal_move(game_state_t *, int, int, int, int); -extern int parse_move(char *, game_state_t *, move_t *, int); +extern int is_move(char *); +extern int parse_move(char *, game_state_t *, move_t *, int); +extern int execute_move(game_state_t *, move_t *, int); +extern int backup_move(int, int); + +/* Some useful chess utilities */ +extern int NextPieceLoop(board_t, int *, int *, int); +extern int InitPieceLoop(board_t, int *, int *, int); +extern int legal_move(game_state_t *, int, int, int, int); +extern int legal_andcheck_move(game_state_t *, int, int, int, int); +extern int in_check(game_state_t *); #endif /* _MOVECHECK_H */ -- cgit v1.2.3