2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* Well, lets see if I can list the possibilities
38 * Drop moves (bughouse, board edit)
41 * (o-o, o-o-o) Castling is handled earlier, so don't worry about that
42 * Of course any of these can have a + or ++ or = string on the end, just
50 * @ - drop character (bughouse)
52 static char *alg_list[] = {
53 "fxfr", "pxfr", /* These two get confused in case of bishop */
54 "ffr", "pfr", /* These two get confused in case of bishop */
68 #define ALG_UNKNOWN -1
70 static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf, int *tr, int *bishconfusion)
77 int lpiece, lff, lfr, ltf, ltr;
80 strlcpy(tmp, str, sizeof(tmp));
81 if ((s = strchr(tmp, '+'))) { /* Cut off any check marks */
84 if ((s = strchr(tmp, '='))) { /* Cut off any promotion marks */
87 if ((s = strchr(tmp, '#'))) { /* Cut off any 'mates' marks */
90 *piece = *ff = *fr = *tf = *tr = ALG_UNKNOWN;
92 for (i = 0; alg_list[i]; i++) {
93 lpiece = lff = lfr = ltf = ltr = ALG_UNKNOWN;
94 if (strlen(alg_list[i]) != len)
96 for (j = len - 1; j >= 0; j--) {
97 switch (alg_list[i][j]) {
99 if ((tmp[j] < 'a') || (tmp[j] > 'h'))
101 if (ltf == ALG_UNKNOWN)
107 if ((tmp[j] < '1') || (tmp[j] > '8'))
109 if (ltr == ALG_UNKNOWN)
135 if ((tmp[j] != 'x') && (tmp[j] != 'X'))
139 if (tmp[j] != '@' && tmp[j] != '*')
141 lff = lfr = ALG_DROP;
146 lff = lfr = ALG_DROP;
149 d_printf( "Unknown character in algebraic parsing\n");
153 if (lpiece == ALG_UNKNOWN)
155 if (lpiece == PAWN && (lfr == ALG_UNKNOWN)) { /* ffr or ff */
156 if (lff != ALG_UNKNOWN) {
159 if ((lff - ltf != 1) && (ltf - lff != 1))
163 *piece = lpiece; /* We have a match */
168 if (matchVal != -1) {
169 /* We have two matches, it must be that Bxc4 vs. bxc4 problem */
170 /* Or it could be the Bc4 vs bc4 problem */
182 int alg_is_move(const char *mstr)
184 int piece=0, ff=0, fr=0, tf=0, tr=0, bc=0;
186 return get_move_info(mstr, &piece, &ff, &fr, &tf, &tr, &bc);
189 /* add any promotion qualifier from a move string */
190 static void add_promotion(struct game_state_t *gs, const char *mstr, struct move_t * mt)
194 s = strchr(mstr, '=');
199 if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) {
202 if (mt->toRank != 7 && mt->toRank != 0) {
206 switch (tolower(s[1])) {
223 mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]);
226 /* We already know it is algebraic, get the move squares */
227 int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
229 int f=0, r=0, tmpr=0, posf=0, posr=0, posr2=0;
230 int piece=0, ff=0, fr=0, tf=0, tr=0, bc=0;
232 if (get_move_info(mstr, &piece, &ff, &fr, &tf, &tr, &bc) != MS_ALG) {
233 d_printf( "CHESSD: Shouldn't try to algebraicly parse non-algabraic move string.\n");
236 /* Resolve ambiguities in to-ness */
237 if (tf == ALG_UNKNOWN) {
238 d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
239 return MOVE_AMBIGUOUS; /* Must always know to file */
241 if (tr == ALG_UNKNOWN) {
242 posr = posr2 = ALG_UNKNOWN;
244 d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
245 return MOVE_AMBIGUOUS;
247 if (ff == ALG_UNKNOWN) {
248 d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
249 return MOVE_AMBIGUOUS;
251 /* Need to find pawn on ff that can take to tf and fill in ranks */
252 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
253 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
254 if ((ff != ALG_UNKNOWN) && (ff != f))
256 if (piecetype(gs->board[f][r]) != piece)
258 if (gs->onMove == WHITE) {
263 /* if ((gs->board[tf][tmpr] == NOPIECE) ||
264 (iscolor(gs->board[tf][tmpr], gs->onMove))) continue;*/
265 /* patch from Soso, added by Sparky 3/16/95 */
266 if (gs->board[tf][tmpr] == NOPIECE) {
267 if ((gs->ep_possible[((gs->onMove == WHITE) ? 0 : 1)][ff]) != (tf - ff))
270 if (iscolor(gs->board[tf][tmpr], gs->onMove))
274 if (legal_andcheck_move(gs, f, r, tf, tmpr)) {
275 if ((posr != ALG_UNKNOWN) && (posr2 != ALG_UNKNOWN)) {
276 d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
277 return MOVE_AMBIGUOUS;
285 } else if (bc) { /* Could be bxc4 or Bxc4, tr is known */
288 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
289 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
290 if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != BISHOP)) {
293 if (legal_andcheck_move(gs, f, r, tf, tr)) {
294 if ((piecetype(gs->board[f][r]) == PAWN) && (f != 1)) {
298 /* if its a lowercase 'b' then prefer the pawn move if there is one */
299 if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
300 piecetype(gs->board[f][r]) == PAWN && mstr[0] == 'b') {
306 if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
307 piecetype(gs->board[ff][fr]) == PAWN && mstr[0] == 'b') {
311 if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN)) {
312 d_printf("Ambiguous %s(%d) mstr=%s\n", __FUNCTION__, __LINE__, mstr);
313 return (MOVE_AMBIGUOUS);
319 } else { /* The from position is unknown */
322 if ((ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) {
323 /* Need to find a piece that can go to tf, tr */
324 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
325 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
326 if ((ff != ALG_UNKNOWN) && (ff != f))
328 if ((fr != ALG_UNKNOWN) && (fr != r))
330 if (piecetype(gs->board[f][r]) != piece)
332 if (legal_andcheck_move(gs, f, r, tf, tr)) {
333 if ((posf != ALG_UNKNOWN) && (posr != ALG_UNKNOWN)) {
334 d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
335 return MOVE_AMBIGUOUS;
341 } else if (ff == ALG_DROP) {
342 if (legal_andcheck_move(gs, ALG_DROP, piece, tf, tr)) {
350 if ((tf == ALG_UNKNOWN) || (tr == ALG_UNKNOWN) ||
351 (ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN))
358 add_promotion(gs, mstr, mt);
363 /* A assumes the move has yet to be made on the board */
365 /* Soso: rewrote alg_unparse function.
366 * Algebraic deparser - sets the mStr variable with move description
367 * in short notation. Used in last move report and in 'moves' command.
370 char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
372 static char mStr[20];
375 int ambig, r_ambig, f_ambig;
376 struct game_state_t fakeMove;
378 if (mt->fromFile == ALG_DROP) {
379 piece = mt->fromRank;
381 piece = piecetype(gs->board[mt->fromFile][mt->fromRank]);
384 if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 6))) {
388 if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 2))) {
389 strcpy(mStr, "O-O-O");
395 if (mt->fromFile == ALG_DROP) {
397 } else if (mt->fromFile != mt->toFile) {
398 sprintf(tmp, "%c", mt->fromFile + 'a');
422 if (mt->fromFile == ALG_DROP) {
425 /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */
427 ambig = r_ambig = f_ambig = 0;
428 for (r = 0; r < 8; r++)
429 for (f = 0; f < 8; f++) {
430 if ((gs->board[f][r] != NOPIECE) && iscolor(gs->board[f][r], gs->onMove)
431 && (piecetype(gs->board[f][r]) == piece) &&
432 ((f != mt->fromFile) || (r != mt->fromRank))) {
433 if (legal_move(gs, f, r, mt->toFile, mt->toRank)) {
435 fakeMove.board[f][r] = NOPIECE;
436 fakeMove.board[mt->toFile][mt->toRank] = piece | gs->onMove;
437 fakeMove.onMove = CToggle(fakeMove.onMove);
438 gs->onMove = CToggle(gs->onMove);
441 d_printf("possible move %c%d%c%d against %c%d%c%d\n",
443 'a' + mt->toFile, mt->toRank+1,
444 'a' + mt->fromFile, mt->fromRank+1,
445 'a' + mt->toFile, mt->toRank+1);
448 if (!in_check(&fakeMove)) {
450 if (f == mt->fromFile) {
454 if (r == mt->fromRank) {
459 gs->onMove = CToggle(gs->onMove);
464 /* Ambiguity in short notation, need to add file,rank or _both_ in
467 sprintf(tmp, "%c", mt->fromFile + 'a');
469 } else if (r_ambig == 0) {
470 sprintf(tmp, "%d", mt->fromRank + 1);
473 sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1);
478 if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) ||
479 ((piece == PAWN) && (mt->fromFile != mt->toFile))) {
483 sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1);
486 if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) {
487 strcat(mStr, "="); /* = before promoting piece */
488 switch (piecetype(mt->piecePromotionTo)) {
507 execute_move(&fakeMove, mt, 0);
508 fakeMove.onMove = CToggle(fakeMove.onMove);
509 if (in_check(&fakeMove)) {