2 * moves.c - Move generation and checking
3 * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
6 * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
8 * The following terms apply to Digital Equipment Corporation's copyright
10 * ------------------------------------------------------------------------
13 * Permission to use, copy, modify, and distribute this software and its
14 * documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appear in all copies and that
16 * both that copyright notice and this permission notice appear in
17 * supporting documentation, and that the name of Digital not be
18 * used in advertising or publicity pertaining to distribution of the
19 * software without specific, written prior permission.
21 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
22 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
24 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
25 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28 * ------------------------------------------------------------------------
30 * The following terms apply to the enhanced version of XBoard distributed
31 * by the Free Software Foundation:
32 * ------------------------------------------------------------------------
33 * This program is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
43 * You should have received a copy of the GNU General Public License
44 * along with this program; if not, write to the Free Software
45 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46 * ------------------------------------------------------------------------
54 #else /* not HAVE_STRING_H */
56 #endif /* not HAVE_STRING_H */
62 int WhitePiece P((ChessSquare));
63 int BlackPiece P((ChessSquare));
64 int SameColor P((ChessSquare, ChessSquare));
70 return (int) piece >= (int) WhitePawn && (int) piece <= (int) WhiteKing;
76 return (int) piece >= (int) BlackPawn && (int) piece <= (int) BlackKing;
79 int SameColor(piece1, piece2)
80 ChessSquare piece1, piece2;
82 return ((int) piece1 >= (int) WhitePawn &&
83 (int) piece1 <= (int) WhiteKing &&
84 (int) piece2 >= (int) WhitePawn &&
85 (int) piece2 <= (int) WhiteKing)
86 || ((int) piece1 >= (int) BlackPawn &&
87 (int) piece1 <= (int) BlackKing &&
88 (int) piece2 >= (int) BlackPawn &&
89 (int) piece2 <= (int) BlackKing);
92 ChessSquare PromoPiece(moveType)
98 case WhitePromotionQueen:
100 case BlackPromotionQueen:
102 case WhitePromotionRook:
104 case BlackPromotionRook:
106 case WhitePromotionBishop:
108 case BlackPromotionBishop:
110 case WhitePromotionKnight:
112 case BlackPromotionKnight:
114 case WhitePromotionKing:
116 case BlackPromotionKing:
121 ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
129 return WhitePromotionKnight;
132 return WhitePromotionBishop;
135 return WhitePromotionRook;
138 return WhitePromotionQueen;
141 return WhitePromotionKing;
150 return BlackPromotionKnight;
153 return BlackPromotionBishop;
156 return BlackPromotionRook;
159 return BlackPromotionQueen;
162 return BlackPromotionKing;
170 char pieceToChar[] = {
171 'P', 'N', 'B', 'R', 'Q', 'K',
172 'p', 'n', 'b', 'r', 'q', 'k', 'x'
178 return pieceToChar[(int) p];
181 ChessSquare CharToPiece(c)
186 case 'x': return EmptySquare;
187 case 'P': return WhitePawn;
188 case 'R': return WhiteRook;
189 case 'N': return WhiteKnight;
190 case 'B': return WhiteBishop;
191 case 'Q': return WhiteQueen;
192 case 'K': return WhiteKing;
193 case 'p': return BlackPawn;
194 case 'r': return BlackRook;
195 case 'n': return BlackKnight;
196 case 'b': return BlackBishop;
197 case 'q': return BlackQueen;
198 case 'k': return BlackKing;
202 void CopyBoard(to, from)
207 for (i = 0; i < BOARD_SIZE; i++)
208 for (j = 0; j < BOARD_SIZE; j++)
209 to[i][j] = from[i][j];
212 int CompareBoards(board1, board2)
213 Board board1, board2;
217 for (i = 0; i < BOARD_SIZE; i++)
218 for (j = 0; j < BOARD_SIZE; j++) {
219 if (board1[i][j] != board2[i][j])
226 /* Call callback once for each pseudo-legal move in the given
227 position, except castling moves. A move is pseudo-legal if it is
228 legal, or if it would be legal except that it leaves the king in
229 check. In the arguments, epfile is EP_NONE if the previous move
230 was not a double pawn push, or the file 0..7 if it was, or
231 EP_UNKNOWN if we don't know and want to allow all e.p. captures.
232 Promotion moves generated are to Queen only.
234 void GenPseudoLegal(board, flags, epfile, callback, closure)
238 MoveCallback callback;
242 int i, j, d, s, fs, rs, rt, ft;
244 for (rf = 0; rf <= 7; rf++)
245 for (ff = 0; ff <= 7; ff++) {
246 if (flags & F_WHITE_ON_MOVE) {
247 if (!WhitePiece(board[rf][ff])) continue;
249 if (!BlackPiece(board[rf][ff])) continue;
251 switch (board[rf][ff]) {
258 if (rf < 7 && board[rf + 1][ff] == EmptySquare) {
259 callback(board, flags,
260 rf == 6 ? WhitePromotionQueen : NormalMove,
261 rf, ff, rf + 1, ff, closure);
263 if (rf == 1 && board[2][ff] == EmptySquare &&
264 board[3][ff] == EmptySquare) {
265 callback(board, flags, NormalMove,
266 rf, ff, 3, ff, closure);
268 for (s = -1; s <= 1; s += 2) {
269 if (rf < 7 && ff + s >= 0 && ff + s <= 7 &&
270 ((flags & F_KRIEGSPIEL_CAPTURE) ||
271 BlackPiece(board[rf + 1][ff + s]))) {
272 callback(board, flags,
273 rf == 6 ? WhitePromotionQueen : NormalMove,
274 rf, ff, rf + 1, ff + s, closure);
277 if (ff + s >= 0 && ff + s <= 7 &&
278 (epfile == ff + s || epfile == EP_UNKNOWN) &&
279 board[4][ff + s] == BlackPawn &&
280 board[5][ff + s] == EmptySquare) {
281 callback(board, flags, WhiteCapturesEnPassant,
282 rf, ff, 5, ff + s, closure);
289 if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
290 callback(board, flags,
291 rf == 1 ? BlackPromotionQueen : NormalMove,
292 rf, ff, rf - 1, ff, closure);
294 if (rf == 6 && board[5][ff] == EmptySquare &&
295 board[4][ff] == EmptySquare) {
296 callback(board, flags, NormalMove,
297 rf, ff, 4, ff, closure);
299 for (s = -1; s <= 1; s += 2) {
300 if (rf > 0 && ff + s >= 0 && ff + s <= 7 &&
301 ((flags & F_KRIEGSPIEL_CAPTURE) ||
302 WhitePiece(board[rf - 1][ff + s]))) {
303 callback(board, flags,
304 rf == 1 ? BlackPromotionQueen : NormalMove,
305 rf, ff, rf - 1, ff + s, closure);
308 if (ff + s >= 0 && ff + s <= 7 &&
309 (epfile == ff + s || epfile == EP_UNKNOWN) &&
310 board[3][ff + s] == WhitePawn &&
311 board[2][ff + s] == EmptySquare) {
312 callback(board, flags, BlackCapturesEnPassant,
313 rf, ff, 2, ff + s, closure);
321 for (i = -1; i <= 1; i += 2)
322 for (j = -1; j <= 1; j += 2)
323 for (s = 1; s <= 2; s++) {
326 if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue;
327 if (SameColor(board[rf][ff], board[rt][ft])) continue;
328 callback(board, flags, NormalMove,
329 rf, ff, rt, ft, closure);
335 for (rs = -1; rs <= 1; rs += 2)
336 for (fs = -1; fs <= 1; fs += 2)
340 if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
341 if (SameColor(board[rf][ff], board[rt][ft])) break;
342 callback(board, flags, NormalMove,
343 rf, ff, rt, ft, closure);
344 if (board[rt][ft] != EmptySquare) break;
350 for (d = 0; d <= 1; d++)
351 for (s = -1; s <= 1; s += 2)
353 rt = rf + (i * s) * d;
354 ft = ff + (i * s) * (1 - d);
355 if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
356 if (SameColor(board[rf][ff], board[rt][ft])) break;
357 callback(board, flags, NormalMove,
358 rf, ff, rt, ft, closure);
359 if (board[rt][ft] != EmptySquare) break;
365 for (rs = -1; rs <= 1; rs++)
366 for (fs = -1; fs <= 1; fs++) {
367 if (rs == 0 && fs == 0) continue;
371 if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
372 if (SameColor(board[rf][ff], board[rt][ft])) break;
373 callback(board, flags, NormalMove,
374 rf, ff, rt, ft, closure);
375 if (board[rt][ft] != EmptySquare) break;
382 for (i = -1; i <= 1; i++)
383 for (j = -1; j <= 1; j++) {
384 if (i == 0 && j == 0) continue;
387 if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue;
388 if (SameColor(board[rf][ff], board[rt][ft])) continue;
389 callback(board, flags, NormalMove,
390 rf, ff, rt, ft, closure);
403 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
404 int rf, int ff, int rt, int ft,
407 void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
414 register GenLegalClosure *cl = (GenLegalClosure *) closure;
416 if (!(flags & F_IGNORE_CHECK) &&
417 CheckTest(board, flags, rf, ff, rt, ft,
418 kind == WhiteCapturesEnPassant ||
419 kind == BlackCapturesEnPassant)) return;
420 if (flags & F_ATOMIC_CAPTURE) {
421 if (board[rt][ft] != EmptySquare ||
422 kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
424 ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;
425 if (board[rf][ff] == king) return;
426 for (r = rt-1; r <= rt+1; r++) {
427 for (f = ft-1; f <= ft+1; f++) {
428 if (r >= 0 && r <= 7 && f >= 0 && f <= 7 &&
429 board[r][f] == king) return;
434 cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);
441 } LegalityTestClosure;
444 /* Like GenPseudoLegal, but (1) include castling moves, (2) unless
445 F_IGNORE_CHECK is set in the flags, omit moves that would leave the
446 king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit
447 moves that would destroy your own king. The CASTLE_OK flags are
448 true if castling is not yet ruled out by a move of the king or
449 rook. Return TRUE if the player on move is currently in check and
450 F_IGNORE_CHECK is not set. */
451 int GenLegal(board, flags, epfile, callback, closure)
455 MoveCallback callback;
460 int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
464 GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
467 CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
469 /* Generate castling moves */
470 for (ff = 4; ff >= 3; ff-- /*ics wild 1*/) {
471 if ((flags & F_WHITE_ON_MOVE) &&
472 (flags & F_WHITE_KCASTLE_OK) &&
473 board[0][ff] == WhiteKing &&
474 board[0][ff + 1] == EmptySquare &&
475 board[0][ff + 2] == EmptySquare &&
476 board[0][6] == EmptySquare &&
477 board[0][7] == WhiteRook &&
479 (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
480 !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {
482 callback(board, flags,
483 ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,
484 0, ff, 0, ff + 2, closure);
486 if ((flags & F_WHITE_ON_MOVE) &&
487 (flags & F_WHITE_QCASTLE_OK) &&
488 board[0][ff] == WhiteKing &&
489 board[0][ff - 1] == EmptySquare &&
490 board[0][ff - 2] == EmptySquare &&
491 board[0][1] == EmptySquare &&
492 board[0][0] == WhiteRook &&
494 (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
495 !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {
497 callback(board, flags,
498 ff==4 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,
499 0, ff, 0, ff - 2, closure);
501 if (!(flags & F_WHITE_ON_MOVE) &&
502 (flags & F_BLACK_KCASTLE_OK) &&
503 board[7][ff] == BlackKing &&
504 board[7][ff + 1] == EmptySquare &&
505 board[7][ff + 2] == EmptySquare &&
506 board[7][6] == EmptySquare &&
507 board[7][7] == BlackRook &&
509 (!CheckTest(board, flags, 7, ff, 7, ff + 1, FALSE) &&
510 !CheckTest(board, flags, 7, ff, 7, ff + 2, FALSE)))) {
512 callback(board, flags,
513 ff==4 ? BlackKingSideCastle : BlackKingSideCastleWild,
514 7, ff, 7, ff + 2, closure);
516 if (!(flags & F_WHITE_ON_MOVE) &&
517 (flags & F_BLACK_QCASTLE_OK) &&
518 board[7][ff] == BlackKing &&
519 board[7][ff - 1] == EmptySquare &&
520 board[7][ff - 2] == EmptySquare &&
521 board[7][1] == EmptySquare &&
522 board[7][0] == BlackRook &&
524 (!CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE) &&
525 !CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE)))) {
527 callback(board, flags,
528 ff==4 ? BlackQueenSideCastle : BlackQueenSideCastleWild,
529 7, ff, 7, ff - 2, closure);
535 /* generate all potential FRC castling moves (KxR), ignoring flags */
537 if ((flags & F_WHITE_ON_MOVE) != 0) {
539 for (ff = 1; ff < 7; ff++) {
540 if (board[0][ff] == WhiteKing) {
541 for (ft = 0; ft < 8; ft++) {
542 if (board[0][ft] == WhiteRook) {
543 callback(board, flags,
544 (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,
545 0, ff, 0, ft, closure);
553 for (ff = 1; ff < 7; ff++) {
554 if (board[7][ff] == BlackKing) {
555 for (ft = 0; ft < 8; ft++) {
556 if (board[7][ft] == BlackRook) {
557 callback(board, flags,
558 (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,
559 7, ff, 7, ft, closure);
578 extern void CheckTestCallback P((Board board, int flags, ChessMove kind,
579 int rf, int ff, int rt, int ft,
583 void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
590 register CheckTestClosure *cl = (CheckTestClosure *) closure;
592 if (rt == cl->rking && ft == cl->fking) cl->check++;
596 /* If the player on move were to move from (rf, ff) to (rt, ft), would
597 he leave himself in check? Or if rf == -1, is the player on move
598 in check now? enPassant must be TRUE if the indicated move is an
599 e.p. capture. The possibility of castling out of a check along the
600 back rank is not accounted for (i.e., we still return nonzero), as
601 this is illegal anyway. Return value is the number of times the
603 int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
606 int rf, ff, rt, ft, enPassant;
609 ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
610 ChessSquare captured = EmptySquare;
611 /* Suppress warnings on uninitialized variables */
615 captured = board[rf][ft];
616 board[rf][ft] = EmptySquare;
618 captured = board[rt][ft];
620 board[rt][ft] = board[rf][ff];
621 board[rf][ff] = EmptySquare;
624 /* For compatibility with ICS wild 9, we scan the board in the
625 order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
626 and we test only whether that one is in check. */
628 for (cl.fking = 0; cl.fking <= 7; cl.fking++)
629 for (cl.rking = 0; cl.rking <= 7; cl.rking++) {
630 if (board[cl.rking][cl.fking] == king) {
631 GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
632 CheckTestCallback, (VOIDSTAR) &cl);
633 goto undo_move; /* 2-level break */
640 board[rf][ff] = board[rt][ft];
642 board[rf][ft] = captured;
643 board[rt][ft] = EmptySquare;
645 board[rt][ft] = captured;
653 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
654 int rf, int ff, int rt, int ft,
657 void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
664 register LegalityTestClosure *cl = (LegalityTestClosure *) closure;
666 if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
670 ChessMove LegalityTest(board, flags, epfile, rf, ff, rt, ft, promoChar)
673 int rf, ff, rt, ft, promoChar;
675 LegalityTestClosure cl;
681 cl.kind = IllegalMove;
682 GenLegal(board, flags, epfile, LegalityTestCallback, (VOIDSTAR) &cl);
683 if (promoChar != NULLCHAR && promoChar != 'x') {
684 if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
686 PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
688 cl.kind = IllegalMove;
698 extern void MateTestCallback P((Board board, int flags, ChessMove kind,
699 int rf, int ff, int rt, int ft,
702 void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
709 register MateTestClosure *cl = (MateTestClosure *) closure;
714 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
715 int MateTest(board, flags, epfile)
723 inCheck = GenLegal(board, flags, epfile, MateTestCallback, (VOIDSTAR) &cl);
725 return inCheck ? MT_CHECK : MT_NONE;
727 return inCheck ? MT_CHECKMATE : MT_STALEMATE;
732 extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,
733 int rf, int ff, int rt, int ft,
736 void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
743 register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
745 if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&
746 (cl->rfIn == -1 || cl->rfIn == rf) &&
747 (cl->ffIn == -1 || cl->ffIn == ff) &&
748 (cl->rtIn == -1 || cl->rtIn == rt) &&
749 (cl->ftIn == -1 || cl->ftIn == ft)) {
752 cl->piece = board[rf][ff];
761 void Disambiguate(board, flags, epfile, closure)
764 DisambiguateClosure *closure;
768 closure->rf = closure->ff = closure->rt = closure->ft = 0;
769 closure->kind = ImpossibleMove;
770 GenLegal(board, flags, epfile, DisambiguateCallback, (VOIDSTAR) closure);
771 if (closure->count == 0) {
772 /* See if it's an illegal move due to check */
774 GenLegal(board, flags|F_IGNORE_CHECK, epfile, DisambiguateCallback,
776 if (closure->count == 0) {
777 /* No, it's not even that */
781 if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {
782 if (closure->kind == WhitePromotionQueen
783 || closure->kind == BlackPromotionQueen) {
785 PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,
786 closure->promoCharIn);
788 closure->kind = IllegalMove;
791 closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));
792 if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
793 if (closure->count > 1) {
794 closure->kind = AmbiguousMove;
797 /* Note: If more than one illegal move matches, but no legal
798 moves, we return IllegalMove, not AmbiguousMove. Caller
799 can look at closure->count to detect this.
801 closure->kind = IllegalMove;
815 } CoordsToAlgebraicClosure;
817 extern void CoordsToAlgebraicCallback P((Board board, int flags,
818 ChessMove kind, int rf, int ff,
819 int rt, int ft, VOIDSTAR closure));
821 void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
828 register CoordsToAlgebraicClosure *cl =
829 (CoordsToAlgebraicClosure *) closure;
831 if (rt == cl->rt && ft == cl->ft &&
832 board[rf][ff] == cl->piece) {
835 cl->kind = kind; /* this is the move we want */
837 cl->file++; /* need file to rule out this move */
841 cl->rank++; /* need rank to rule out this move */
843 cl->either++; /* rank or file will rule out this move */
849 /* Convert coordinates to normal algebraic notation.
850 promoChar must be NULLCHAR or 'x' if not a promotion.
852 ChessMove CoordsToAlgebraic(board, flags, epfile,
853 rf, ff, rt, ft, promoChar, out)
863 CoordsToAlgebraicClosure cl;
865 if (rf == DROP_RANK) {
866 /* Bughouse piece drop */
867 *outp++ = ToUpper(PieceToChar((ChessSquare) ff));
872 return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;
875 if (promoChar == 'x') promoChar = NULLCHAR;
876 piece = board[rf][ff];
880 kind = LegalityTest(board, flags, epfile, rf, ff, rt, ft, promoChar);
881 if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
882 /* Keep short notation if move is illegal only because it
883 leaves the player in check, but still return IllegalMove */
884 kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile,
885 rf, ff, rt, ft, promoChar);
886 if (kind == IllegalMove) break;
892 /* Non-capture; use style "e5" */
895 /* Capture; use style "exd5" */
900 /* Use promotion suffix style "=Q" */
901 if (promoChar != NULLCHAR && promoChar != 'x') {
903 *outp++ = ToUpper(promoChar);
911 /* Fabien moved code: FRC castling first (if KxR), wild castling second */
912 /* Code added by Tord: FRC castling. */
913 if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||
914 (piece == BlackKing && board[rt][ft] == BlackRook)) {
915 if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");
916 return LegalityTest(board, flags, epfile,
917 rf, ff, rt, ft, promoChar);
919 /* End of code added by Tord */
920 /* Test for castling or ICS wild castling */
921 /* Use style "O-O" (oh-oh) for PGN compatibility */
923 rf == ((piece == WhiteKing) ? 0 : 7) &&
924 ((ff == 4 && (ft == 2 || ft == 6)) ||
925 (ff == 3 && (ft == 1 || ft == 5)))) {
933 strcpy(out, "O-O-O");
936 /* This notation is always unambiguous, unless there are
937 kings on both the d and e files, with "wild castling"
938 possible for the king on the d file and normal castling
939 possible for the other. ICS rules for wild 9
940 effectively make castling illegal for either king in
941 this situation. So I am not going to worry about it;
942 I'll just generate an ambiguous O-O in this case.
944 return LegalityTest(board, flags, epfile,
945 rf, ff, rt, ft, promoChar);
948 /* else fall through */
957 cl.kind = IllegalMove;
958 cl.rank = cl.file = cl.either = 0;
959 GenLegal(board, flags, epfile,
960 CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
962 if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
963 /* Generate pretty moves for moving into check, but
964 still return IllegalMove.
966 GenLegal(board, flags|F_IGNORE_CHECK, epfile,
967 CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
968 if (cl.kind == IllegalMove) break;
969 cl.kind = IllegalMove;
972 /* Style is "Nf3" or "Nxf7" if this is unambiguous,
973 else "Ngf3" or "Ngxf7",
974 else "N1f3" or "N5xf7",
975 else "Ng1f3" or "Ng5xf7".
977 *outp++ = ToUpper(PieceToChar(piece));
979 if (cl.file || (cl.either && !cl.rank)) {
986 if(board[rt][ft] != EmptySquare)
995 /* Moving a nonexistent piece */
999 /* Not a legal move, even ignoring check.
1000 If there was a piece on the from square,
1001 use style "Ng1g3" or "Ng1xe8";
1002 if there was a pawn or nothing (!),
1003 use style "g1g3" or "g1xe8". Use "x"
1004 if a piece was on the to square, even
1005 a piece of the same color.
1008 if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
1009 *outp++ = ToUpper(PieceToChar(piece));
1013 if (board[rt][ft] != EmptySquare) *outp++ = 'x';
1016 /* Use promotion suffix style "=Q" */
1017 if (promoChar != NULLCHAR && promoChar != 'x') {
1019 *outp++ = ToUpper(promoChar);