2 * moves.c - Move generation and checking
\r
3 * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
\r
8 * The following terms apply to Digital Equipment Corporation's copyright
\r
9 * interest in XBoard:
\r
10 * ------------------------------------------------------------------------
\r
11 * All Rights Reserved
\r
13 * Permission to use, copy, modify, and distribute this software and its
\r
14 * documentation for any purpose and without fee is hereby granted,
\r
15 * provided that the above copyright notice appear in all copies and that
\r
16 * both that copyright notice and this permission notice appear in
\r
17 * supporting documentation, and that the name of Digital not be
\r
18 * used in advertising or publicity pertaining to distribution of the
\r
19 * software without specific, written prior permission.
\r
21 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
22 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
23 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
24 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
25 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
26 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
28 * ------------------------------------------------------------------------
\r
30 * The following terms apply to the enhanced version of XBoard distributed
\r
31 * by the Free Software Foundation:
\r
32 * ------------------------------------------------------------------------
\r
33 * This program is free software; you can redistribute it and/or modify
\r
34 * it under the terms of the GNU General Public License as published by
\r
35 * the Free Software Foundation; either version 2 of the License, or
\r
36 * (at your option) any later version.
\r
38 * This program is distributed in the hope that it will be useful,
\r
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
41 * GNU General Public License for more details.
\r
43 * You should have received a copy of the GNU General Public License
\r
44 * along with this program; if not, write to the Free Software
\r
45 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
46 * ------------------------------------------------------------------------
\r
53 # include <string.h>
\r
54 #else /* not HAVE_STRING_H */
\r
55 # include <strings.h>
\r
56 #endif /* not HAVE_STRING_H */
\r
58 #include "backend.h"
\r
62 int WhitePiece P((ChessSquare));
\r
63 int BlackPiece P((ChessSquare));
\r
64 int SameColor P((ChessSquare, ChessSquare));
\r
66 extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
\r
69 int WhitePiece(piece)
\r
72 return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn;
\r
75 int BlackPiece(piece)
\r
78 return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;
\r
81 int SameColor(piece1, piece2)
\r
82 ChessSquare piece1, piece2;
\r
84 return ((int) piece1 >= (int) WhitePawn && /* [HGM] can be > King ! */
\r
85 (int) piece1 < (int) BlackPawn &&
\r
86 (int) piece2 >= (int) WhitePawn &&
\r
87 (int) piece2 < (int) BlackPawn)
\r
88 || ((int) piece1 >= (int) BlackPawn &&
\r
89 (int) piece1 < (int) EmptySquare &&
\r
90 (int) piece2 >= (int) BlackPawn &&
\r
91 (int) piece2 < (int) EmptySquare);
\r
94 ChessSquare PromoPiece(moveType)
\r
100 case WhitePromotionQueen:
\r
102 case BlackPromotionQueen:
\r
104 case WhitePromotionRook:
\r
106 case BlackPromotionRook:
\r
108 case WhitePromotionBishop:
\r
109 return WhiteBishop;
\r
110 case BlackPromotionBishop:
\r
111 return BlackBishop;
\r
112 case WhitePromotionKnight:
\r
113 return WhiteKnight;
\r
114 case BlackPromotionKnight:
\r
115 return BlackKnight;
\r
116 case WhitePromotionKing:
\r
118 case BlackPromotionKing:
\r
121 case WhitePromotionChancellor:
\r
122 return WhiteMarshall;
\r
123 case BlackPromotionChancellor:
\r
124 return BlackMarshall;
\r
125 case WhitePromotionArchbishop:
\r
126 return WhiteCardinal;
\r
127 case BlackPromotionArchbishop:
\r
128 return BlackCardinal;
\r
133 ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
\r
138 switch (promoChar) {
\r
141 return WhitePromotionKnight;
\r
144 return WhitePromotionBishop;
\r
147 return WhitePromotionRook;
\r
151 return WhitePromotionArchbishop;
\r
154 return WhitePromotionChancellor;
\r
158 return WhitePromotionQueen;
\r
161 return WhitePromotionKing;
\r
167 switch (promoChar) {
\r
170 return BlackPromotionKnight;
\r
173 return BlackPromotionBishop;
\r
176 return BlackPromotionRook;
\r
180 return BlackPromotionArchbishop;
\r
183 return BlackPromotionChancellor;
\r
187 return BlackPromotionQueen;
\r
190 return BlackPromotionKing;
\r
198 char pieceToChar[] = {
\r
199 'P', 'N', 'B', 'R', 'Q',
\r
201 'F', 'W', 'E', 'H', 'A', 'C', 'G', 'O', 'M', 'U',
\r
203 'K', 'p', 'n', 'b', 'r', 'q',
\r
205 'f', 'w', 'e', 'h', 'a', 'c', 'g', 'o', 'm', 'u',
\r
210 char PieceToChar(p)
\r
213 return pieceToChar[(int) p];
\r
216 ChessSquare CharToPiece(c)
\r
220 for(i=0; i< (int) EmptySquare; i++)
\r
221 if(pieceToChar[i] == c) return (ChessSquare) i;
\r
222 return EmptySquare;
\r
223 /* [HGM] code marked for deletion
\r
226 case 'x': return EmptySquare;
\r
227 case 'P': return WhitePawn;
\r
228 case 'R': return WhiteRook;
\r
229 case 'N': return WhiteKnight;
\r
230 case 'B': return WhiteBishop;
\r
231 case 'Q': return WhiteQueen;
\r
232 case 'K': return WhiteKing;
\r
233 case 'p': return BlackPawn;
\r
234 case 'r': return BlackRook;
\r
235 case 'n': return BlackKnight;
\r
236 case 'b': return BlackBishop;
\r
237 case 'q': return BlackQueen;
\r
238 case 'k': return BlackKing;
\r
240 case 'A': return WhiteCardinal;
\r
241 case 'C': return WhiteMarshall;
\r
242 case 'F': return WhiteFerz;
\r
243 case 'H': return WhiteNightrider;
\r
244 case 'E': return WhiteAlfil;
\r
245 case 'W': return WhiteWazir;
\r
246 case 'U': return WhiteUnicorn;
\r
247 case 'O': return WhiteCannon;
\r
248 case 'G': return WhiteGrasshopper;
\r
249 case 'M': return WhiteMan;
\r
251 case 'a': return BlackCardinal;
\r
252 case 'c': return BlackMarshall;
\r
253 case 'f': return BlackFerz;
\r
254 case 'h': return BlackNightrider;
\r
255 case 'e': return BlackAlfil;
\r
256 case 'w': return BlackWazir;
\r
257 case 'u': return BlackUnicorn;
\r
258 case 'o': return BlackCannon;
\r
259 case 'g': return BlackGrasshopper;
\r
260 case 'm': return BlackMan;
\r
267 void CopyBoard(to, from)
\r
272 for (i = 0; i < BOARD_HEIGHT; i++)
\r
273 for (j = 0; j < BOARD_WIDTH; j++)
\r
274 to[i][j] = from[i][j];
\r
277 int CompareBoards(board1, board2)
\r
278 Board board1, board2;
\r
282 for (i = 0; i < BOARD_HEIGHT; i++)
\r
283 for (j = 0; j < BOARD_WIDTH; j++) {
\r
284 if (board1[i][j] != board2[i][j])
\r
291 /* Call callback once for each pseudo-legal move in the given
\r
292 position, except castling moves. A move is pseudo-legal if it is
\r
293 legal, or if it would be legal except that it leaves the king in
\r
294 check. In the arguments, epfile is EP_NONE if the previous move
\r
295 was not a double pawn push, or the file 0..7 if it was, or
\r
296 EP_UNKNOWN if we don't know and want to allow all e.p. captures.
\r
297 Promotion moves generated are to Queen only.
\r
299 void GenPseudoLegal(board, flags, epfile, callback, closure)
\r
303 MoveCallback callback;
\r
307 int i, j, d, s, fs, rs, rt, ft, m;
\r
309 for (rf = 0; rf < BOARD_HEIGHT; rf++)
\r
310 for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
\r
313 if (flags & F_WHITE_ON_MOVE) {
\r
314 if (!WhitePiece(board[rf][ff])) continue;
\r
316 if (!BlackPiece(board[rf][ff])) continue;
\r
318 m = 0; piece = board[rf][ff];
\r
319 if(gameInfo.variant == VariantCrazyhouse &&
\r
320 ( (int) piece > (int) WhiteQueen && (int) piece < (int) WhiteKing
\r
321 || (int) piece > (int) BlackQueen && (int) piece < (int) BlackKing ))
\r
322 piece = (ChessSquare) ( DEMOTED piece );
\r
323 if(gameInfo.variant == VariantShogi)
\r
324 piece = (ChessSquare) ( SHOGI piece );
\r
327 /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */
\r
329 /* can't happen ([HGM] except for faries...) */
\r
334 if(gameInfo.variant == VariantXiangqi) {
\r
335 /* [HGM] capture and move straight ahead in Xiangqi */
\r
336 if (rf < BOARD_HEIGHT-1 &&
\r
337 !SameColor(board[rf][ff], board[rf + 1][ff]) ) {
\r
338 callback(board, flags, NormalMove,
\r
339 rf, ff, rf + 1, ff, closure);
\r
341 /* and move sideways when across the river */
\r
342 for (s = -1; s <= 1; s += 2) {
\r
343 if (rf >= BOARD_HEIGHT>>1 &&
\r
344 ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
345 !WhitePiece(board[rf][ff+s]) ) {
\r
346 callback(board, flags, NormalMove,
\r
347 rf, ff, rf, ff+s, closure);
\r
353 if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {
\r
354 callback(board, flags,
\r
355 rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
\r
356 rf, ff, rf + 1, ff, closure);
\r
358 if (rf == 1 && board[2][ff] == EmptySquare &&
\r
359 gameInfo.variant != VariantShatranj && /* [HGM] */
\r
360 gameInfo.variant != VariantCourier && /* [HGM] */
\r
361 board[3][ff] == EmptySquare ) {
\r
362 callback(board, flags, NormalMove,
\r
363 rf, ff, 3, ff, closure);
\r
365 for (s = -1; s <= 1; s += 2) {
\r
366 if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
367 ((flags & F_KRIEGSPIEL_CAPTURE) ||
\r
368 BlackPiece(board[rf + 1][ff + s]))) {
\r
369 callback(board, flags,
\r
370 rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
\r
371 rf, ff, rf + 1, ff + s, closure);
\r
373 if (rf == BOARD_HEIGHT-4) {
\r
374 if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
375 (epfile == ff + s || epfile == EP_UNKNOWN) &&
\r
376 board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&
\r
377 board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {
\r
378 callback(board, flags, WhiteCapturesEnPassant,
\r
379 rf, ff, 5, ff + s, closure);
\r
387 if(gameInfo.variant == VariantXiangqi) {
\r
388 /* [HGM] capture straight ahead in Xiangqi */
\r
389 if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {
\r
390 callback(board, flags, NormalMove,
\r
391 rf, ff, rf - 1, ff, closure);
\r
393 /* and move sideways when across the river */
\r
394 for (s = -1; s <= 1; s += 2) {
\r
395 if (rf < BOARD_HEIGHT>>1 &&
\r
396 ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
397 !BlackPiece(board[rf][ff+s]) ) {
\r
398 callback(board, flags, NormalMove,
\r
399 rf, ff, rf, ff+s, closure);
\r
405 if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
\r
406 callback(board, flags,
\r
407 rf == 1 ? BlackPromotionQueen : NormalMove,
\r
408 rf, ff, rf - 1, ff, closure);
\r
410 if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
\r
411 gameInfo.variant != VariantShatranj && /* [HGM] */
\r
412 gameInfo.variant != VariantCourier && /* [HGM] */
\r
413 board[BOARD_HEIGHT-4][ff] == EmptySquare) {
\r
414 callback(board, flags, NormalMove,
\r
415 rf, ff, BOARD_HEIGHT-4, ff, closure);
\r
417 for (s = -1; s <= 1; s += 2) {
\r
418 if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
419 ((flags & F_KRIEGSPIEL_CAPTURE) ||
\r
420 WhitePiece(board[rf - 1][ff + s]))) {
\r
421 callback(board, flags,
\r
422 rf == 1 ? BlackPromotionQueen : NormalMove,
\r
423 rf, ff, rf - 1, ff + s, closure);
\r
426 if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
427 (epfile == ff + s || epfile == EP_UNKNOWN) &&
\r
428 board[3][ff + s] == WhitePawn &&
\r
429 board[2][ff + s] == EmptySquare) {
\r
430 callback(board, flags, BlackCapturesEnPassant,
\r
431 rf, ff, 2, ff + s, closure);
\r
444 for (i = -1; i <= 1; i += 2)
\r
445 for (j = -1; j <= 1; j += 2)
\r
446 for (s = 1; s <= 2; s++) {
\r
449 if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
\r
450 && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)
\r
451 && !SameColor(board[rf][ff], board[rt][ft]))
\r
452 callback(board, flags, NormalMove,
\r
453 rf, ff, rt, ft, closure);
\r
458 case SHOGI WhiteKnight:
\r
459 for (s = -1; s <= 1; s += 2) {
\r
460 if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
461 !SameColor(board[rf][ff], board[rf + 2][ff + s])) {
\r
462 callback(board, flags,
\r
463 rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
\r
464 rf, ff, rf + 2, ff + s, closure);
\r
469 case SHOGI BlackKnight:
\r
470 for (s = -1; s <= 1; s += 2) {
\r
471 if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
472 !SameColor(board[rf][ff], board[rf - 2][ff + s])) {
\r
473 callback(board, flags,
\r
474 rf == 1 ? BlackPromotionQueen : NormalMove,
\r
475 rf, ff, rf - 2, ff + s, closure);
\r
482 for (d = 0; d <= 1; d++)
\r
483 for (s = -1; s <= 1; s += 2) {
\r
485 for (i = 1;; i++) {
\r
486 rt = rf + (i * s) * d;
\r
487 ft = ff + (i * s) * (1 - d);
\r
488 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
\r
489 if (m == 0 && board[rt][ft] == EmptySquare)
\r
490 callback(board, flags, NormalMove,
\r
491 rf, ff, rt, ft, closure);
\r
492 if (m == 1 && board[rt][ft] != EmptySquare &&
\r
493 !SameColor(board[rf][ff], board[rt][ft]) )
\r
494 callback(board, flags, NormalMove,
\r
495 rf, ff, rt, ft, closure);
\r
496 if (board[rt][ft] != EmptySquare && m++) break;
\r
501 /* Gold General (and all its promoted versions) . First do the */
\r
502 /* diagonal forward steps, then proceed as normal Wazir */
\r
503 case SHOGI WhiteWazir:
\r
504 case SHOGI (PROMOTED WhitePawn):
\r
505 case SHOGI (PROMOTED WhiteKnight):
\r
506 case SHOGI (PROMOTED WhiteQueen):
\r
507 case SHOGI (PROMOTED WhiteFerz):
\r
508 for (s = -1; s <= 1; s += 2) {
\r
509 if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
510 !SameColor(board[rf][ff], board[rf + 1][ff + s])) {
\r
511 callback(board, flags,
\r
512 rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
\r
513 rf, ff, rf + 1, ff + s, closure);
\r
518 case SHOGI BlackWazir:
\r
519 case SHOGI (PROMOTED BlackPawn):
\r
520 case SHOGI (PROMOTED BlackKnight):
\r
521 case SHOGI (PROMOTED BlackQueen):
\r
522 case SHOGI (PROMOTED BlackFerz):
\r
523 for (s = -1; s <= 1; s += 2) {
\r
524 if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
\r
525 !SameColor(board[rf][ff], board[rf - 1][ff + s])) {
\r
526 callback(board, flags,
\r
527 rf == 1 ? BlackPromotionQueen : NormalMove,
\r
528 rf, ff, rf - 1, ff + s, closure);
\r
535 for (d = 0; d <= 1; d++)
\r
536 for (s = -1; s <= 1; s += 2) {
\r
538 ft = ff + s * (1 - d);
\r
539 if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
\r
540 && !SameColor(board[rf][ff], board[rt][ft]) &&
\r
541 (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
\r
542 callback(board, flags, NormalMove,
\r
543 rf, ff, rt, ft, closure);
\r
549 /* [HGM] support Shatranj pieces */
\r
550 for (rs = -1; rs <= 1; rs += 2)
\r
551 for (fs = -1; fs <= 1; fs += 2) {
\r
554 if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
\r
555 && ( gameInfo.variant != VariantXiangqi ||
\r
556 board[rf+rs][ff+fs] == EmptySquare && (2*rf < BOARD_HEIGHT) == (2*rt < BOARD_HEIGHT) )
\r
558 && !SameColor(board[rf][ff], board[rt][ft]))
\r
559 callback(board, flags, NormalMove,
\r
560 rf, ff, rt, ft, closure);
\r
564 /* Shogi Dragon Horse has to continue with Wazir after Bishop */
\r
565 case SHOGI WhiteCardinal:
\r
566 case SHOGI BlackCardinal:
\r
569 /* Capablanca Archbishop continues as Knight */
\r
570 case WhiteCardinal:
\r
571 case BlackCardinal:
\r
574 /* Shogi Bishops are ordinary Bishops */
\r
575 case SHOGI WhiteBishop:
\r
576 case SHOGI BlackBishop:
\r
580 for (rs = -1; rs <= 1; rs += 2)
\r
581 for (fs = -1; fs <= 1; fs += 2)
\r
582 for (i = 1;; i++) {
\r
583 rt = rf + (i * rs);
\r
584 ft = ff + (i * fs);
\r
585 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
\r
586 if (SameColor(board[rf][ff], board[rt][ft])) break;
\r
587 callback(board, flags, NormalMove,
\r
588 rf, ff, rt, ft, closure);
\r
589 if (board[rt][ft] != EmptySquare) break;
\r
591 if(m==1) goto mounted;
\r
592 if(m==2) goto finishGold;
\r
593 /* Bishop falls through */
\r
597 /* Shogi Lance is unlike anything, and asymmetric at that */
\r
598 case SHOGI WhiteQueen:
\r
602 if (rt >= BOARD_HEIGHT) break;
\r
603 if (SameColor(board[rf][ff], board[rt][ft])) break;
\r
604 callback(board, flags, NormalMove,
\r
605 rf, ff, rt, ft, closure);
\r
606 if (board[rt][ft] != EmptySquare) break;
\r
610 case SHOGI BlackQueen:
\r
615 if (SameColor(board[rf][ff], board[rt][ft])) break;
\r
616 callback(board, flags, NormalMove,
\r
617 rf, ff, rt, ft, closure);
\r
618 if (board[rt][ft] != EmptySquare) break;
\r
622 /* Shogi Dragon King has to continue as Ferz after Rook moves */
\r
623 case SHOGI WhiteMarshall:
\r
624 case SHOGI BlackMarshall:
\r
627 /* Capablanca Chancellor sets flag to continue as Knight */
\r
628 case WhiteMarshall:
\r
629 case BlackMarshall:
\r
632 /* Shogi Rooks are ordinary Rooks */
\r
633 case SHOGI WhiteRook:
\r
634 case SHOGI BlackRook:
\r
638 for (d = 0; d <= 1; d++)
\r
639 for (s = -1; s <= 1; s += 2)
\r
640 for (i = 1;; i++) {
\r
641 rt = rf + (i * s) * d;
\r
642 ft = ff + (i * s) * (1 - d);
\r
643 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
\r
644 if (SameColor(board[rf][ff], board[rt][ft])) break;
\r
645 callback(board, flags, NormalMove,
\r
646 rf, ff, rt, ft, closure);
\r
647 if (board[rt][ft] != EmptySquare) break;
\r
649 if(m==1) goto mounted;
\r
650 if(m==2) goto walking;
\r
655 for (rs = -1; rs <= 1; rs++)
\r
656 for (fs = -1; fs <= 1; fs++) {
\r
657 if (rs == 0 && fs == 0) continue;
\r
658 for (i = 1;; i++) {
\r
659 rt = rf + (i * rs);
\r
660 ft = ff + (i * fs);
\r
661 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
\r
662 if (SameColor(board[rf][ff], board[rt][ft])) break;
\r
663 callback(board, flags, NormalMove,
\r
664 rf, ff, rt, ft, closure);
\r
665 if (board[rt][ft] != EmptySquare) break;
\r
671 /* Shogi Pawn and Silver General: first the Pawn move, */
\r
672 /* then the General continues like a Ferz */
\r
673 case SHOGI WhitePawn:
\r
674 case SHOGI WhiteFerz:
\r
675 if (rf < BOARD_HEIGHT-1 &&
\r
676 !SameColor(board[rf][ff], board[rf + 1][ff]) )
\r
677 callback(board, flags, NormalMove,
\r
678 rf, ff, rf + 1, ff, closure);
\r
679 if(piece != SHOGI WhitePawn) goto finishSilver;
\r
682 case SHOGI BlackPawn:
\r
683 case SHOGI BlackFerz:
\r
685 !SameColor(board[rf][ff], board[rf - 1][ff]) )
\r
686 callback(board, flags, NormalMove,
\r
687 rf, ff, rf - 1, ff, closure);
\r
688 if(piece == SHOGI BlackPawn) break;
\r
693 /* [HGM] support Shatranj pieces */
\r
694 for (rs = -1; rs <= 1; rs += 2)
\r
695 for (fs = -1; fs <= 1; fs += 2) {
\r
698 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
\r
699 if (!SameColor(board[rf][ff], board[rt][ft]) &&
\r
700 (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
\r
701 callback(board, flags, NormalMove,
\r
702 rf, ff, rt, ft, closure);
\r
708 case SHOGI WhiteKing:
\r
709 case SHOGI BlackKing:
\r
714 for (i = -1; i <= 1; i++)
\r
715 for (j = -1; j <= 1; j++) {
\r
716 if (i == 0 && j == 0) continue;
\r
719 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
\r
720 if (SameColor(board[rf][ff], board[rt][ft])) continue;
\r
721 callback(board, flags, NormalMove,
\r
722 rf, ff, rt, ft, closure);
\r
735 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
\r
736 int rf, int ff, int rt, int ft,
\r
737 VOIDSTAR closure));
\r
739 void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
743 int rf, ff, rt, ft;
\r
746 register GenLegalClosure *cl = (GenLegalClosure *) closure;
\r
748 if (!(flags & F_IGNORE_CHECK) &&
\r
749 CheckTest(board, flags, rf, ff, rt, ft,
\r
750 kind == WhiteCapturesEnPassant ||
\r
751 kind == BlackCapturesEnPassant)) return;
\r
752 if (flags & F_ATOMIC_CAPTURE) {
\r
753 if (board[rt][ft] != EmptySquare ||
\r
754 kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
\r
756 ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;
\r
757 if (board[rf][ff] == king) return;
\r
758 for (r = rt-1; r <= rt+1; r++) {
\r
759 for (f = ft-1; f <= ft+1; f++) {
\r
760 if (r >= 0 && r < BOARD_HEIGHT && f >= BOARD_LEFT && f < BOARD_RGHT &&
\r
761 board[r][f] == king) return;
\r
766 cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);
\r
771 int rf, ff, rt, ft;
\r
773 } LegalityTestClosure;
\r
776 /* Like GenPseudoLegal, but (1) include castling moves, (2) unless
\r
777 F_IGNORE_CHECK is set in the flags, omit moves that would leave the
\r
778 king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit
\r
779 moves that would destroy your own king. The CASTLE_OK flags are
\r
780 true if castling is not yet ruled out by a move of the king or
\r
781 rook. Return TRUE if the player on move is currently in check and
\r
782 F_IGNORE_CHECK is not set. [HGM] add castlingRights parameter */
\r
783 int GenLegal(board, flags, epfile, castlingRights, callback, closure)
\r
787 char castlingRights[];
\r
788 MoveCallback callback;
\r
791 GenLegalClosure cl;
\r
793 int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
\r
797 GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
\r
799 if (!ignoreCheck &&
\r
800 CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
\r
802 /* Generate castling moves */
\r
803 for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {
\r
804 if ((flags & F_WHITE_ON_MOVE) &&
\r
805 (flags & F_WHITE_KCASTLE_OK) &&
\r
806 board[0][ff] == WhiteKing &&
\r
807 board[0][ff + 1] == EmptySquare &&
\r
808 board[0][ff + 2] == EmptySquare &&
\r
809 board[0][BOARD_RGHT-3] == EmptySquare &&
\r
810 board[0][BOARD_RGHT-2] == EmptySquare &&
\r
811 board[0][BOARD_RGHT-1] == WhiteRook &&
\r
812 castlingRights[0] >= 0 && /* [HGM] check rights */
\r
813 ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
\r
815 (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
\r
816 !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&
\r
817 !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {
\r
819 callback(board, flags,
\r
820 ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,
\r
821 0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure);
\r
823 if ((flags & F_WHITE_ON_MOVE) &&
\r
824 (flags & F_WHITE_QCASTLE_OK) &&
\r
825 board[0][ff] == WhiteKing &&
\r
826 board[0][ff - 1] == EmptySquare &&
\r
827 board[0][ff - 2] == EmptySquare &&
\r
828 board[0][BOARD_LEFT+2] == EmptySquare &&
\r
829 board[0][BOARD_LEFT+1] == EmptySquare &&
\r
830 board[0][BOARD_LEFT+0] == WhiteRook &&
\r
831 castlingRights[1] >= 0 && /* [HGM] check rights */
\r
832 ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
\r
834 (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
\r
835 !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&
\r
836 !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {
\r
838 callback(board, flags,
\r
839 ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,
\r
840 0, ff, 0, ff - ((gameInfo.boardWidth+2)>>2), closure);
\r
842 if (!(flags & F_WHITE_ON_MOVE) &&
\r
843 (flags & F_BLACK_KCASTLE_OK) &&
\r
844 board[BOARD_HEIGHT-1][ff] == BlackKing &&
\r
845 board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&
\r
846 board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&
\r
847 board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&
\r
848 board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&
\r
849 board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&
\r
850 castlingRights[3] >= 0 && /* [HGM] check rights */
\r
851 ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
\r
853 (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&
\r
854 !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&
\r
855 !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {
\r
857 callback(board, flags,
\r
858 ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,
\r
859 BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2), closure);
\r
861 if (!(flags & F_WHITE_ON_MOVE) &&
\r
862 (flags & F_BLACK_QCASTLE_OK) &&
\r
863 board[BOARD_HEIGHT-1][ff] == BlackKing &&
\r
864 board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&
\r
865 board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&
\r
866 board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&
\r
867 board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&
\r
868 board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&
\r
869 castlingRights[4] >= 0 && /* [HGM] check rights */
\r
870 ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
\r
872 (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&
\r
873 !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&
\r
874 !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE)))) {
\r
876 callback(board, flags,
\r
877 ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,
\r
878 BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((gameInfo.boardWidth+2)>>2), closure);
\r
884 /* generate all potential FRC castling moves (KxR), ignoring flags */
\r
885 /* [HGM] Tord! Help requested! */
\r
887 if ((flags & F_WHITE_ON_MOVE) != 0) {
\r
889 for (ff = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) {
\r
890 if (board[0][ff] == WhiteKing) {
\r
891 for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; ft++) {
\r
892 if (board[0][ft] == WhiteRook) {
\r
893 callback(board, flags,
\r
894 (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,
\r
895 0, ff, 0, ft, closure);
\r
903 for (ff = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) {
\r
904 if (board[BOARD_HEIGHT-1][ff] == BlackKing) {
\r
905 for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; ft++) {
\r
906 if (board[BOARD_HEIGHT-1][ft] == BlackRook) {
\r
907 callback(board, flags,
\r
908 (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,
\r
909 BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
\r
925 } CheckTestClosure;
\r
928 extern void CheckTestCallback P((Board board, int flags, ChessMove kind,
\r
929 int rf, int ff, int rt, int ft,
\r
930 VOIDSTAR closure));
\r
933 void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
937 int rf, ff, rt, ft;
\r
940 register CheckTestClosure *cl = (CheckTestClosure *) closure;
\r
942 if (rt == cl->rking && ft == cl->fking) cl->check++;
\r
946 /* If the player on move were to move from (rf, ff) to (rt, ft), would
\r
947 he leave himself in check? Or if rf == -1, is the player on move
\r
948 in check now? enPassant must be TRUE if the indicated move is an
\r
949 e.p. capture. The possibility of castling out of a check along the
\r
950 back rank is not accounted for (i.e., we still return nonzero), as
\r
951 this is illegal anyway. Return value is the number of times the
\r
952 king is in check. */
\r
953 int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
\r
956 int rf, ff, rt, ft, enPassant;
\r
958 CheckTestClosure cl;
\r
959 ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
\r
960 ChessSquare captured = EmptySquare;
\r
961 /* Suppress warnings on uninitialized variables */
\r
963 if(gameInfo.variant == VariantXiangqi)
\r
964 king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
\r
965 if(gameInfo.variant == VariantKnightmate)
\r
966 king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
\r
970 captured = board[rf][ft];
\r
971 board[rf][ft] = EmptySquare;
\r
973 captured = board[rt][ft];
\r
975 board[rt][ft] = board[rf][ff];
\r
976 board[rf][ff] = EmptySquare;
\r
979 /* For compatibility with ICS wild 9, we scan the board in the
\r
980 order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
\r
981 and we test only whether that one is in check. */
\r
983 for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)
\r
984 for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {
\r
985 if (board[cl.rking][cl.fking] == king) {
\r
986 GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
\r
987 CheckTestCallback, (VOIDSTAR) &cl);
\r
988 goto undo_move; /* 2-level break */
\r
995 board[rf][ff] = board[rt][ft];
\r
997 board[rf][ft] = captured;
\r
998 board[rt][ft] = EmptySquare;
\r
1000 board[rt][ft] = captured;
\r
1008 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
\r
1009 int rf, int ff, int rt, int ft,
\r
1010 VOIDSTAR closure));
\r
1012 void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
1016 int rf, ff, rt, ft;
\r
1019 register LegalityTestClosure *cl = (LegalityTestClosure *) closure;
\r
1021 if (appData.debugMode) {
\r
1022 fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
\r
1024 if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
\r
1028 ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)
\r
1030 int flags, epfile;
\r
1031 int rf, ff, rt, ft, promoChar;
\r
1032 char castlingRights[];
\r
1034 LegalityTestClosure cl;
\r
1040 cl.kind = IllegalMove;
\r
1041 GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);
\r
1042 if (promoChar != NULLCHAR && promoChar != 'x') {
\r
1043 if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
\r
1045 PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
\r
1047 cl.kind = IllegalMove;
\r
1055 } MateTestClosure;
\r
1057 extern void MateTestCallback P((Board board, int flags, ChessMove kind,
\r
1058 int rf, int ff, int rt, int ft,
\r
1059 VOIDSTAR closure));
\r
1061 void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
1065 int rf, ff, rt, ft;
\r
1068 register MateTestClosure *cl = (MateTestClosure *) closure;
\r
1073 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
\r
1074 int MateTest(board, flags, epfile, castlingRights)
\r
1076 int flags, epfile;
\r
1077 char castlingRights[];
\r
1079 MateTestClosure cl;
\r
1083 inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);
\r
1084 if (cl.count > 0) {
\r
1085 return inCheck ? MT_CHECK : MT_NONE;
\r
1087 return inCheck || gameInfo.variant == VariantXiangqi ?
\r
1088 MT_CHECKMATE : MT_STALEMATE;
\r
1093 extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,
\r
1094 int rf, int ff, int rt, int ft,
\r
1095 VOIDSTAR closure));
\r
1097 void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
1101 int rf, ff, rt, ft;
\r
1104 register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
\r
1106 if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&
\r
1107 (cl->rfIn == -1 || cl->rfIn == rf) &&
\r
1108 (cl->ffIn == -1 || cl->ffIn == ff) &&
\r
1109 (cl->rtIn == -1 || cl->rtIn == rt) &&
\r
1110 (cl->ftIn == -1 || cl->ftIn == ft)) {
\r
1113 cl->piece = board[rf][ff];
\r
1122 void Disambiguate(board, flags, epfile, closure)
\r
1124 int flags, epfile;
\r
1125 DisambiguateClosure *closure;
\r
1128 closure->count = 0;
\r
1129 closure->rf = closure->ff = closure->rt = closure->ft = 0;
\r
1130 closure->kind = ImpossibleMove;
\r
1131 GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);
\r
1132 if (closure->count == 0) {
\r
1133 /* See if it's an illegal move due to check */
\r
1135 GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,
\r
1136 (VOIDSTAR) closure);
\r
1137 if (closure->count == 0) {
\r
1138 /* No, it's not even that */
\r
1142 if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {
\r
1143 if (closure->kind == WhitePromotionQueen
\r
1144 || closure->kind == BlackPromotionQueen) {
\r
1146 PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,
\r
1147 closure->promoCharIn);
\r
1149 closure->kind = IllegalMove;
\r
1152 closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));
\r
1153 if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
\r
1154 if (closure->count > 1) {
\r
1155 closure->kind = AmbiguousMove;
\r
1158 /* Note: If more than one illegal move matches, but no legal
\r
1159 moves, we return IllegalMove, not AmbiguousMove. Caller
\r
1160 can look at closure->count to detect this.
\r
1162 closure->kind = IllegalMove;
\r
1169 ChessSquare piece;
\r
1170 int rf, ff, rt, ft;
\r
1176 } CoordsToAlgebraicClosure;
\r
1178 extern void CoordsToAlgebraicCallback P((Board board, int flags,
\r
1179 ChessMove kind, int rf, int ff,
\r
1180 int rt, int ft, VOIDSTAR closure));
\r
1182 void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
1186 int rf, ff, rt, ft;
\r
1189 register CoordsToAlgebraicClosure *cl =
\r
1190 (CoordsToAlgebraicClosure *) closure;
\r
1192 if (rt == cl->rt && ft == cl->ft &&
\r
1193 board[rf][ff] == cl->piece) {
\r
1194 if (rf == cl->rf) {
\r
1195 if (ff == cl->ff) {
\r
1196 cl->kind = kind; /* this is the move we want */
\r
1198 cl->file++; /* need file to rule out this move */
\r
1201 if (ff == cl->ff) {
\r
1202 cl->rank++; /* need rank to rule out this move */
\r
1204 cl->either++; /* rank or file will rule out this move */
\r
1210 /* Convert coordinates to normal algebraic notation.
\r
1211 promoChar must be NULLCHAR or 'x' if not a promotion.
\r
1213 ChessMove CoordsToAlgebraic(board, flags, epfile,
\r
1214 rf, ff, rt, ft, promoChar, out)
\r
1216 int flags, epfile;
\r
1217 int rf, ff, rt, ft;
\r
1219 char out[MOVE_LEN];
\r
1221 ChessSquare piece;
\r
1224 CoordsToAlgebraicClosure cl;
\r
1226 if (rf == DROP_RANK) {
\r
1227 /* Bughouse piece drop */
\r
1228 *outp++ = ToUpper(PieceToChar((ChessSquare) ff));
\r
1230 *outp++ = ft + AAA;
\r
1232 *outp++ = rt + ONE;
\r
1233 else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
\r
1235 AlphaRank(out, 5);
\r
1236 return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;
\r
1239 if (promoChar == 'x') promoChar = NULLCHAR;
\r
1240 piece = board[rf][ff];
\r
1244 kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);
\r
1245 if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
\r
1246 /* Keep short notation if move is illegal only because it
\r
1247 leaves the player in check, but still return IllegalMove */
\r
1248 kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,
\r
1249 rf, ff, rt, ft, promoChar);
\r
1250 if (kind == IllegalMove) break;
\r
1251 kind = IllegalMove;
\r
1254 *outp++ = ff + AAA;
\r
1255 if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */
\r
1256 /* Non-capture; use style "e5" */
\r
1258 *outp++ = rt + ONE;
\r
1259 else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
\r
1261 /* Capture; use style "exd5" */
\r
1262 if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )
\r
1263 *outp++ = 'x'; /* [HGM] Xiangqi has sideway noncaptures across river! */
\r
1264 *outp++ = ft + AAA;
\r
1266 *outp++ = rt + ONE;
\r
1267 else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
\r
1269 /* Use promotion suffix style "=Q" */
\r
1270 if (promoChar != NULLCHAR && promoChar != 'x') {
\r
1272 *outp++ = ToUpper(promoChar);
\r
1275 AlphaRank(out, 10);
\r
1281 /* Fabien moved code: FRC castling first (if KxR), wild castling second */
\r
1282 /* Code added by Tord: FRC castling. */
\r
1283 if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||
\r
1284 (piece == BlackKing && board[rt][ft] == BlackRook)) {
\r
1285 if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");
\r
1286 return LegalityTest(board, flags, epfile, initialRights,
\r
1287 rf, ff, rt, ft, promoChar);
\r
1289 /* End of code added by Tord */
\r
1290 /* Test for castling or ICS wild castling */
\r
1291 /* Use style "O-O" (oh-oh) for PGN compatibility */
\r
1292 else if (rf == rt &&
\r
1293 rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&
\r
1294 ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
\r
1295 (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
\r
1296 if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
\r
1297 strcpy(out, "O-O");
\r
1299 strcpy(out, "O-O-O");
\r
1301 /* This notation is always unambiguous, unless there are
\r
1302 kings on both the d and e files, with "wild castling"
\r
1303 possible for the king on the d file and normal castling
\r
1304 possible for the other. ICS rules for wild 9
\r
1305 effectively make castling illegal for either king in
\r
1306 this situation. So I am not going to worry about it;
\r
1307 I'll just generate an ambiguous O-O in this case.
\r
1309 return LegalityTest(board, flags, epfile, initialRights,
\r
1310 rf, ff, rt, ft, promoChar);
\r
1313 /* else fall through */
\r
1321 cl.kind = IllegalMove;
\r
1322 cl.rank = cl.file = cl.either = 0;
\r
1323 GenLegal(board, flags, epfile, initialRights,
\r
1324 CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
\r
1326 if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
\r
1327 /* Generate pretty moves for moving into check, but
\r
1328 still return IllegalMove.
\r
1330 GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,
\r
1331 CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
\r
1332 if (cl.kind == IllegalMove) break;
\r
1333 cl.kind = IllegalMove;
\r
1336 /* Style is "Nf3" or "Nxf7" if this is unambiguous,
\r
1337 else "Ngf3" or "Ngxf7",
\r
1338 else "N1f3" or "N5xf7",
\r
1339 else "Ng1f3" or "Ng5xf7".
\r
1341 *outp++ = ToUpper(PieceToChar(piece));
\r
1343 if (cl.file || (cl.either && !cl.rank)) {
\r
1344 *outp++ = ff + AAA;
\r
1348 *outp++ = rf + ONE;
\r
1349 else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
\r
1352 if(board[rt][ft] != EmptySquare)
\r
1355 *outp++ = ft + AAA;
\r
1357 *outp++ = rt + ONE;
\r
1358 else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
\r
1360 AlphaRank(out, 10);
\r
1364 /* [HGM] Always long notation for fairies, don't know how they move */
\r
1365 case WhiteNightrider:
\r
1366 case BlackNightrider:
\r
1367 case WhiteGrasshopper:
\r
1368 case BlackGrasshopper:
\r
1371 /* Moving a nonexistent piece */
\r
1375 /* Not a legal move, even ignoring check.
\r
1376 If there was a piece on the from square,
\r
1377 use style "Ng1g3" or "Ng1xe8";
\r
1378 if there was a pawn or nothing (!),
\r
1379 use style "g1g3" or "g1xe8". Use "x"
\r
1380 if a piece was on the to square, even
\r
1381 a piece of the same color.
\r
1384 if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
\r
1385 *outp++ = ToUpper(PieceToChar(piece));
\r
1387 *outp++ = ff + AAA;
\r
1389 *outp++ = rf + ONE;
\r
1390 else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
\r
1391 if (board[rt][ft] != EmptySquare) *outp++ = 'x';
\r
1392 *outp++ = ft + AAA;
\r
1394 *outp++ = rt + ONE;
\r
1395 else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
\r
1396 /* Use promotion suffix style "=Q" */
\r
1397 if (promoChar != NULLCHAR && promoChar != 'x') {
\r
1399 *outp++ = ToUpper(promoChar);
\r
1403 AlphaRank(out, 0);
\r
1404 return IllegalMove;
\r