/* algcheck.c * */ /* icds - Internet Checkers and Draughts Server Copyright (C) 1997 Michael Rohrer 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 Michael Rohrer 97/05/01 Modified */ #include "stdinclude.h" #include "common.h" #include "algcheck.h" #include "movecheck.h" #include "board.h" #include "utils.h" #include "gamedb.h" /* Well, lets see if I can list the possibilities * d2c3 * d2-c3 * 12-15 PDN * In the future, this stuff must be changed */ /* f - file * r - rank * p - piece */ char *alg_list[] = { "frfr", "fr-fr", NULL }; #define ALG_UNKNOWN -1 PRIVATE int get_move_info(char *str, int *piece, int *ff, int *fr, int *tf, int *tr, int *bishconfusion) { char tmp[1024]; int i, j, len; int matchVal = -1; int lff, lfr, ltf, ltr; strcpy(tmp, str); *piece = *ff = *fr = *tf = *tr = ALG_UNKNOWN; len = strlen(tmp); for (i = 0; alg_list[i]; i++) { 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] > 'j')) { goto nomatch; } if (ltf == ALG_UNKNOWN) ltf = tmp[j] - 'a'; else lff = tmp[j] - 'a'; break; case 'r': if ((tmp[j] < '0') || (tmp[j] > '9')) { goto nomatch; } if (ltr == ALG_UNKNOWN) { if (tmp[j] == '0') { ltr = 9; } else { ltr = tmp[j] - '1'; } } else { if (tmp[j] == '0') { lfr = 9; } else { lfr = tmp[j] - '1'; } } break; case '-': if ((tmp[j] != 'x') && (tmp[j] != 'X')) { goto nomatch; } break; default: fprintf(stderr, "Unknown character in algebraic parsing\n"); break; } } #if 0 if (lpiece == PIECE && (lfr == ALG_UNKNOWN)) { /* ffr or ff */ if (lff != ALG_UNKNOWN) { if (lff == ltf) goto nomatch; if ((lff - ltf != 1) && (ltf - lff != 1)) goto nomatch; } } #endif *tf = ltf; /* We have a match */ *tr = ltr; *ff = lff; *fr = lfr; #if 0 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; } #endif 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, "ICDS: 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 != PIECE) { 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, gs);) { 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 0 /* 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) { } else { if (iscolor(gs->board[tf][tmpr], gs->onMove)) continue; } #endif 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 { /* 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, gs);) { 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; } } ff = posf; fr = posr; } } if ((tf == ALG_UNKNOWN) || (tr == ALG_UNKNOWN) || (ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) { return MOVE_ILLEGAL; } mt->square[0].file = ff; mt->square[0].rank = fr; mt->square[1].file = tf; mt->square[1].rank = tr; return MOVE_OK; } /* 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 type; /* int piece; */ /* int ambig, r_ambig, f_ambig; */ /* piece = piecetype(gs->board[mt->square[0].file][mt->square[0].rank]); */ strcpy(mStr, ""); #if 0 /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */ if (ambig > 0) { /* Ambiguity in short notation, need to add file,rank or _both_ in notation */ if (f_ambig == 0) { sprintf(tmp, "%c", mt->square[0].file + 'a'); strcat(mStr, tmp); } else if (r_ambig == 0) { sprintf(tmp, "%d", mt->square[0].rank + 1); strcat(mStr, tmp); } else { sprintf(tmp, "%c%d", mt->square[0].file + 'a', mt->square[0].rank + 1); strcat(mStr, tmp); } } #endif /* this is so moves2pdn can get the correct board size */ if (garray[gs->gameNum].type == TYPE_POLISH) { type = TYPE_POLISH; } else { type = TYPE_BRITISH; } /* sprintf(tmp, "%c%d%c%d", mt->square[0].file + 'a', mt->square[0].rank + 1, mt->square[1].file + 'a', mt->square[1].rank + 1); */ sprintf(tmp, "%d%c%d", moves2pdn(mt->square[0].rank, mt->square[0].file, type), '-', moves2pdn(mt->square[1].rank, mt->square[1].file, type)); strcat(mStr, tmp); #if 0 /*Infinite loop in execute_move */ /* check:; */ fakeMove = *gs; execute_move(&fakeMove, mt, g); fakeMove.onMove = CToggle(fakeMove.onMove); #endif return mStr; } /* Function to convert a move in pdn to row, column format */ /* Current mt number passed in to help function know where to fill * the moves in at. */ /* Also, made to handle either polish or spanish boards */ PUBLIC int pdn2moves(int* rank, int* file, int type, int pdnumber) { int drank = 0; int dfile = 0; if (type == TYPE_POLISH) { /* Polish Board */ drank = pdnumber / 5; dfile = 9 - 2 * (pdnumber % 5); /* to compensate for those numbers evenly divisble by 4 */ if (dfile == 9) { drank--; dfile = -1; } dfile++; if (drank % 2 == 1) { dfile++; } /* Because I'm too lazy to rewrite this! */ /* Besides, I may end up changing the board later */ *rank = abs(drank - 9); *file = abs(dfile - 9); } else { /* Standard board size */ drank = pdnumber / 4; dfile = 7 - 2 * (pdnumber % 4); if (dfile == 7) { drank--; dfile = -1; } dfile++; if (type == TYPE_SPANISH) { /* Spanish Board */ if (drank % 2 == 0) { dfile++; } fprintf(stderr, "Spanish Move: %i %i\n", drank, dfile); } else { /* British or Pool */ if (drank % 2 == 1) { dfile++; } } /* Because I'm too lazy to rewrite this! */ /* Besides, I may end up changing the board later */ *rank = abs(drank - 7); *file = abs(dfile - 7); } return 1; } /* The opposite of previous function: converts a row, col to a pdn number. * PDN number returned by function. This will likely be used in * string parsing for commands like smoves, mailmoves, etc., and also in * showing previous move made. */ PUBLIC int moves2pdn(int rank, int file, int type) { int pdnnumber = 0; if (type == TYPE_POLISH) { /* Polish Board */ pdnnumber = (9 - rank) * 5; pdnnumber += (file / 2); } else { /* Standard board size */ pdnnumber = (7 - rank) * 4; if (type == TYPE_SPANISH) { file++; } pdnnumber += (file / 2); } pdnnumber++; return pdnnumber; }