Fix build failure.
[cboard.git] / libchess / move.c
blob0b5948c6814f4119ed9f3783433ba3d4783bc308
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2019 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
28 #include "chess.h"
29 #include "common.h"
31 #ifdef DEBUG
32 #include "debug.h"
33 #endif
35 enum
37 CHECK = 1,
38 CHECK_SELF,
39 CHECK_MATE
42 enum
44 KINGSIDE = 1, QUEENSIDE
47 static int finalize_move (GAME g, BOARD b, int promo, int sfile, int srank,
48 int file, int rank);
49 static int find_source_square (GAME, BOARD, int, int *, int *, int, int);
50 static int check_self (GAME g, BOARD b, int file, int rank);
51 static int validate_pawn (GAME g, BOARD b, int sfile, int srank, int file,
52 int rank);
53 static int find_source_square (GAME, BOARD, int, int *, int *, int, int);
55 static int
56 val_piece_side (char turn, int c)
58 if ((isupper (c) && turn == WHITE) || (islower (c) && turn == BLACK))
59 return 1;
61 return 0;
64 static int
65 count_piece (GAME g, BOARD b, int piece, int sfile,
66 int srank, int file, int rank, int *count)
68 int p, pi;
70 if (!VALIDRANK (rank) || !VALIDFILE (file))
71 return 0;
73 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
74 pi = pgn_piece_to_int (p);
76 if (pi != OPEN_SQUARE)
78 if (pi == piece && val_piece_side (g->turn, p))
80 if (sfile && file == sfile)
82 if (!srank || (srank && rank == srank))
83 (*count)++;
85 else if (srank && rank == srank)
87 if (!sfile)
88 (*count)++;
90 else if (!sfile && !srank)
91 (*count)++;
94 return 1;
97 return 0;
101 * Get the source row and column for a given piece.
103 * The following two functions find 'piece' from the given square 'col' and
104 * 'row' and store the resulting column or row in 'c' and 'r'. The return
105 * value is the number of 'piece' found (on the current g->side) or zero.
106 * Search for 'piece' stops when a non-empty square is found.
108 static int
109 count_by_diag (GAME g, BOARD b, int piece,
110 int sfile, int srank, int file, int rank)
112 int count = 0;
113 int ul = 0, ur = 0, dl = 0, dr = 0;
114 int i;
115 int f, r;
117 for (i = 1; VALIDFILE (i); i++)
119 r = rank + i;
120 f = file - i;
122 if (!ul && VALIDRANK (r) && VALIDFILE (f))
123 ul = count_piece (g, b, piece, sfile, srank, f, r, &count);
125 r = rank + i;
126 f = file + i;
128 if (!ur && VALIDRANK (r) && VALIDFILE (f))
129 ur = count_piece (g, b, piece, sfile, srank, f, r, &count);
131 r = rank - i;
132 f = file - i;
134 if (!dl && VALIDRANK (r) && VALIDFILE (f))
135 dl = count_piece (g, b, piece, sfile, srank, f, r, &count);
137 r = rank - i;
138 f = file + i;
140 if (!dr && VALIDRANK (r) && VALIDFILE (f))
141 dr = count_piece (g, b, piece, sfile, srank, f, r, &count);
144 return count;
147 static int
148 count_knight (GAME g, BOARD b, int piece, int sfile, int srank,
149 int file, int rank)
151 int count = 0;
153 count_piece (g, b, piece, sfile, srank, file - 1, rank + 2, &count);
154 count_piece (g, b, piece, sfile, srank, file + 1, rank + 2, &count);
155 count_piece (g, b, piece, sfile, srank, file + 2, rank + 1, &count);
156 count_piece (g, b, piece, sfile, srank, file - 2, rank + 1, &count);
157 count_piece (g, b, piece, sfile, srank, file + 1, rank - 2, &count);
158 count_piece (g, b, piece, sfile, srank, file - 1, rank - 2, &count);
159 count_piece (g, b, piece, sfile, srank, file + 2, rank - 1, &count);
160 count_piece (g, b, piece, sfile, srank, file - 2, rank - 1, &count);
161 return count;
164 static int
165 count_by_rank (GAME g, BOARD b, int piece,
166 int sfile, int srank, int file, int rank)
168 int i;
169 int count = 0;
170 int u = 0, d = 0;
172 for (i = 1; VALIDRANK (i); i++)
174 if (!u && VALIDRANK ((rank + i)))
175 u = count_piece (g, b, piece, sfile, srank, file, rank + i, &count);
177 if (!d && VALIDRANK ((rank - i)))
178 d = count_piece (g, b, piece, sfile, srank, file, rank - i, &count);
180 if (d && u)
181 break;
184 return count;
187 static int
188 count_by_file (GAME g, BOARD b, int piece,
189 int sfile, int srank, int file, int rank)
191 int i;
192 int count = 0;
193 int l = 0, r = 0;
195 for (i = 1; VALIDFILE (i); i++)
197 if (!r && VALIDFILE ((file + i)))
198 r = count_piece (g, b, piece, sfile, srank, file + i, rank, &count);
200 if (!l && VALIDFILE ((file - i)))
201 l = count_piece (g, b, piece, sfile, srank, file - i, rank, &count);
203 if (r && l)
204 break;
207 return count;
210 static int
211 count_by_rank_file (GAME g, BOARD b, int piece,
212 int sfile, int srank, int file, int rank)
214 int count;
216 count = count_by_rank (g, b, piece, sfile, srank, file, rank);
217 return count + count_by_file (g, b, piece, sfile, srank, file, rank);
220 static int
221 opponent_can_attack (GAME g, BOARD b, int file, int rank)
223 int f, r;
224 int p, pi;
225 int kf = g->kfile, kr = g->krank;
227 pgn_switch_turn (g);
228 g->kfile = g->okfile, g->krank = g->okrank;
230 for (r = 1; VALIDRANK (r); r++)
232 for (f = 1; VALIDFILE (f); f++)
234 p = b[RANKTOBOARD (r)][FILETOBOARD (f)].icon;
235 pi = pgn_piece_to_int (p);
237 if (pi == OPEN_SQUARE || !val_piece_side (g->turn, p))
238 continue;
240 if (find_source_square (g, b, pi, &f, &r, file, rank) != 0)
242 g->kfile = kf, g->krank = kr;
243 pgn_switch_turn (g);
244 return 1;
249 g->kfile = kf, g->krank = kr;
250 pgn_switch_turn (g);
251 return 0;
254 static int
255 validate_castle_move (GAME g, BOARD b, int side, int sfile,
256 int srank, int file, int rank)
258 int n;
260 if (side == KINGSIDE)
262 if ((g->turn == WHITE && !TEST_FLAG (g->flags, GF_WK_CASTLE)) ||
263 (g->turn == BLACK && !TEST_FLAG (g->flags, GF_BK_CASTLE)))
264 return E_PGN_INVALID;
266 else
268 if ((g->turn == WHITE && !TEST_FLAG (g->flags, GF_WQ_CASTLE)) ||
269 (g->turn == BLACK && !TEST_FLAG (g->flags, GF_BQ_CASTLE)))
270 return E_PGN_INVALID;
273 if (file > FILETOINT ('e'))
275 if (b[RANKTOBOARD (srank)][FILETOBOARD ((sfile + 1))].icon
276 != pgn_int_to_piece (g->turn, OPEN_SQUARE) ||
277 b[RANKTOBOARD (srank)][FILETOBOARD ((sfile + 2))].icon
278 != pgn_int_to_piece (g->turn, OPEN_SQUARE))
279 return E_PGN_INVALID;
282 if (pgn_config.strict_castling > 0)
284 if (opponent_can_attack (g, b, sfile + 1, srank))
285 return E_PGN_INVALID;
287 if (opponent_can_attack (g, b, sfile + 2, srank))
288 return E_PGN_INVALID;
291 else
293 if (b[RANKTOBOARD (srank)][FILETOBOARD ((sfile - 1))].icon !=
294 pgn_int_to_piece (g->turn, OPEN_SQUARE) ||
295 b[RANKTOBOARD (srank)][FILETOBOARD ((sfile - 2))].icon !=
296 pgn_int_to_piece (g->turn, OPEN_SQUARE) ||
297 b[RANKTOBOARD (srank)][FILETOBOARD ((sfile - 3))].icon !=
298 pgn_int_to_piece (g->turn, OPEN_SQUARE))
299 return E_PGN_INVALID;
301 if (pgn_config.strict_castling > 0)
303 if (opponent_can_attack (g, b, sfile - 1, srank))
304 return E_PGN_INVALID;
306 if (opponent_can_attack (g, b, sfile - 2, srank))
307 return E_PGN_INVALID;
309 if (opponent_can_attack (g, b, sfile - 3, srank))
310 return E_PGN_INVALID;
314 n = g->check_testing;
315 g->check_testing = 1;
317 if (check_self (g, b, g->kfile, g->krank) == CHECK_SELF)
319 g->check_testing = n;
320 return E_PGN_INVALID;
323 g->check_testing = n;
324 g->castle = side;
325 return E_PGN_OK;
328 static int
329 validate_piece (GAME g, BOARD b, int p, int sfile,
330 int srank, int file, int rank)
332 int f, r;
333 int i, dist;
335 switch (p)
337 case PAWN:
338 if (sfile == file)
340 /* Find the first pawn in the current column. */
341 i = (g->turn == WHITE) ? -1 : 1;
343 if (!srank)
345 for (r = rank + i, dist = 0; VALIDFILE (r); r += i, dist++)
347 p = b[RANKTOBOARD (r)][FILETOBOARD (file)].icon;
349 if (pgn_piece_to_int (p) != OPEN_SQUARE)
350 break;
353 if (pgn_piece_to_int (p) != PAWN || !val_piece_side (g->turn, p)
354 || dist > 2)
355 return E_PGN_INVALID;
357 srank = r;
359 else
361 dist = abs (srank - rank);
362 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
364 if (pgn_piece_to_int (p) != PAWN || !val_piece_side (g->turn, p)
365 || dist > 2)
366 return E_PGN_INVALID;
369 if (g->turn == WHITE)
371 if ((srank == 2 && dist > 2) || (srank > 2 && dist > 1))
372 return E_PGN_INVALID;
374 else
376 if ((srank == 7 && dist > 2) || (srank < 7 && dist > 1))
377 return E_PGN_INVALID;
380 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
382 if (pgn_piece_to_int (p) != OPEN_SQUARE)
383 return E_PGN_INVALID;
385 else if (sfile != file)
387 if (abs (sfile - file) != 1)
388 return E_PGN_INVALID;
390 srank = (g->turn == WHITE) ? rank - 1 : rank + 1;
391 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
393 if (!val_piece_side (g->turn, p))
394 return E_PGN_INVALID;
396 if (pgn_piece_to_int (p) != PAWN || abs (srank - rank) != 1)
397 return E_PGN_INVALID;
399 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
401 /* En Passant. */
402 if (pgn_piece_to_int (p) == OPEN_SQUARE)
404 /* Previous move was not 2 squares and a pawn. */
405 if (!TEST_FLAG (g->flags, GF_ENPASSANT))
406 return E_PGN_INVALID;
408 if (!b[RANKTOBOARD (rank)][FILETOBOARD (file)].enpassant)
409 return E_PGN_INVALID;
411 r = (g->turn == WHITE) ? 6 : 3;
413 if (rank != r)
414 return E_PGN_INVALID;
416 r = (g->turn == WHITE) ? rank - 1 : rank + 1;
417 p = b[RANKTOBOARD (r)][FILETOBOARD (file)].icon;
419 if (pgn_piece_to_int (p) != PAWN)
420 return E_PGN_INVALID;
423 if (val_piece_side (g->turn, p))
424 return E_PGN_INVALID;
427 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
429 if (!val_piece_side (g->turn, p))
430 return E_PGN_INVALID;
432 break;
433 case KING:
434 f = abs (sfile - file);
435 r = abs (srank - rank);
437 if (r > 1 || f > 2)
438 return E_PGN_INVALID;
440 if (f == 2)
442 if (sfile != FILETOINT ('e'))
443 return E_PGN_INVALID;
444 else
446 if (validate_castle_move (g, b, (file > FILETOINT ('e')) ?
447 KINGSIDE : QUEENSIDE, sfile, srank,
448 file, rank) != E_PGN_OK)
449 return E_PGN_INVALID;
452 break;
453 default:
454 break;
457 return E_PGN_OK;
461 * Returns the number of pieces of type 'p' that can move to the destination
462 * square located at 'file' and 'rank'. The source square 'sfile' and 'srank'
463 * (if available in the move text) should be determined before calling this
464 * function or set to 0 if unknown. Returns 0 if the move is impossible for
465 * the piece 'p'.
467 static int
468 find_ambiguous (GAME g, BOARD b, int p, int sfile,
469 int srank, int file, int rank)
471 int count = 0;
473 switch (p)
475 case PAWN:
476 count = validate_pawn (g, b, sfile, srank, file, rank);
477 break;
478 case ROOK:
479 count = count_by_rank_file (g, b, p, sfile, srank, file, rank);
480 break;
481 case KNIGHT:
482 count = count_knight (g, b, p, sfile, srank, file, rank);
483 break;
484 case BISHOP:
485 count = count_by_diag (g, b, p, sfile, srank, file, rank);
486 break;
487 case QUEEN:
488 count = count_by_rank_file (g, b, p, sfile, srank, file, rank);
489 count += count_by_diag (g, b, p, sfile, srank, file, rank);
490 break;
491 case KING:
492 count = count_by_rank_file (g, b, p, sfile, srank, file, rank);
493 count += count_by_diag (g, b, p, sfile, srank, file, rank);
494 break;
495 default:
496 break;
499 return count;
502 static void
503 find_king_squares (GAME g, BOARD b, int *file,
504 int *rank, int *ofile, int *orank)
506 int f, r;
508 for (r = 1; VALIDRANK (r); r++)
510 for (f = 1; VALIDFILE (f); f++)
512 int p = b[RANKTOBOARD (r)][FILETOBOARD (f)].icon;
513 int pi = pgn_piece_to_int (p);
515 if (pi == OPEN_SQUARE || pi != KING)
516 continue;
518 if (val_piece_side (g->turn, p))
519 *file = f, *rank = r;
520 else
521 *ofile = f, *orank = r;
525 #ifdef DEBUG
526 PGN_DUMP ("%s:%d: king location: %c%c %c%c(opponent)\n", __FILE__,
527 __LINE__, INTTOFILE (*file), INTTORANK (*rank),
528 INTTOFILE (*ofile), INTTORANK (*orank));
529 #endif
532 static int
533 parse_castle_move (GAME g, BOARD b, int side, int *sfile,
534 int *srank, int *file, int *rank)
536 *srank = *rank = (g->turn == WHITE) ? 1 : 8;
537 *sfile = FILETOINT ('e');
539 if (side == KINGSIDE)
540 *file = FILETOINT ('g');
541 else
542 *file = FILETOINT ('c');
544 return validate_castle_move (g, b, side, *sfile, *srank, *file, *rank);
548 * Almost exactly like pgn_find_valid_moves() but returns immediately after a
549 * valid move is found.
551 static int
552 check_mate_thingy (GAME g, BOARD b, int file, int rank)
554 int r, f;
555 int p = pgn_piece_to_int (b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon);
557 for (r = 1; VALIDRANK (r); r++)
559 for (f = 1; VALIDFILE (f); f++)
561 if (val_piece_side
562 (g->turn, b[RANKTOBOARD (r)][FILETOBOARD (f)].icon))
563 continue;
565 if (find_source_square (g, b, p, &file, &rank, f, r) != 0)
566 return 1;
570 return 0;
573 static int
574 checkmate_test (GAME g, BOARD b)
576 int f, r;
577 int n = CHECK_MATE;
578 int kf = g->kfile, kr = g->krank, okf = g->okfile, okr = g->okrank;
580 #ifdef DEBUG
581 PGN_DUMP ("%s:%d: BEGIN checkmate test\n", __FILE__, __LINE__);
582 #endif
584 * The king squares need to be switched also for find_source_squares()
585 * which calls check_self().
587 pgn_switch_turn (g);
588 g->kfile = g->okfile, g->krank = g->okrank;
590 for (r = 1; VALIDRANK (r); r++)
592 for (f = 1; VALIDFILE (f); f++)
594 int p;
595 int sfile = f, srank = r;
597 p = b[RANKTOBOARD (r)][FILETOBOARD (f)].icon;
599 if (p == OPEN_SQUARE || !val_piece_side (g->turn, p))
600 continue;
602 if (check_mate_thingy (g, b, sfile, srank))
604 n = CHECK;
605 goto done;
610 done:
611 pgn_switch_turn (g);
612 g->kfile = kf, g->krank = kr, g->okfile = okf, g->okrank = okr;
613 return n;
616 static int
617 check_opponent (GAME g, BOARD b, int file, int rank)
619 int f, r;
620 int p, pi;
622 #ifdef DEBUG
623 PGN_DUMP ("%s:%d: BEGIN opponent check test\n", __FILE__, __LINE__);
624 #endif
626 for (r = 1; VALIDRANK (r); r++)
628 for (f = 1; VALIDFILE (f); f++)
630 p = b[RANKTOBOARD (r)][FILETOBOARD (f)].icon;
631 pi = pgn_piece_to_int (p);
633 if (pi == OPEN_SQUARE || !val_piece_side (g->turn, p))
634 continue;
636 if (find_source_square (g, b, pi, &f, &r, file, rank) != 0)
637 return CHECK;
641 return 0;
644 static int
645 check_self (GAME g, BOARD b, int file, int rank)
647 int f, r;
648 int p, pi;
650 #ifdef DEBUG
651 PGN_DUMP ("%s:%d: BEGIN self check test\n", __FILE__, __LINE__);
652 #endif
653 pgn_switch_turn (g);
655 for (r = 1; VALIDRANK (r); r++)
657 for (f = 1; VALIDFILE (f); f++)
659 p = b[RANKTOBOARD (r)][FILETOBOARD (f)].icon;
660 pi = pgn_piece_to_int (p);
662 if (pi == OPEN_SQUARE || !val_piece_side (g->turn, p))
663 continue;
665 if (find_source_square (g, b, pi, &f, &r, file, rank) != 0)
667 pgn_switch_turn (g);
668 return CHECK_SELF;
673 pgn_switch_turn (g);
674 return g->check;
677 static int
678 check_test (GAME g, BOARD b)
680 #ifdef DEBUG
681 PGN_DUMP ("%s:%d: BEGIN check test\n", __FILE__, __LINE__);
682 #endif
683 g->check = check_opponent (g, b, g->okfile, g->okrank);
685 if (g->check)
686 return checkmate_test (g, b);
688 g->check_testing = 0;
689 return g->check;
692 static int
693 validate_pawn (GAME g, BOARD b, int sfile, int srank, int file, int rank)
695 int n = abs (srank - rank);
696 int p;
698 if (abs (sfile - file) > 1)
699 return 0;
701 if (g->turn == WHITE)
703 if ((srank == 2 && n > 2) || (srank > 2 && n > 1))
704 return 0;
706 else
708 if ((srank == 7 && n > 2) || (srank < 7 && n > 1))
709 return 0;
712 if (n > 1 && abs (sfile - file) != 0)
713 return 0;
715 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
717 if (!val_piece_side (g->turn, p) || pgn_piece_to_int (p) != PAWN)
718 return 0;
720 if (srank == rank || (g->turn == WHITE && rank < srank) ||
721 (g->turn == BLACK && rank > srank))
722 return 0;
724 if (sfile == file)
726 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
728 if (pgn_piece_to_int (p) != OPEN_SQUARE)
729 return 0;
731 p = (g->turn == WHITE) ? rank - 1 : rank + 1;
732 p = b[RANKTOBOARD (p)][FILETOBOARD (file)].icon;
734 if (n > 1 && pgn_piece_to_int (p) != OPEN_SQUARE)
735 return 0;
737 return 1;
740 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
742 if (pgn_piece_to_int (p) != OPEN_SQUARE)
744 if (val_piece_side (g->turn, p))
745 return 0;
747 return 1;
750 /* En Passant. */
751 p = (g->turn == WHITE) ? rank - 1 : rank + 1;
752 p = b[RANKTOBOARD (p)][FILETOBOARD (file)].icon;
754 if (pgn_piece_to_int (p) == OPEN_SQUARE || val_piece_side (g->turn, p))
755 return 0;
757 /* Previous move was not 2 squares and a pawn. */
758 if (!TEST_FLAG (g->flags, GF_ENPASSANT) ||
759 b[RANKTOBOARD (rank)][FILETOBOARD (file)].enpassant == 0)
760 return 0;
763 // GF_ENPASSANT should take care of this
764 if (!b[RANKTOBOARD(rank)][FILETOBOARD(file)].enpassant)
765 return 0;
768 if ((g->turn == WHITE && rank != 6) || (g->turn == BLACK && rank != 3))
769 return 0;
771 #if 0
772 // GF_ENPASSANT should take care of this
773 n = (g->turn == WHITE) ? rank - 1 : rank + 1;
774 p = b[RANKTOBOARD (n)][FILETOBOARD (file)].icon;
776 if (pgn_piece_to_int (p) != PAWN)
777 return 0;
779 if (val_piece_side (g->turn, p))
780 return 0;
781 #endif
783 return 1;
786 static int
787 check_self_test (GAME g, BOARD b, int p, int sfile, int srank,
788 int file, int rank)
790 BOARD tmpb;
791 struct game_s newg;
792 int oldv = g->validate;
793 int nkfile, nkrank, nokfile, nokrank;
794 int go;
796 nkrank = nkfile = 0;
797 g->validate = 0;
798 g->check_testing = 1;
799 memcpy (tmpb, b, sizeof (BOARD));
800 memcpy (&newg, g, sizeof (struct game_s));
802 if (finalize_move (&newg, tmpb, 0, sfile, srank, file, rank) != E_PGN_OK)
804 g->check_testing = 0;
805 g->validate = oldv;
806 return 0;
809 if (p == KING)
810 find_king_squares (&newg, tmpb, &nkfile, &nkrank, &nokfile, &nokrank);
811 else
812 nkfile = g->kfile, nkrank = g->krank;
814 go = TEST_FLAG (newg.flags, GF_GAMEOVER);
815 memcpy (&newg, g, sizeof (struct game_s));
817 if (check_self (&newg, tmpb, nkfile, nkrank) == CHECK_SELF)
819 g->check_testing = 0;
820 g->validate = oldv;
821 return 0;
824 if (!g->validate && !g->validate_find)
826 g->flags = newg.flags;
828 if (go)
829 SET_FLAG (g->flags, GF_GAMEOVER);
832 g->validate = oldv;
833 g->check_testing = 0;
834 return 1;
837 static int
838 find_source_square (GAME g, BOARD b, int piece, int *sfile,
839 int *srank, int file, int rank)
841 int p = 0;
842 int r, f, i;
843 int dist = 0;
844 int count = 0;
846 #ifdef DEBUG
847 PGN_DUMP ("%s:%d: finding source square: piece=%c source=%c%c dest=%c%c\n",
848 __FILE__, __LINE__, pgn_int_to_piece (g->turn, piece),
849 (*sfile) ? INTTOFILE (*sfile) : '0',
850 (*srank) ? INTTORANK (*srank) : '0', INTTOFILE (file),
851 INTTORANK (rank));
852 #endif
854 if (piece == PAWN)
856 if (!*srank && *sfile == file)
858 /* Find the first pawn in 'file'. */
859 i = (g->turn == WHITE) ? -1 : 1;
861 for (r = rank + i, dist = 0; VALIDFILE (r); r += i, dist++)
864 pgn_piece_to_int (b[RANKTOBOARD (r)][FILETOBOARD (file)].
865 icon);
867 if (p != OPEN_SQUARE)
868 break;
871 *srank = r;
874 if (!*srank)
875 *srank = (g->turn == WHITE) ? rank - 1 : rank + 1;
877 if (!validate_pawn (g, b, *sfile, *srank, file, rank))
878 return 0;
879 else
880 count = 1;
882 if (!g->check_testing)
884 if (check_self_test (g, b, piece, *sfile, *srank, file, rank) == 0)
885 return 0;
888 else
890 if (*sfile && *srank)
892 count = find_ambiguous (g, b, piece, *sfile, *srank, file, rank);
894 if (count != 1)
895 return count;
897 if (!g->check_testing)
899 if (check_self_test (g, b, piece, *sfile, *srank, file, rank)
900 == 0)
901 return 0;
904 else
906 int ff = *sfile, rr = *srank;
908 for (r = 1; VALIDRANK (r); r++)
910 for (f = 1; VALIDFILE (f); f++)
912 int n;
914 if ((*sfile && f != ff) || (*srank && r != rr))
915 continue;
917 n = find_ambiguous (g, b, piece, f, r, file, rank);
919 if (n)
921 if (!g->check_testing &&
922 check_self_test (g, b, piece, f, r, file,
923 rank) == 0)
924 continue;
926 count += n;
927 ff = f;
928 rr = r;
933 if (count == 1)
935 *sfile = ff;
936 *srank = rr;
940 if (validate_piece (g, b, piece, *sfile, *srank, file, rank) !=
941 E_PGN_OK)
942 return 0;
945 return count;
948 static int
949 finalize_move (GAME g, BOARD b, int promo, int sfile, int srank,
950 int file, int rank)
952 int p, pi;
954 #ifdef DEBUG
955 if (!g->validate && !g->check_testing)
956 PGN_DUMP ("%s:%d: BEGIN finalizing\n", __FILE__, __LINE__);
957 #endif
959 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
960 pi = pgn_piece_to_int (p);
962 if (pi != OPEN_SQUARE && val_piece_side (g->turn, p))
963 return E_PGN_INVALID;
965 if (!g->validate)
967 #ifdef DEBUG
968 if (!g->check_testing)
969 PGN_DUMP ("%s:%d: updating board and game flags\n", __FILE__,
970 __LINE__);
971 #endif
972 pgn_reset_enpassant (b);
973 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
974 pi = pgn_piece_to_int (p);
976 if (pi == PAWN)
978 p = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
980 if (sfile != file && pgn_piece_to_int (p) == OPEN_SQUARE &&
981 TEST_FLAG (g->flags, GF_ENPASSANT))
983 p = (g->turn == WHITE) ? rank - 1 : rank + 1;
984 b[RANKTOBOARD (p)][FILETOBOARD (file)].icon =
985 pgn_int_to_piece (g->turn, OPEN_SQUARE);
988 if (abs (srank - rank) > 1)
990 SET_FLAG (g->flags, GF_ENPASSANT);
991 b[RANKTOBOARD (((g->turn == WHITE) ? rank - 1 : rank + 1))]
992 [FILETOBOARD (file)].enpassant = 1;
995 else if (pi == ROOK)
997 if (g->turn == WHITE)
999 if (sfile == FILETOINT ('h') && srank == 1)
1000 CLEAR_FLAG (g->flags, GF_WK_CASTLE);
1001 else if (sfile == FILETOINT ('a') && srank == 1)
1002 CLEAR_FLAG (g->flags, GF_WQ_CASTLE);
1004 else
1006 if (sfile == FILETOINT ('h') && srank == 8)
1007 CLEAR_FLAG (g->flags, GF_BK_CASTLE);
1008 else if (sfile == FILETOINT ('a') && srank == 8)
1009 CLEAR_FLAG (g->flags, GF_BQ_CASTLE);
1013 if (pi != PAWN)
1014 CLEAR_FLAG (g->flags, GF_ENPASSANT);
1016 if (pi == KING && !g->castle)
1018 if (g->turn == WHITE)
1019 CLEAR_FLAG (g->flags, GF_WK_CASTLE | GF_WQ_CASTLE);
1020 else
1021 CLEAR_FLAG (g->flags, GF_BK_CASTLE | GF_BQ_CASTLE);
1024 if (g->castle)
1026 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
1027 b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon =
1028 pgn_int_to_piece (g->turn, OPEN_SQUARE);
1029 b[RANKTOBOARD (srank)][FILETOBOARD ((file >
1030 FILETOINT ('e') ? 8 : 1))].
1031 icon = pgn_int_to_piece (g->turn, OPEN_SQUARE);
1032 b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon = p;
1034 if (file > FILETOINT ('e'))
1035 b[RANKTOBOARD (rank)][FILETOBOARD ((file - 1))].icon =
1036 pgn_int_to_piece (g->turn, ROOK);
1037 else
1038 b[RANKTOBOARD (rank)][FILETOBOARD ((file + 1))].icon =
1039 pgn_int_to_piece (g->turn, ROOK);
1041 if (g->turn == WHITE)
1042 CLEAR_FLAG (g->flags, (file > FILETOINT ('e')) ? GF_WK_CASTLE :
1043 GF_WQ_CASTLE);
1044 else
1045 CLEAR_FLAG (g->flags, (file > FILETOINT ('e')) ? GF_BK_CASTLE :
1046 GF_BQ_CASTLE);
1048 else
1050 if (promo)
1051 p = pgn_int_to_piece (g->turn, promo);
1052 else
1053 p = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
1055 b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon =
1056 pgn_int_to_piece (g->turn, OPEN_SQUARE);
1057 b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon = p;
1061 g->castle = 0;
1063 if (!g->check_testing)
1065 if (pgn_piece_to_int (p) == KING)
1066 find_king_squares (g, b, &g->kfile, &g->krank, &g->okfile,
1067 &g->okrank);
1069 switch (check_test (g, b))
1071 case CHECK:
1072 g->check = CHECK;
1073 break;
1074 case CHECK_MATE:
1075 g->check = CHECK_MATE;
1077 if (!g->validate)
1079 pgn_tag_add (&g->tag, (char *) "Result",
1080 (g->turn ==
1081 WHITE) ? (char *) "1-0" : (char *) "0-1");
1082 SET_FLAG (g->flags, GF_GAMEOVER);
1084 break;
1085 default:
1086 break;
1089 // FIXME RAV
1090 if (!g->validate && (g->pgn_fen_tag > 0 && !g->done_fen_tag) &&
1091 !pgn_history_total (g->hp) && srank >= 7)
1092 SET_FLAG (g->flags, GF_BLACK_OPENING);
1095 #ifdef DEBUG
1096 if (!g->validate && !g->check_testing)
1097 PGN_DUMP ("%s:%d: END finalizing\n", __FILE__, __LINE__);
1098 #endif
1100 if (!g->validate)
1102 p = pgn_piece_to_int (p);
1104 if (p == PAWN || promo || g->capture)
1105 g->ply = 0;
1106 else
1107 g->ply++;
1109 if (g->ply >= 50)
1111 if (g->tag[6]->value[0] == '*')
1113 pgn_tag_add (&g->tag, (char *) "Result", (char *) "1/2-1/2");
1114 SET_FLAG (g->flags, GF_GAMEOVER);
1119 return E_PGN_OK;
1122 static void
1123 black_opening (GAME g, BOARD b, int rank)
1125 if (!g->ravlevel && !g->hindex && pgn_tag_find (g->tag, "FEN") == -1)
1127 if (rank > 4)
1129 g->turn = BLACK;
1130 find_king_squares (g, b, &g->kfile, &g->krank, &g->okfile,
1131 &g->okrank);
1133 if (!g->validate)
1134 SET_FLAG (g->flags, GF_BLACK_OPENING);
1136 else
1138 g->turn = WHITE;
1140 if (!g->validate)
1141 CLEAR_FLAG (g->flags, GF_BLACK_OPENING);
1145 #ifdef DEBUG
1146 if (TEST_FLAG (g->flags, GF_BLACK_OPENING))
1147 PGN_DUMP ("%s:%d: black opening\n", __FILE__, __LINE__);
1148 #endif
1151 static char *
1152 format_santofrfr (int promo, int sfile, int srank, int file, int rank)
1154 char *frfr = malloc (6);
1156 memset (frfr, 0, 6);
1157 snprintf (frfr, 6, "%c%c%c%c", INTTOFILE (sfile),
1158 INTTORANK (srank), INTTOFILE (file), INTTORANK (rank));
1160 if (promo)
1161 frfr[4] = pgn_int_to_piece (BLACK, promo);
1163 return frfr;
1167 * Converts a2a3 formatted moves to SAN format. The promotion piece should be
1168 * appended (a7a8q).
1170 static int
1171 frfrtosan (GAME g, BOARD b, char **m, char **dst)
1173 char buf[MAX_SAN_MOVE_LEN + 1] = { 0 }, *bp = buf;
1174 int icon, p, dp, promo = 0;
1175 int sfile, srank, file, rank;
1176 int n;
1177 int fc, rc;
1178 int ff = 0, rr = 0;
1180 #ifdef DEBUG
1181 PGN_DUMP ("%s:%d: converting to SAN format\n", __FILE__, __LINE__);
1182 #endif
1184 strcpy (buf, *m);
1185 sfile = FILETOINT (bp[0]);
1186 srank = RANKTOINT (bp[1]);
1187 file = FILETOINT (bp[2]);
1188 rank = RANKTOINT (bp[3]);
1190 black_opening (g, b, rank);
1192 if (bp[4])
1194 if ((promo = pgn_piece_to_int (bp[4])) == -1 || promo == OPEN_SQUARE)
1195 return E_PGN_PARSE;
1196 #ifdef DEBUG
1197 PGN_DUMP ("%s:%d: promotion to %c\n", __FILE__, __LINE__,
1198 pgn_int_to_piece (g->turn, promo));
1199 #endif
1202 icon = b[RANKTOBOARD (srank)][FILETOBOARD (sfile)].icon;
1204 if ((p = pgn_piece_to_int (icon)) == -1 || p == OPEN_SQUARE)
1205 return E_PGN_PARSE;
1207 if (p != PAWN && promo)
1208 return E_PGN_INVALID;
1210 if (p == PAWN)
1212 if (find_source_square (g, b, p, &sfile, &srank, file, rank) != 1)
1213 return E_PGN_INVALID;
1215 goto capture;
1218 if (validate_piece (g, b, p, sfile, srank, file, rank) != E_PGN_OK)
1219 return E_PGN_INVALID;
1221 if (p == KING && abs (sfile - file) > 1)
1223 strcpy (buf, (file > FILETOINT ('e')) ? "O-O" : "O-O-O");
1225 if (finalize_move (g, b, promo, sfile, srank, file, rank) != E_PGN_OK)
1226 return E_PGN_INVALID;
1228 if (g->check)
1229 strcat (buf, (g->check == CHECK) ? "+" : "#");
1231 /* The move buffer size may be shorter than frfr format. Since
1232 * pgn_parse() uses a buffer allocated on the stack, this is not
1233 * needed because its' size is always MAX_SAN_MOVE_LEN+1.
1235 if (!parsing_file && strlen (*m) < strlen (buf))
1237 free (*m);
1238 *m = malloc (strlen (buf) + 1);
1239 strcpy (*m, buf);
1241 else
1242 strcpy (*m, buf);
1244 *dst = format_santofrfr (promo, sfile, srank, file, rank);
1245 return E_PGN_OK;
1248 bp = buf;
1249 *bp++ = toupper (icon);
1250 fc = rc = 0;
1251 n = find_source_square (g, b, p, &fc, &rc, file, rank);
1253 if (!n)
1254 return E_PGN_INVALID;
1255 else if (n > 1)
1257 fc = find_source_square (g, b, p, &sfile, &rr, file, rank);
1258 rc = find_source_square (g, b, p, &ff, &srank, file, rank);
1260 if (fc == 1)
1261 *bp++ = INTTOFILE (sfile);
1262 else if (!fc && rc)
1263 *bp++ = INTTORANK (srank);
1264 else if (fc && rc)
1266 if (rc == 1)
1267 *bp++ = INTTORANK (srank);
1268 else
1270 *bp++ = INTTOFILE (sfile);
1271 *bp++ = INTTORANK (srank);
1274 else
1275 return E_PGN_PARSE; // not reached.
1278 capture:
1279 icon = b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon;
1281 if ((dp = pgn_piece_to_int (icon)) == -1)
1282 return E_PGN_PARSE;
1285 * [Pf][fr]x
1287 if (dp != OPEN_SQUARE || (dp == OPEN_SQUARE && p == PAWN && sfile != file))
1289 if (p == PAWN)
1290 *bp++ = INTTOFILE (sfile);
1292 *bp++ = 'x';
1296 * [Pf][fr][x]fr
1299 *bp++ = INTTOFILE (file);
1300 *bp++ = INTTORANK (rank);
1302 if (p == PAWN && !promo && (rank == 8 || rank == 1))
1303 promo = pgn_piece_to_int ('q');
1306 * [Pf][fr][x]fr[=P]
1308 if (promo)
1310 if (p != PAWN || (g->turn == WHITE && (srank != 7 || rank != 8)) ||
1311 (g->turn == BLACK && (srank != 2 || rank != 1)))
1312 return E_PGN_INVALID;
1314 *bp++ = '=';
1315 *bp++ = pgn_int_to_piece (WHITE, promo);
1318 *bp = 0;
1320 if (find_source_square (g, b, p, &sfile, &srank, file, rank) != 1)
1321 return E_PGN_INVALID;
1323 if (finalize_move (g, b, promo, sfile, srank, file, rank) != E_PGN_OK)
1324 return E_PGN_INVALID;
1326 if (g->check)
1327 *bp++ = (g->check == CHECK) ? '+' : '#';
1329 *bp = 0;
1331 /* The move buffer size may be shorter than frfr format. Since
1332 * pgn_parse() uses a buffer allocated on the stack, this is not
1333 * needed because its' size is always MAX_SAN_MOVE_LEN+1.
1335 if (strlen (*m) < strlen (buf))
1337 free (*m);
1338 *m = malloc (strlen (buf) + 1);
1339 strcpy (*m, buf);
1341 else
1342 strcpy (*m, buf);
1344 g->check = 0;
1345 *dst = format_santofrfr (promo, sfile, srank, file, rank);
1346 #ifdef DEBUG
1347 PGN_DUMP ("%s:%d: END validating %s\n", __FILE__, __LINE__, *m);
1348 #endif
1349 return E_PGN_OK;
1352 static int
1353 do_santofrfr (GAME g, BOARD b, char **san, int *promo, int *sfile,
1354 int *srank, int *file, int *rank)
1356 char *p;
1357 int piece;
1358 int i = 0;
1359 char *m = *san;
1361 g->capture = 0;
1363 again:
1364 if (strlen (m) < 2)
1365 return E_PGN_PARSE;
1367 p = (m) + strlen (m);
1369 while (!isdigit (*--p) && *p != 'O')
1371 if (*p == '=')
1373 *promo = pgn_piece_to_int (i);
1374 i = 0;
1375 break;
1378 i = *p;
1379 *p = '\0';
1382 /* Alternate promotion text (e8Q). Convert to SAN. */
1383 if (i && pgn_piece_to_int (i) != E_PGN_ERR)
1385 p = (m) + strlen (m);
1386 *p++ = '=';
1387 *p++ = toupper (i);
1388 *p = '\0';
1389 goto again;
1392 p = m;
1394 /* Skip 'P' (pawn). */
1395 if (pgn_piece_to_int (*p) == PAWN)
1396 p++;
1398 /* Pawn. */
1399 if (VALIDCOL (*p))
1401 for (i = 0; *p; i++)
1403 if (VALIDCOL (*p))
1405 if (i > 0)
1406 *file = FILETOINT (*p++);
1407 else
1408 *file = *sfile = FILETOINT (*p++);
1410 else if (VALIDROW (*p))
1412 *rank = RANKTOINT (*p++);
1414 else if (*p == 'x')
1416 *file = FILETOINT (*++p);
1417 *rank = RANKTOINT (*++p);
1418 g->capture++;
1420 else if (*p == '=')
1422 if (*promo == -1 || *promo == KING || *promo == PAWN)
1423 return E_PGN_PARSE;
1425 *p++ = '=';
1426 *p++ = toupper (pgn_int_to_piece (g->turn, *promo));
1427 *p = '\0';
1428 break;
1430 else
1432 #ifdef DEBUG
1433 PGN_DUMP ("Pawn (move: '%s'): %c\n", m, *p++);
1434 #else
1435 p++;
1436 #endif
1440 black_opening (g, b, *rank);
1442 if (find_source_square (g, b, PAWN, sfile, srank, *file, *rank) != 1)
1443 return E_PGN_INVALID;
1445 if (!*promo && (*rank == 8 || *rank == 1))
1447 *promo = pgn_piece_to_int ('q');
1448 *p++ = '=';
1449 *p++ = pgn_int_to_piece (WHITE, *promo);
1450 *p = 0;
1453 /* Not a pawn. */
1454 else
1456 p = m;
1459 * P[fr][x]fr
1461 * The first character is the piece but only if not a pawn.
1463 if ((piece = pgn_piece_to_int (*p++)) == -1)
1464 return E_PGN_PARSE;
1467 * [fr]fr
1469 if (strlen (m) > 3)
1472 * rfr
1474 if (isdigit (*p))
1475 *srank = RANKTOINT (*p++);
1477 * f[r]fr
1479 else if (VALIDCOL (*p))
1481 *sfile = FILETOINT (*p++);
1484 * frfr
1486 if (isdigit (*p))
1487 *srank = RANKTOINT (*p++);
1491 * xfr
1493 if (*p == 'x')
1495 g->capture++;
1496 p++;
1501 * fr
1503 * The destination square.
1505 *file = FILETOINT (*p++);
1506 *rank = RANKTOINT (*p++);
1508 if (*p == '=')
1509 *promo = *++p;
1511 black_opening (g, b, *rank);
1513 if ((i = find_source_square (g, b, piece, sfile, srank, *file, *rank))
1514 != 1 && !g->check)
1515 return (i == 0) ? E_PGN_INVALID : E_PGN_AMBIGUOUS;
1517 #if 0
1519 * The move is a valid one. Find the source file and rank so we
1520 * can later update the board positions.
1522 if (find_source_square (*g, b, piece, sfile, srank, *file, *rank)
1523 != 1 && !check)
1524 return E_PGN_INVALID;
1525 #endif
1528 *p = 0;
1529 *san = m;
1530 return E_PGN_OK;
1534 * Valididate move 'mp' against the game state 'g' and game board 'b' and
1535 * update board 'b'. 'mp' is updated to SAN format for moves which aren't
1536 * (frfr or e8Q for example). Returns E_PGN_PARSE if there was a move text
1537 * parsing error, E_PGN_INVALID if the move is invalid or E_PGN_OK if
1538 * successful.
1540 pgn_error_t
1541 pgn_parse_move (GAME g, BOARD b, char **mp, char **dst)
1543 int srank = 0, sfile = 0, rank, file;
1544 char *m = *mp, *p;
1545 int i;
1546 int promo = -1;
1547 size_t len = m ? strlen (m) : 0;
1550 * This may be an empty move with only an annotation. Kinda strange.
1552 if (!m || !*m)
1553 return E_PGN_OK;
1555 #ifdef DEBUG
1556 PGN_DUMP ("%s:%d: BEGIN validating '%s' (%s)...\n", __FILE__, __LINE__, m,
1557 (g->turn == WHITE) ? "white" : "black");
1558 #endif
1560 g->check_testing = g->castle = 0;
1561 srank = rank = file = sfile = promo = 0;
1562 find_king_squares (g, b, &g->kfile, &g->krank, &g->okfile, &g->okrank);
1564 if (m[len - 1] == '+')
1565 m[--len] = 0;
1567 if (VALIDCOL (*m) && VALIDROW (*(m + 1)) && VALIDCOL (*(m + 2))
1568 && VALIDROW (*(m + 3)))
1569 return frfrtosan (g, b, mp, dst);
1570 else if (*m == 'O')
1572 if (strcmp (m, "O-O") == 0)
1573 i = KINGSIDE;
1574 else if (strcmp (m, "O-O-O") == 0)
1575 i = QUEENSIDE;
1576 else
1577 return E_PGN_PARSE;
1579 if (parse_castle_move (g, b, i, &sfile, &srank, &file, &rank) !=
1580 E_PGN_OK)
1581 return E_PGN_INVALID;
1583 /* The move buffer size may be shorter than frfr format. Since
1584 * pgn_parse() uses a buffer allocated on the stack, this is not
1585 * needed because its' size is always MAX_SAN_MOVE_LEN+1.
1587 if (len < 4 && !parsing_file)
1589 m = malloc (5 * sizeof (char));
1590 free (*mp);
1591 *mp = m;
1594 m = *mp;
1595 *m++ = INTTOFILE (sfile);
1596 *m++ = INTTORANK (srank);
1597 *m++ = INTTOFILE (file);
1598 *m++ = INTTORANK (rank);
1599 *m = 0;
1600 return frfrtosan (g, b, mp, dst);
1603 if ((i = do_santofrfr (g, b, &m, &promo, &sfile, &srank, &file, &rank))
1604 != E_PGN_OK)
1605 return i;
1607 p = m + strlen (m);
1609 if (finalize_move (g, b, promo, sfile, srank, file, rank) != E_PGN_OK)
1610 return E_PGN_INVALID;
1612 if (g->check)
1613 *p++ = (g->check == CHECK) ? '+' : '#';
1615 *p = g->check = 0;
1616 *dst = format_santofrfr (promo, sfile, srank, file, rank);
1618 #ifdef DEBUG
1619 PGN_DUMP ("%s:%d: END validating %s\n", __FILE__, __LINE__, m);
1620 #endif
1621 return E_PGN_OK;
1625 * Like pgn_parse_move() but don't modify game flags in 'g' or board 'b'.
1627 pgn_error_t
1628 pgn_validate_move (GAME g, BOARD b, char **m, char **dst)
1630 int ret;
1631 int side = g->side, turn = g->turn;
1632 unsigned short flags = g->flags;
1634 #ifdef DEBUG
1635 PGN_DUMP ("%s:%d: BEGIN validate only\n", __FILE__, __LINE__);
1636 #endif
1637 g->validate = 1;
1638 ret = pgn_parse_move (g, b, m, dst);
1639 g->validate = 0;
1640 #ifdef DEBUG
1641 PGN_DUMP ("%s:%d: END validate only\n", __FILE__, __LINE__);
1642 #endif
1643 g->side = side;
1644 g->turn = turn;
1645 g->flags = flags;
1646 return ret;
1650 * Sets valid moves from game 'g' using board 'b'. The valid moves are for the
1651 * piece on the board 'b' at 'rank' and 'file'. Returns nothing.
1653 void
1654 pgn_find_valid_moves (GAME g, BOARD b, int file, int rank)
1656 int p = pgn_piece_to_int (b[RANKTOBOARD (rank)][FILETOBOARD (file)].icon);
1657 int r, f;
1659 #ifdef DEBUG
1660 PGN_DUMP ("%s:%d: BEGIN valid destination squares for %c%c\n", __FILE__,
1661 __LINE__, INTTOFILE (file), INTTORANK (rank));
1662 #endif
1664 g->validate_find = 1;
1665 find_king_squares (g, b, &g->kfile, &g->krank, &g->okfile, &g->okrank);
1667 for (r = 1; VALIDRANK (r); r++)
1669 for (f = 1; VALIDFILE (f); f++)
1671 if (val_piece_side
1672 (g->turn, b[RANKTOBOARD (r)][FILETOBOARD (f)].icon))
1673 continue;
1675 if (find_source_square (g, b, p, &file, &rank, f, r) != 0)
1677 b[RANKTOBOARD (r)][FILETOBOARD (f)].valid = 1;
1678 #ifdef DEBUG
1679 PGN_DUMP ("%s:%d: %c%c is valid\n", __FILE__, __LINE__,
1680 INTTOFILE (f), INTTORANK (r));
1681 #endif
1686 #ifdef DEBUG
1687 PGN_DUMP ("%s:%d: END valid destination squares for %c%c\n", __FILE__,
1688 __LINE__, INTTOFILE (file), INTTORANK (rank));
1689 #endif
1690 g->check_testing = 0;
1691 g->validate_find = 0;