2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 // [HGM] some explanation of the parser code:
24 // The routine parse_move() calls is_move() to recognize some simple cases,
25 // like OO-castle and long algebraic with or without dash. What does not fall
26 // in this class is handed to alg_is_move(), whch is really a continuation
27 // of is_move(), to recognize SAN.
28 // Depending on the type of move syntax, parse_move can extract from- and to-square
29 // immediately, or transate the OO-castling to internal from-to representation.
30 // Only for SAN syntax the routine alg_pars_move() is called to extract the
31 // given elements, (through get_move_info(), which is the same as alg_is_move(),
32 // xcept that it does not discard the value of the elements), and disambiguate
33 // the move (i.e. determines the from-square) by looking for a piece of the given
34 // type on the board for which the move is pseudo-legal (using legal_move() ).
37 /* Simply tests if the input string is a move or not. */
38 /* If it matches patterns below */
39 /* Add to this list as you improve the move parser */
41 /* MS_COMPDASH e2-e4 */
42 /* MS_CASTLE o-o, o-o-o */
44 /* MS_ALG e4, Nd5 Ncd5 */
45 int is_move(const char *mstr)
47 int len = strlen(mstr);
48 if ((len > 3) && (mstr[len - 2] == '='))
51 /* remove the 'mates' marker */
52 if (mstr[len - 1] == '#')
55 if (len == 4) { /* Test for e2e4 */
56 if (isfile(mstr[0]) && isrank(mstr[1]) &&
57 isfile(mstr[2]) && isrank(mstr[3])) {
61 if (len == 5) { /* Test for e2-e4 */
62 if (isfile(mstr[0]) && isrank(mstr[1]) &&
64 isfile(mstr[3]) && isrank(mstr[4])) {
68 if (len == 3) { /* Test for o-o */
69 if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o')) {
72 if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O')) {
75 if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0')) {
79 if (len == 2) { /* Test for oo */
80 if ((mstr[0] == 'o') && (mstr[1] == 'o')) {
83 if ((mstr[0] == 'O') && (mstr[1] == 'O')) {
86 if ((mstr[0] == '0') && (mstr[1] == '0')) {
90 if (len == 5) { /* Test for o-o-o */
91 if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o') && (mstr[3] == '-') && (mstr[4] == 'o')) {
94 if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O') && (mstr[3] == '-') && (mstr[4] == 'O')) {
97 if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0') && (mstr[3] == '-') && (mstr[4] == '0')) {
101 if (len == 3) { /* Test for ooo */
102 if ((mstr[0] == 'o') && (mstr[1] == 'o') && (mstr[2] == 'o')) {
105 if ((mstr[0] == 'O') && (mstr[1] == 'O') && (mstr[2] == 'O')) {
108 if ((mstr[0] == '0') && (mstr[1] == '0') && (mstr[2] == '0')) {
112 return alg_is_move(mstr);
116 int NextPieceLoop(board_t b, int *f, int *r, int color, int w, int h)
126 if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color))
132 int InitPieceLoop(board_t b, int *f, int *r, int color)
139 /* All of the routines assume that the obvious problems have been checked */
140 /* See legal_move() */
141 static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr )
144 if (gs->board[tf][tr] != NOPIECE && !gs->palace && gs->promoType != 3) return 0; // [HGM] XQ and Shogi pawns can capture straight ahead
\r
145 if (gs->onMove == WHITE) {
\r
146 if (tr - fr == 1) return 1;
\r
147 if ((fr <= gs->pawnDblStep) && (tr - fr == 2) && gs->board[ff][fr+1]==NOPIECE) return 1;
149 if (fr - tr == 1) return 1;
\r
150 if ((fr >= gs->ranks - 1 - gs->pawnDblStep) && (fr - tr == 2) && gs->board[ff][fr-1]==NOPIECE) return 1;
\r
154 if (ff != tf && gs->promoType != 3) { /* Capture ? ([HGM] but not in Shogi) */
155 if ((ff - tf != 1) && (tf - ff != 1)) return 0;
156 if (gs->onMove == WHITE) {
157 if(gs->palace) return (fr >= gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns
\r
158 if (tr != fr+1) return 0;
159 if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK))
161 if (gs->ep_possible[0][ff] == 1) {
162 if ((tf==ff+1) && (gs->board[ff+1][fr] == B_PAWN)) return 1;
163 } else if (gs->ep_possible[0][ff] == -1) {
164 if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1;
167 if(gs->palace) return (fr < gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns
\r
168 if (tr != fr-1) return 0;
169 if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE))
171 if (gs->ep_possible[1][ff] == 1) {
172 if ((tf==ff+1) && (gs->board[ff+1][fr] == W_PAWN)) return 1;
173 } else if (gs->ep_possible[1][ff] == -1) {
174 if ((tf==ff-1) && (gs->board[ff-1][fr] == W_PAWN)) return 1;
181 static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
198 static int legal_horse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
205 if (abs(dy) == 1 && gs->board[(ff+tf)/2][fr] == NOPIECE)
209 if (abs(dx) == 1 && gs->board[ff][(fr+tr)/2] == NOPIECE)
215 static int legal_honorablehorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
221 if (dy == (gs->onMove == WHITE ? -2 : 2)) {
228 static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
252 return 0; /* Not diagonal */
254 return 1; /* One square, ok */
256 for (x = startx, y = starty; count; x += incx, y += incy, count--) {
257 if (gs->board[x][y] != NOPIECE)
263 static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
269 if (abs(fr - tr) == 1)
278 for (i = start; i <= stop; i++) {
279 if (gs->board[ff][i] != NOPIECE)
283 } else if (fr == tr) {
284 if (abs(ff - tf) == 1)
293 for (i = start; i <= stop; i++) {
294 if (gs->board[i][fr] != NOPIECE)
303 static int legal_cannon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
316 for (i = start; i <= stop; i++) {
317 if (gs->board[ff][i] != NOPIECE) cnt++;
319 return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
320 (cnt == 1 && gs->board[tf][tr] != NOPIECE);
321 } else if (fr == tr) {
329 for (i = start; i <= stop; i++) {
330 if (gs->board[i][fr] != NOPIECE) cnt++;
332 return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
333 (cnt == 1 && gs->board[tf][tr] != NOPIECE);
339 static int legal_lance_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
345 if (abs(fr - tr) == 1)
348 if(gs->onMove != WHITE) return 0;
352 if(gs->onMove == WHITE) return 0;
356 for (i = start; i <= stop; i++) {
357 if (gs->board[ff][i] != NOPIECE)
364 static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
366 return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
369 static int legal_cardinal_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
371 return legal_knight_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
\r
374 static int legal_marshall_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
376 return legal_rook_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);
\r
379 /* Ckeck, if square (kf,kr) is attacked by enemy piece.
380 * Used in castling from/through check testing.
383 /* new one from soso: */
384 static int is_square_attacked (struct game_state_t *gs, int kf, int kr)
386 struct game_state_t fakeMove;
387 int oldk = gs->onMove == WHITE ? gs->wkmoved : gs->bkmoved;
390 fakeMove.board[oldk][kr] = NOPIECE; // [HGM] castle: this routine is called only when King has not moved
\r
391 fakeMove.board[kf][kr] = KING | fakeMove.onMove;
392 fakeMove.onMove = CToggle (fakeMove.onMove);
393 if (in_check(&fakeMove)) return 1;
398 static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
401 gs->onMove = CToggle(gs->onMove);
403 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
404 NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
405 if (legal_move(gs, f, r, kf, kr)) {
406 gs->onMove = CToggle(gs->onMove);
410 gs->onMove = CToggle(gs->onMove);
415 static int legal_man_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
417 if (abs(ff - tf) > 1)
\r
419 if (abs(fr - tr) > 1)
\r
424 static int legal_wazir_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
426 if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
427 tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
429 if (abs(ff - tf) == 1 && fr == tr)
\r
431 if (abs(fr - tr) == 1 && ff == tf)
\r
436 static int legal_dababba_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
438 if (abs(ff - tf) == 2 && fr == tr)
\r
440 if (abs(fr - tr) == 2 && ff == tf)
\r
445 static int legal_ferz_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
447 if (abs(ff - tf) != 1)
\r
449 if (abs(fr - tr) != 1)
\r
454 static int legal_mandarin_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
456 if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
457 tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
459 if (abs(ff - tf) != 1)
\r
461 if (abs(fr - tr) != 1)
\r
466 static int legal_alfil_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
468 if (abs(ff - tf) != 2)
\r
470 if (abs(fr - tr) != 2)
\r
475 static int legal_elephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
477 if (abs(ff - tf) != 2)
\r
479 if (abs(fr - tr) != 2)
\r
481 if(gs->board[(ff+tf)/2][(fr+tr)/2] != NOPIECE) return 0; // blocked
482 if((tr >= gs->ranks/2) != (fr >= gs->ranks/2)) return 0; // do not cross river
\r
486 static int legal_gold_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
488 return legal_wazir_move(gs, ff, fr, tf, tr) || (abs(ff-tf) == 1 && tr == fr + (gs->onMove==WHITE ? 1 : -1));
\r
491 static int legal_silver_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
493 return legal_ferz_move(gs, ff, fr, tf, tr) || (tf == ff && tr == fr + (gs->onMove==WHITE ? 1 : -1) );
\r
496 static int legal_woody_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
498 return legal_wazir_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr);
\r
501 static int legal_squirrel_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
503 return legal_alfil_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr)
504 || legal_knight_move(gs, ff, fr, tf, tr);
\r
507 static int legal_mastodon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
509 return legal_man_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr)
510 || legal_dababba_move(gs, ff, fr, tf, tr);
\r
513 static int legal_centaur_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
515 return legal_man_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);
\r
518 static int legal_amazon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
520 return legal_queen_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);
\r
523 static int legal_dragonking_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
525 return legal_rook_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr);
\r
528 static int legal_dragonhorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
530 return legal_bishop_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr);
\r
533 static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
535 return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr);
\r
538 static int legal_priestess_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
540 return legal_knight_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr)
541 || legal_alfil_move(gs, ff, fr, tf, tr);
\r
544 static int legal_minister_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
\r
546 return legal_knight_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr)
547 || legal_dababba_move(gs, ff, fr, tf, tr);
\r
550 static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
554 // [HGM] castle: test first if valid as regular King move; result = 1 or 0
555 if(gs->royalKnight)
\r
556 result = legal_knight_move(gs, ff, fr, tf, tr);
\r
557 else if(gs->palace) {
558 result = legal_wazir_move(gs, ff, fr, tf, tr);
559 if(!result && ff == tf && piecetype(gs->board[tf][tr]) == KING) { // XQ regicide
560 int i, d = (tr>fr ? 1 : -1);
561 for(i=fr+d; i!=tr; i+=d)
562 if(gs->board[ff][i] != NOPIECE) return 0; // line of sight blocked
566 result = legal_man_move(gs, ff, fr, tf, tr);
568 if(result) return 1;
\r
569 // [HGM] castle: orthodox legal castlings given as King move return 2
571 if (gs->onMove == WHITE) {
\r
572 /* King side castling */
\r
573 if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->wkmoved >= 0)
\r
574 && (gs->wkrmoved >= 0) && (gs->board[gs->files-3][0] == NOPIECE) &&
\r
575 (gs->board[gs->files-2][0] == NOPIECE) && (gs->board[gs->files-1][0] == W_ROOK) &&
\r
576 (gs->board[gs->files/2+1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, 0)) &&
\r
577 (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, gs->files-3, 0))) {
\r
580 /* Queen side castling */
\r
581 if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == 2) && (gs->wkmoved >= 0)
\r
582 && (gs->wqrmoved >= 0) && (gs->board[3][0] == NOPIECE) &&
\r
583 (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&
\r
584 (gs->board[0][0] == W_ROOK) &&
\r
585 (gs->board[gs->files/2-1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, 0)) &&
\r
586 (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, 3, 0))) {
\r
589 } else { /* Black */
\r
590 /* King side castling */
\r
591 if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->bkmoved >= 0)
\r
592 && (gs->bkrmoved >= 0) && (gs->board[gs->files-3][7] == NOPIECE) &&
\r
593 (gs->board[gs->files-2][gs->ranks-1] == NOPIECE) && (gs->board[gs->files-1][gs->ranks-1] == B_ROOK) &&
\r
594 (gs->board[gs->files/2+1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, gs->ranks-1)) &&
\r
595 (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, gs->files-3, gs->ranks-1))) {
\r
598 /* Queen side castling */
\r
599 if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == 2) && (gs->bkmoved >= 0)
\r
600 && (gs->bqrmoved >= 0) && (gs->board[3][gs->ranks-1] == NOPIECE) &&
\r
601 (gs->board[2][gs->ranks-1] == NOPIECE) && (gs->board[1][gs->ranks-1] == NOPIECE) &&
\r
602 (gs->board[0][gs->ranks-1] == B_ROOK) &&
\r
603 (gs->board[gs->files/2-1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, gs->ranks-1)) &&
\r
604 (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, 3, gs->ranks-1))) {
\r
609 return 0; // neither regular King move nor castling
612 static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos)
619 static void possible_pawn_moves(struct game_state_t * gs,
621 int *posf, int *posr, int *numpos)
623 if (gs->onMove == WHITE) {
\r
624 if (gs->board[onf][onr + 1] == NOPIECE || gs->palace || gs->promoType == 3) {
\r
625 add_pos(onf, onr + 1, posf, posr, numpos);
\r
626 if ((onr <= gs->pawnDblStep) && (gs->board[onf][onr + 2] == NOPIECE))
\r
627 add_pos(onf, onr + 2, posf, posr, numpos);
\r
630 if (gs->board[onf - 1][onr + 1] != NOPIECE &&
\r
631 iscolor(gs->board[onf - 1][onr + 1], BLACK) &&
632 !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi
\r
633 add_pos(onf - 1, onr + 1, posf, posr, numpos);
634 if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf-1][onr] || iscolor(gs->board[onf-1][onr], BLACK)))
635 add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
637 if (onf < gs->files-1) {
638 if (gs->board[onf + 1][onr + 1] != NOPIECE &&
\r
639 iscolor(gs->board[onf + 1][onr + 1], BLACK) &&
640 !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi
\r
641 add_pos(onf + 1, onr + 1, posf, posr, numpos);
642 if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf+1][onr] || iscolor(gs->board[onf+1][onr], BLACK)))
643 add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
645 if (gs->ep_possible[0][onf] == -1)
\r
646 add_pos(onf - 1, onr + 1, posf, posr, numpos);
\r
647 if (gs->ep_possible[0][onf] == 1)
\r
648 add_pos(onf + 1, onr + 1, posf, posr, numpos);
650 if (gs->board[onf][onr - 1] == NOPIECE || gs->palace || gs->promoType == 3) {
\r
651 add_pos(onf, onr - 1, posf, posr, numpos);
\r
652 if ((onr >= gs->ranks - gs->pawnDblStep - 1) && (gs->board[onf][onr - 2] == NOPIECE))
\r
653 add_pos(onf, onr - 2, posf, posr, numpos);
\r
656 if (gs->board[onf - 1][onr - 1] != NOPIECE &&
\r
657 iscolor(gs->board[onf - 1][onr - 1], WHITE) &&
\r
658 !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi
\r
659 add_pos(onf - 1, onr - 1, posf, posr, numpos);
660 if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf-1][onr], BLACK))
661 add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
663 if (onf < gs->files-1) {
664 if (gs->board[onf + 1][onr - 1] != NOPIECE &&
\r
665 iscolor(gs->board[onf + 1][onr - 1], WHITE) &&
\r
666 !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi
\r
667 add_pos(onf + 1, onr - 1, posf, posr, numpos);
668 if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf+1][onr], BLACK))
669 add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
671 if (gs->ep_possible[1][onf] == -1)
\r
672 add_pos(onf - 1, onr - 1, posf, posr, numpos);
\r
673 if (gs->ep_possible[1][onf] == 1)
\r
674 add_pos(onf + 1, onr - 1, posf, posr, numpos);
\r
678 static void possible_knight_moves(struct game_state_t * gs,
680 int *posf, int *posr, int *numpos)
682 static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},
\r
683 {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};
\r
687 for (j = 0; j < 8; j++) {
\r
688 f = knightJumps[j][0] + onf;
\r
689 r = knightJumps[j][1] + onr;
\r
690 if ((f < 0) || (f >= gs->files))
\r
692 if ((r < 0) || (r >= gs->ranks))
\r
694 if ((gs->board[f][r] == NOPIECE) ||
\r
695 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
696 add_pos(f, r, posf, posr, numpos);
\r
700 static void possible_horse_moves(struct game_state_t * gs,
702 int *posf, int *posr, int *numpos)
704 static int knightJumps[8][4] = {{-1, 2, 0, 1}, {1, 2, 0, 1}, {2, -1, 1, 0}, {2, 1, 1, 0},
\r
705 {-1, -2, 0, -1}, {1, -2, 0, -1}, {-2, 1, -1, 0}, {-2, -1, -1, 0}};
\r
709 for (j = 0; j < 8; j++) {
\r
710 f = knightJumps[j][0] + onf;
\r
711 r = knightJumps[j][1] + onr;
\r
712 if ((f < 0) || (f >= gs->files))
\r
714 if ((r < 0) || (r >= gs->ranks))
\r
716 if ((gs->board[knightJumps[j][2] + onf][knightJumps[j][3] + onr] == NOPIECE) &&
717 ((gs->board[f][r] == NOPIECE) || (iscolor(gs->board[f][r], CToggle(gs->onMove)))))
\r
718 add_pos(f, r, posf, posr, numpos);
\r
722 static void possible_bishop_moves(struct game_state_t * gs,
724 int *posf, int *posr, int *numpos)
734 if ((f < 0) || (f >= gs->files))
\r
736 if ((r < 0) || (r >= gs->ranks))
\r
738 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
740 add_pos(f, r, posf, posr, numpos);
\r
741 if (gs->board[f][r] != NOPIECE)
\r
750 if ((f < 0) || (f >= gs->files))
\r
752 if ((r < 0) || (r >= gs->ranks))
\r
754 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
756 add_pos(f, r, posf, posr, numpos);
\r
757 if (gs->board[f][r] != NOPIECE)
\r
766 if ((f < 0) || (f >= gs->files))
\r
768 if ((r < 0) || (r >= gs->ranks))
\r
770 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
772 add_pos(f, r, posf, posr, numpos);
\r
773 if (gs->board[f][r] != NOPIECE)
\r
782 if ((f < 0) || (f >= gs->files))
\r
784 if ((r < 0) || (r >= gs->ranks))
\r
786 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
788 add_pos(f, r, posf, posr, numpos);
\r
789 if (gs->board[f][r] != NOPIECE)
\r
794 static void possible_rook_moves(struct game_state_t * gs,
796 int *posf, int *posr, int *numpos)
805 if ((f < 0) || (f >= gs->files))
\r
807 if ((r < 0) || (r >= gs->ranks))
\r
809 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
811 add_pos(f, r, posf, posr, numpos);
\r
812 if (gs->board[f][r] != NOPIECE)
\r
820 if ((f < 0) || (f >= gs->files))
\r
822 if ((r < 0) || (r >= gs->ranks))
\r
824 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
826 add_pos(f, r, posf, posr, numpos);
\r
827 if (gs->board[f][r] != NOPIECE)
\r
835 if ((f < 0) || (f >= gs->files))
\r
837 if ((r < 0) || (r >= gs->ranks))
\r
839 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
841 add_pos(f, r, posf, posr, numpos);
\r
842 if (gs->board[f][r] != NOPIECE)
\r
850 if ((f < 0) || (f >= gs->files))
\r
852 if ((r < 0) || (r >= gs->ranks))
\r
854 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
856 add_pos(f, r, posf, posr, numpos);
\r
857 if (gs->board[f][r] != NOPIECE)
\r
862 static void possible_cannon_moves(struct game_state_t * gs,
864 int *posf, int *posr, int *numpos)
873 if ((f < 0) || (f >= gs->files))
\r
875 if ((r < 0) || (r >= gs->ranks))
\r
877 if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
879 add_pos(f, r, posf, posr, numpos); // no hop: non-capt
880 else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove))
881 add_pos(f, r, posf, posr, numpos); // hop: capt
\r
882 if (gs->board[f][r] != NOPIECE)
\r
890 if ((f < 0) || (f >= gs->files))
\r
892 if ((r < 0) || (r >= gs->ranks))
\r
894 if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
896 add_pos(f, r, posf, posr, numpos); // no hop: non-capt
897 else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove))
898 add_pos(f, r, posf, posr, numpos); // hop: capt
\r
899 if (gs->board[f][r] != NOPIECE)
\r
907 if ((f < 0) || (f >= gs->files))
\r
909 if ((r < 0) || (r >= gs->ranks))
\r
911 if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
913 add_pos(f, r, posf, posr, numpos); // no hop: non-capt
914 else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove))
915 add_pos(f, r, posf, posr, numpos); // hop: capt
\r
916 if (gs->board[f][r] != NOPIECE)
\r
924 if ((f < 0) || (f >= gs->files))
\r
926 if ((r < 0) || (r >= gs->ranks))
\r
928 if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
930 add_pos(f, r, posf, posr, numpos); // no hop: non-capt
931 else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove))
932 add_pos(f, r, posf, posr, numpos); // hop: capt
\r
933 if (gs->board[f][r] != NOPIECE)
\r
938 static void possible_lance_moves(struct game_state_t * gs,
940 int *posf, int *posr, int *numpos)
947 for (;gs->onMove == WHITE;) {
\r
949 if ((f < 0) || (f >= gs->files))
\r
951 if ((r < 0) || (r >= gs->ranks))
\r
953 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
955 add_pos(f, r, posf, posr, numpos);
\r
956 if (gs->board[f][r] != NOPIECE)
\r
962 for (;gs->onMove == BLACK;) {
\r
964 if ((f < 0) || (f >= gs->files))
\r
966 if ((r < 0) || (r >= gs->ranks))
\r
968 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
\r
970 add_pos(f, r, posf, posr, numpos);
\r
971 if (gs->board[f][r] != NOPIECE)
\r
976 static void possible_cardinal_moves(struct game_state_t * gs,
\r
978 int *posf, int *posr, int *numpos)
\r
980 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
\r
981 possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
\r
984 static void possible_marshall_moves(struct game_state_t * gs,
\r
986 int *posf, int *posr, int *numpos)
\r
988 possible_rook_moves(gs, onf, onr, posf, posr, numpos);
\r
989 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
\r
992 static void possible_queen_moves(struct game_state_t * gs,
994 int *posf, int *posr, int *numpos)
996 possible_rook_moves(gs, onf, onr, posf, posr, numpos);
997 possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
1000 static void possible_alfil_moves(struct game_state_t * gs,
\r
1002 int *posf, int *posr, int *numpos)
\r
1004 static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
\r
1008 for (j = 0; j < 4; j++) {
\r
1009 f = 2*kingJumps[j][0] + onf;
\r
1010 r = 2*kingJumps[j][1] + onr;
\r
1011 if ((f < 0) || (f >= gs->files))
\r
1013 if ((r < 0) || (r >= gs->ranks))
\r
1015 if ((gs->board[f][r] == NOPIECE) ||
\r
1016 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
1017 add_pos(f, r, posf, posr, numpos);
\r
1021 static void possible_ferz_moves(struct game_state_t * gs,
\r
1023 int *posf, int *posr, int *numpos)
\r
1025 static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
\r
1029 for (j = 0; j < 4; j++) {
\r
1030 f = kingJumps[j][0] + onf;
\r
1031 r = kingJumps[j][1] + onr;
\r
1032 if ((f < 0) || (f >= gs->files))
\r
1034 if ((r < 0) || (r >= gs->ranks))
\r
1036 if ((gs->board[f][r] == NOPIECE) ||
\r
1037 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
1038 add_pos(f, r, posf, posr, numpos);
\r
1042 static void possible_mandarin_moves(struct game_state_t * gs,
\r
1044 int *posf, int *posr, int *numpos)
\r
1046 static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
\r
1050 for (j = 0; j < 4; j++) {
\r
1051 f = kingJumps[j][0] + onf;
\r
1052 r = kingJumps[j][1] + onr;
\r
1053 if ((f < 0) || (f >= gs->files))
\r
1055 if ((r < 0) || (r >= gs->ranks))
\r
1057 if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1058 f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1060 if ((gs->board[f][r] == NOPIECE) ||
\r
1061 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
1062 add_pos(f, r, posf, posr, numpos);
\r
1066 static void possible_wazir_moves(struct game_state_t * gs,
\r
1068 int *posf, int *posr, int *numpos)
\r
1070 static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
\r
1074 for (j = 0; j < 4; j++) {
\r
1075 f = kingJumps[j][0] + onf;
\r
1076 r = kingJumps[j][1] + onr;
\r
1077 if ((f < 0) || (f >= gs->files))
\r
1079 if ((r < 0) || (r >= gs->ranks))
\r
1081 if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1082 f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1084 if ((gs->board[f][r] == NOPIECE) ||
\r
1085 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
1086 add_pos(f, r, posf, posr, numpos);
\r
1090 static void possible_dababba_moves(struct game_state_t * gs,
\r
1092 int *posf, int *posr, int *numpos)
\r
1094 static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
\r
1098 for (j = 0; j < 4; j++) {
\r
1099 f = 2*kingJumps[j][0] + onf;
\r
1100 r = 2*kingJumps[j][1] + onr;
\r
1101 if ((f < 0) || (f >= gs->files))
\r
1103 if ((r < 0) || (r >= gs->ranks))
\r
1105 if ((gs->board[f][r] == NOPIECE) ||
\r
1106 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
\r
1107 add_pos(f, r, posf, posr, numpos);
\r
1111 static void possible_man_moves(struct game_state_t * gs,
\r
1113 int *posf, int *posr, int *numpos)
1115 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1116 possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1119 static void possible_dragonking_moves(struct game_state_t * gs,
\r
1121 int *posf, int *posr, int *numpos)
1123 possible_rook_moves(gs, onf, onr, posf, posr, numpos);
1124 possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1127 static void possible_dragonhorse_moves(struct game_state_t * gs,
\r
1129 int *posf, int *posr, int *numpos)
1131 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1132 possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
1135 static void possible_centaur_moves(struct game_state_t * gs,
\r
1137 int *posf, int *posr, int *numpos)
1139 possible_man_moves(gs, onf, onr, posf, posr, numpos);
1140 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1143 static void possible_woody_moves(struct game_state_t * gs,
\r
1145 int *posf, int *posr, int *numpos)
1147 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1148 possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1151 static void possible_squirrel_moves(struct game_state_t * gs,
\r
1153 int *posf, int *posr, int *numpos)
1155 possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1156 possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1157 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1160 static void possible_mastodon_moves(struct game_state_t * gs,
\r
1162 int *posf, int *posr, int *numpos)
1164 possible_man_moves(gs, onf, onr, posf, posr, numpos);
1165 possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1166 possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1169 static void possible_amazon_moves(struct game_state_t * gs,
\r
1171 int *posf, int *posr, int *numpos)
1173 possible_queen_moves(gs, onf, onr, posf, posr, numpos);
1174 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1177 static void possible_modernelephant_moves(struct game_state_t * gs,
\r
1179 int *posf, int *posr, int *numpos)
1181 possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1182 possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1185 static void possible_priestess_moves(struct game_state_t * gs,
\r
1187 int *posf, int *posr, int *numpos)
1189 possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1190 possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1191 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1194 static void possible_minister_moves(struct game_state_t * gs,
\r
1196 int *posf, int *posr, int *numpos)
1198 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1199 possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1200 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1203 static void possible_gold_moves(struct game_state_t * gs,
\r
1205 int *posf, int *posr, int *numpos)
1207 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1208 if(gs->onMove == WHITE) {
1209 if(onr < gs->ranks-1)
1210 if(onf > 0 && !iscolor(gs->board[onf-1][onr+1], WHITE))
1211 add_pos(onf-1, onr+1, posf, posr, numpos);
\r
1212 if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr+1], WHITE))
1213 add_pos(onf+1, onr+1, posf, posr, numpos);
\r
1216 if(onf > 0 && !iscolor(gs->board[onf-1][onr-1], BLACK))
1217 add_pos(onf-1, onr-1, posf, posr, numpos);
\r
1218 if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr-1], BLACK))
1219 add_pos(onf+1, onr-1, posf, posr, numpos);
\r
1223 static void possible_silver_moves(struct game_state_t * gs,
\r
1225 int *posf, int *posr, int *numpos)
1227 possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1228 if(gs->onMove == WHITE) {
1229 if(onr < gs->ranks-1 && !iscolor(gs->board[onf][onr+1], WHITE))
1230 add_pos(onf, onr+1, posf, posr, numpos);
\r
1232 if(onr > 0 && !iscolor(gs->board[onf][onr-1], BLACK))
1233 add_pos(onf, onr-1, posf, posr, numpos);
\r
1237 static void possible_honorablehorse_moves(struct game_state_t * gs,
\r
1239 int *posf, int *posr, int *numpos)
\r
1241 int f, r = onr + (gs->onMove == WHITE ? 2 : -2);
\r
1243 if(r < 0 || r >= gs->ranks) return;
\r
1245 if ((gs->board[onf-1][r] == NOPIECE) ||
\r
1246 (iscolor(gs->board[onf-1][r], CToggle(gs->onMove))))
\r
1247 add_pos(onf - 1, r, posf, posr, numpos);
\r
1249 if(onf < gs->files - 1) {
1250 if ((gs->board[onf+1][r] == NOPIECE) ||
\r
1251 (iscolor(gs->board[onf+1][r], CToggle(gs->onMove))))
\r
1252 add_pos(onf + 1, r, posf, posr, numpos);
\r
1256 static void possible_king_moves(struct game_state_t * gs,
1258 int *posf, int *posr, int *numpos)
1260 if(gs->royalKnight)
\r
1261 possible_knight_moves(gs, onf, onr, posf, posr, numpos);
\r
1263 possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1265 possible_man_moves(gs, onf, onr, posf, posr, numpos);
\r
1268 static void possible_elephant_moves(struct game_state_t * gs,
1270 int *posf, int *posr, int *numpos)
1272 static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
\r
1276 for (j = 0; j < 4; j++) {
\r
1277 f = 2*kingJumps[j][0] + onf;
\r
1278 r = 2*kingJumps[j][1] + onr;
\r
1279 if ((f < 0) || (f >= gs->files))
\r
1281 if ((r < 0) || (r >= gs->ranks))
\r
1283 if ((gs->board[(f+onf)/2][(r+onr)/2] == NOPIECE) && ((gs->board[f][r] == NOPIECE) ||
\r
1284 (iscolor(gs->board[f][r], CToggle(gs->onMove)))))
\r
1285 add_pos(f, r, posf, posr, numpos);
\r
1289 /* Doesn't check for check */
1290 int legal_move(struct game_state_t * gs,
1291 int fFile, int fRank,
1292 int tFile, int tRank)
1297 if (fFile == ALG_DROP) {
1299 if(!gs->drops) return 0; // [HGM] variants: no drops in this variant
1300 if (move_piece == KING)
1302 if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
1304 if (gs->board[tFile][tRank] != NOPIECE)
1306 if (gs->promoType == 3) { // Shogi
1308 switch(move_piece) {
1309 case PAWN: // check for own Pawn in same file
1310 for(r=0; r<gs->ranks; r++) if(gs->board[tFile][r] == (gs->onMove|PAWN)) return 0;
1311 case LANCE: // Pawns and Lances not on last rank
1312 if(gs->onMove == WHITE && tRank >= gs->ranks-1) return 0;
1313 if(gs->onMove == BLACK && tRank < 1) return 0;
1315 case HONORABLEHORSE: // Knights at least two ranks from edge
1316 if(gs->onMove == WHITE && tRank >= gs->ranks-2) return 0;
1317 if(gs->onMove == BLACK && tRank < 2) return 0;
1321 if (move_piece == PAWN && (tRank == 0 || tRank == gs->ranks-1))
1324 } else if(fFile == ALG_CASTLE) {
1325 // [HGM] castle: this code can handle any type of free castling
1326 // it does not check if Rook and King from squares correspond to the rights, as the
1327 // user never enters such squares, but they are copied from the rights on entering o-o-o
1328 int backRank, kRook, qRook, fKing, leftEmpty, rightEmpty, leftCheck, rightCheck, f;
1329 if(!gs->castlingStyle) return 0; // no castling in this variant
1330 if(gs->onMove == WHITE) {
1331 if(gs->wkmoved < 0) return 0; // King moved
1332 fKing = gs->wkmoved;
1334 kRook = gs->wkrmoved;
1335 qRook = gs->wqrmoved;
1337 if(gs->bkmoved < 0) return 0; // King moved
1338 fKing = gs->bkmoved;
1339 backRank = gs->ranks-1;
1340 kRook = gs->bkrmoved;
1341 qRook = gs->bqrmoved;
1343 if((tRank > tFile ? qRook : kRook) < 0) return 0; // Rook moved
1344 // here we verified rights do exist, so from squares (fRank and fKing) must be valid
1345 if(gs->board[fRank][backRank] != (ROOK | gs->onMove) ) return 0; // only with own Rook
1346 if(gs->board[fKing][backRank] != (KING | gs->onMove) ) return 0; // only with own King
1348 // by now we know that K and R are in correct position, and still have rights
1349 if(tRank > tFile) { // R ends right of K: q-side
1350 leftEmpty = fRank < tFile ? fRank+1 : tFile+1;
1351 rightEmpty = tRank < fKing ? fKing-1 : tRank-1;
1353 leftEmpty = tRank < fKing ? tRank+1 : fKing+1;
1354 rightEmpty = fRank < tFile ? fRank-1 : tFile-1;
1356 for(f=leftEmpty; f<=rightEmpty; f++) // check if other pieces block castling
1357 if(f != fRank && f != fKing && gs->board[f][backRank] != NOPIECE) return 0;
1359 leftCheck = fKing < tFile ? fKing : tFile+1;
1360 rightCheck = fKing < tFile ? tFile-1 : fKing;
1361 for(f=leftCheck; f<=rightCheck; f++) // check if King passes attacked square or was in check
1362 if(is_square_attacked(gs, f, backRank)) return 0;
1364 return 1; // passed all tests
1366 move_piece = piecetype(gs->board[fFile][fRank]);
1368 if (gs->board[fFile][fRank] == NOPIECE)
1370 if (!iscolor(gs->board[fFile][fRank], gs->onMove)) /* Wrong color */
1372 if ((gs->board[tFile][tRank] != NOPIECE) &&
1373 iscolor(gs->board[tFile][tRank], gs->onMove)) /* Can't capture own */
1375 if ((fFile == tFile) && (fRank == tRank)) /* Same square */
1377 switch (move_piece) {
1379 legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank);
1382 legal = legal_knight_move(gs, fFile, fRank, tFile, tRank);
1385 legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank);
1388 legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
1392 legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank);
\r
1396 legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank);
\r
1400 legal = legal_man_move(gs, fFile, fRank, tFile, tRank);
\r
1403 legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
1406 legal = legal_elephant_move(gs, fFile, fRank, tFile, tRank);
1409 legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank);
1412 legal = legal_woody_move(gs, fFile, fRank, tFile, tRank);
1415 legal = legal_squirrel_move(gs, fFile, fRank, tFile, tRank);
1418 legal = legal_mastodon_move(gs, fFile, fRank, tFile, tRank);
1421 legal = legal_centaur_move(gs, fFile, fRank, tFile, tRank);
1424 legal = legal_horse_move(gs, fFile, fRank, tFile, tRank);
1428 legal = legal_ferz_move(gs, fFile, fRank, tFile, tRank);
1431 legal = legal_mandarin_move(gs, fFile, fRank, tFile, tRank);
1434 legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank);
1438 legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank);
1440 case MODERNELEPHANT:
1441 legal = legal_modernelephant_move(gs, fFile, fRank, tFile, tRank);
1444 legal = legal_priestess_move(gs, fFile, fRank, tFile, tRank);
1447 legal = legal_minister_move(gs, fFile, fRank, tFile, tRank);
1450 legal = legal_silver_move(gs, fFile, fRank, tFile, tRank);
1453 legal = legal_gold_move(gs, fFile, fRank, tFile, tRank);
1456 legal = legal_lance_move(gs, fFile, fRank, tFile, tRank);
1459 legal = legal_cannon_move(gs, fFile, fRank, tFile, tRank);
1462 legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank);
1465 legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank);
1467 case HONORABLEHORSE:
1468 legal = legal_honorablehorse_move(gs, fFile, fRank, tFile, tRank);
1471 legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
1480 #define DROP_CHAR '@'
1482 /* This fills in the rest of the mt structure once it is determined that
1483 * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
1484 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
1486 struct game_state_t fakeMove;
\r
1488 mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];
\r
1489 mt->enPassant = 0; /* Don't know yet, let execute move take care
\r
1491 if (mt->fromFile == ALG_DROP) {
\r
1492 mt->piecePromotionTo = NOPIECE;
\r
1493 sprintf(mt->moveString, "%s/%c%c-%c%d",
\r
1494 wpstring[mt->fromRank],
\r
1495 DROP_CHAR, DROP_CHAR,
\r
1496 mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));
\r
1497 } else if(mt->fromFile == ALG_CASTLE) {
1498 // [HGM] castle: generalized castling, fr and tr give from and to file of Rook.
1499 sprintf(mt->moveString, mt->toRank > mt->toFile ? "o-o-o" : "o-o");
1501 if(gs->promoType == 3) { // Shogi-style promotions: not just Pawns, but many pieces can promote
1502 int piece = gs->board[mt->fromFile][mt->fromRank];
1503 mt->piecePromotionTo = NOPIECE;
1504 if(colorval(piece) == WHITE && mt->fromRank < gs->ranks - gs->ranks/3
1505 && mt->toRank < gs->ranks - gs->ranks/3 ||
1506 colorval(piece) == BLACK && mt->fromRank >= gs->ranks/3
1507 && mt->toRank >= gs->ranks/3 )
1508 promote = NOPIECE; // suppress promotion outside zone
1509 if(promote) { // promotion piece determined by original, no matter what was requested
1510 switch(piecetype(piece)) {
1513 case HONORABLEHORSE:
1515 promote = GOLD; break;
1517 promote = DRAGONHORSE; break;
1519 promote = DRAGONKING; break;
1520 default: promote = NOPIECE; // not a promotion
1523 switch(piecetype(piece)) { // force mandatory promotions
1524 case HONORABLEHORSE:
1525 if(mt->toRank == 1 || mt->toRank == gs->files-2) promote = GOLD;
1528 if(mt->toRank == 0 || mt->toRank == gs->files-1) promote = GOLD;
1531 if(promote) mt->piecePromotionTo = promote | (colorval(gs->board[mt->fromFile][mt->fromRank]));
\r
1533 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
1534 !gs->palace && // [HGM] XQ: no promotions in xiangqi
\r
1535 ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) {
1536 int stm = colorval(gs->board[mt->fromFile][mt->fromRank]);
1537 if(!promote && (mt->toRank == 0 || mt->toRank == gs->ranks-1)) { // promotion obligatory, but not specified
1538 if(gs->promoType != 2) promote = QUEEN; else { // choose a default
1539 for(promote=KING-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break;
1540 if(promote == PAWN) return MOVE_ILLEGAL; // nothing available
1542 } // if not obligatory, we defer unless promoton was explicitly specified!
1543 if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2;
1544 if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj
1545 // non-promotion can still be an option for deeper promotion zones
1546 mt->piecePromotionTo = promote ? (promote | stm) : NOPIECE;
1547 if(promote && gs->promoType == 2 && !gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified
1549 mt->piecePromotionTo = NOPIECE;
\r
1551 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
\r
1552 ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {
\r
1553 mt->doublePawn = mt->fromFile;
\r
1555 mt->doublePawn = -1;
\r
1558 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
\r
1559 (mt->fromFile == gs->files/2) && (mt->toFile == 2) &&
1560 mt->fromRank == mt->toRank) {
\r
1561 sprintf(mt->moveString, "o-o-o");
\r
1562 } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
\r
1563 (mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2) &&
1564 mt->fromRank == mt->toRank) {
\r
1565 sprintf(mt->moveString, "o-o");
1570 sprintf(mt->moveString, "%s/%c%d-%c%d",
\r
1571 wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],
\r
1572 mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks>9),
\r
1573 mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));
\r
1576 /* Replace this with an algabraic de-parser */
\r
1578 sprintf(mt->algString, alg_unparse(gs, mt));
\r
1580 /* Calculates enPassant also */
1581 execute_move(&fakeMove, mt, 0);
\r
1583 /* Does making this move leave ME in check? */
\r
1584 if (in_check(&fakeMove))
\r
1585 return MOVE_ILLEGAL;
\r
1586 /* IanO: bughouse variants: drop cannot be check/checkmate */
\r
1591 int legal_andcheck_move(struct game_state_t * gs,
1592 int fFile, int fRank,
1593 int tFile, int tRank)
1597 if (!legal_move(gs, fFile, fRank, tFile, tRank))
1599 mt.color = gs->onMove;
1600 mt.fromFile = fFile;
1601 mt.fromRank = fRank;
1604 /* This should take into account a pawn promoting to another piece */
1605 if (move_calculate(gs, &mt, NOPIECE) == MOVE_OK)
1611 /* in_check: checks if the side that is NOT about to move is in check
1613 int in_check(struct game_state_t * gs)
1616 int kf = -1, kr = -1;
\r
1618 /* Find the king */
\r
1619 if (gs->onMove == WHITE) {
\r
1620 for (f = 0; f < gs->files && kf < 0; f++)
\r
1621 for (r = 0; r < gs->ranks && kf < 0; r++)
\r
1622 if (gs->board[f][r] == B_KING) {
\r
1627 for (f = 0; f < gs->files && kf < 0; f++)
\r
1628 for (r = 0; r < gs->ranks && kf < 0; r++)
\r
1629 if (gs->board[f][r] == W_KING) {
\r
1635 d_printf( "CHESSD: Error game with no king!\n");
\r
1638 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
\r
1639 NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
\r
1640 if (legal_move(gs, f, r, kf, kr)) { /* In Check? */
1647 int has_legal_move(struct game_state_t * gs)
1652 int possiblef[500], possibler[500];
1653 int numpossible = 0;
1655 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
1656 NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
1657 switch (piecetype(gs->board[f][r])) {
1659 possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
1662 possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
1665 possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
1668 possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
1672 possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible);
\r
1676 possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible);
\r
1680 possible_man_moves(gs, f, r, possiblef, possibler, &numpossible);
\r
1683 possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
1686 possible_elephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1689 possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible);
1692 possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible);
1695 possible_squirrel_moves(gs, f, r, possiblef, possibler, &numpossible);
1698 possible_mastodon_moves(gs, f, r, possiblef, possibler, &numpossible);
1701 possible_centaur_moves(gs, f, r, possiblef, possibler, &numpossible);
1704 possible_horse_moves(gs, f, r, possiblef, possibler, &numpossible);
1708 possible_ferz_moves(gs, f, r, possiblef, possibler, &numpossible);
1711 possible_mandarin_moves(gs, f, r, possiblef, possibler, &numpossible);
1714 possible_wazir_moves(gs, f, r, possiblef, possibler, &numpossible);
1718 possible_alfil_moves(gs, f, r, possiblef, possibler, &numpossible);
1720 case MODERNELEPHANT:
1721 possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1724 possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible);
1727 possible_minister_moves(gs, f, r, possiblef, possibler, &numpossible);
1730 possible_silver_moves(gs, f, r, possiblef, possibler, &numpossible);
1733 possible_gold_moves(gs, f, r, possiblef, possibler, &numpossible);
1736 possible_cannon_moves(gs, f, r, possiblef, possibler, &numpossible);
1739 possible_lance_moves(gs, f, r, possiblef, possibler, &numpossible);
1742 possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1745 possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible);
1747 case HONORABLEHORSE:
1748 possible_honorablehorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1753 possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
1756 if (numpossible >= 500) {
1757 d_printf( "CHESSD: Possible move overrun\n");
1759 for (i = 0; i < numpossible; i++)
1760 if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) {
1765 /* IanO: if we got here, then kf and kr must be set */
\r
1766 if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0
1767 || gs->holdings) { // [HGM] zh: also in 2-player games with drops
\r
1768 /* bughouse: potential drops as check interpositions */
\r
1769 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;
\r
1770 for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {
\r
1771 if (f>=0 && f<gs->files && r>=0 && r<gs->ranks && gs->board[f][r] == NOPIECE) {
\r
1772 /* try a drop next to the king */
\r
1773 if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {
\r
1774 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
1775 // OK, so we have an interposing drop. But do we have something to drop?
1776 if(game_globals.garray[gs->gameNum].link < 0) {
1777 // we have no partner, so we must have something to drop now
1778 for(i=QUEEN; i>=PAWN; i--)
1779 if (legal_andcheck_move(gs, ALG_DROP, i, f, r)) return 1;
\r
1786 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
\r
1792 /* This will end up being a very complicated function */
1793 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
1795 int type = is_move(mstr);
\r
1798 mt->piecePromotionTo = NOPIECE;
\r
1799 mt->color = gs->onMove;
\r
1802 return MOVE_ILLEGAL;
\r
1805 mt->fromFile = mstr[0] - 'a';
\r
1806 mt->fromRank = mstr[1] - '1' + (gs->ranks>9);
\r
1807 mt->toFile = mstr[2] - 'a';
\r
1808 mt->toRank = mstr[3] - '1' + (gs->ranks>9);
\r
1811 mt->fromFile = mstr[0] - 'a';
\r
1812 mt->fromRank = mstr[1] - '1' + (gs->ranks>9);
\r
1813 mt->toFile = mstr[3] - 'a';
\r
1814 mt->toRank = mstr[4] - '1' + (gs->ranks>9);
\r
1818 mt->fromFile = gs->files/2;
\r
1819 mt->toFile = gs->files-2;
\r
1820 if (gs->onMove == WHITE) {
\r
1824 mt->fromRank = gs->ranks-1;
\r
1825 mt->toRank = gs->ranks-1;
\r
1829 // [HGM] castle: for now always assume Fischer-type castling (of which normal castling is a special case).
1830 mt->fromFile = ALG_CASTLE;
\r
1831 mt->toFile = gs->files-2;
\r
1832 mt->fromRank = gs->onMove == WHITE ? gs->wkrmoved : gs->bkrmoved;
\r
1833 mt->toRank = mt->toFile-1; // R next to K
\r
1837 mt->fromFile = gs->files/2;
\r
1839 if (gs->onMove == WHITE) {
\r
1843 mt->fromRank = gs->ranks-1;
\r
1844 mt->toRank = gs->ranks-1;
\r
1848 mt->fromFile = ALG_CASTLE;
\r
1850 mt->fromRank = gs->onMove == WHITE ? gs->wqrmoved : gs->bqrmoved;
\r
1851 mt->toRank = mt->toFile+1;
1854 /* Fills in the mt structure */
\r
1855 if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)
\r
1859 return MOVE_ILLEGAL;
\r
1862 if((mt->fromRank >= gs->ranks || mt->fromRank < 0 || mt->fromFile >= gs->files) &&
1863 mt->fromFile != ALG_DROP && mt->fromFile != ALG_CASTLE
\r
1864 || mt->toRank < 0 || mt->toRank >= gs->ranks || mt->toFile >= gs->files)
\r
1865 return MOVE_ILLEGAL; // [HGM] make sure move stays on board
1867 if (!(result = legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)))
1868 return MOVE_ILLEGAL;
\r
1870 if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format
1871 if(mt->fromFile - mt->toFile > 1) { // Q-side
1873 mt->toRank = mt->toFile+1;
1874 } else if(mt->toFile - mt->fromFile > 1) { // K-side
1875 mt->fromRank = gs->files-1;
1876 mt->toRank = mt->toFile-1;
1878 mt->fromFile = ALG_CASTLE;
1881 if (mt->piecePromotionTo != NOPIECE) {
1882 promote = piecetype(mt->piecePromotionTo);
\r
1885 return move_calculate(gs, mt, promote);
\r
1888 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
1889 /* check_game_status prevents recursion */
1890 int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_status)
1894 int i, j, foobar, wCnt, bCnt, king, rook;
1896 if (mt->fromFile == ALG_DROP) {
1897 movedPiece = mt->fromRank;
1898 tookPiece = NOPIECE;
1899 gs->holding[gs->onMove==WHITE ? 0 : 1][movedPiece-1]--;
1900 gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
1901 if (gs->gameNum >= 0)
1902 gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1903 } else if(mt->fromFile == ALG_CASTLE) {
1904 int backRank, fKing;
1905 // [HGM] castle: perform castling
1906 if(gs->onMove == WHITE) {
1908 fKing = gs->wkmoved;
1909 gs->wkmoved = -gs->wkmoved-2;
1911 backRank = gs->ranks-1;
1912 fKing = gs->bkmoved;
1913 gs->bkmoved = -gs->bkmoved-2;
1915 // move Rook & King, in a way that is resistant to ending where they started (for FRC!)
1916 rook = gs->board[mt->fromRank][backRank]; // first remember
\r
1917 king = gs->board[fKing][backRank];
\r
1918 gs->board[mt->fromRank][backRank] = NOPIECE; // then erase
\r gs->board[fKing][backRank] = NOPIECE;
\r gs->board[mt->toRank][backRank] = rook; // then put back
1919 gs->board[mt->toFile][backRank] = king;
1921 movedPiece = gs->board[mt->fromFile][mt->fromRank];
1922 tookPiece = gs->board[mt->toFile][mt->toRank];
1923 if (mt->piecePromotionTo == NOPIECE) {
1924 gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
1926 gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
1927 if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
1929 gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
1930 /* Check if irreversable */
1931 if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible!
1932 || (tookPiece != NOPIECE)) {
1933 if (gs->gameNum >= 0)
1934 gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1936 /* Check if this move is en-passant */
1937 if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
1938 (tookPiece == NOPIECE) && !gs->palace) { // [HGM] XQ: no e.p. in sideway xiangqi moves
1939 if (gs->onMove == WHITE) {
1940 mt->pieceCaptured = B_PAWN;
1942 mt->pieceCaptured = W_PAWN;
1944 if (mt->fromFile > mt->toFile) {
1949 gs->board[mt->toFile][mt->fromRank] = NOPIECE;
1951 /* Check en-passant flags for next moves */
\r
1952 for (i = 0; i < gs->files; i++) {
\r
1953 gs->ep_possible[0][i] = 0;
\r
1954 gs->ep_possible[1][i] = 0;
\r
1956 /* Added by Sparky 3/16/95
1958 From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
1959 Subject: Re: To DAV: enpassant prob. again
1960 To: chess@caissa.onenet.net (ICS)
1961 Date: Thu, 16 Mar 1995 20:06:20 +0100 (MET)
1964 There was bug in other part of code:
1966 movecheck.c , line about 800:
1968 if (gs->onMove == WHITE) {
1969 if ((mt->toFile+1 < 7 ) .... should be : (mt->toFile < 7 ) }
1972 if ((piecetype(movedPiece) == PAWN) &&
\r
1973 ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {
\r
1974 /* Should turn on enpassent flag if possible */
\r
1975 if (gs->onMove == WHITE) {
\r
1976 if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == B_PAWN) {
\r
1977 gs->ep_possible[1][mt->toFile + 1] = -1;
\r
1979 if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == B_PAWN) {
\r
1980 gs->ep_possible[1][mt->toFile - 1] = 1;
\r
1983 if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == W_PAWN) {
\r
1984 gs->ep_possible[0][mt->toFile + 1] = -1;
\r
1986 if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == W_PAWN) {
\r
1987 gs->ep_possible[0][mt->toFile - 1] = 1;
\r
1991 if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == 0) && (gs->onMove == WHITE)) {
\r
1992 if (mt->fromFile == gs->wqrmoved) // [HGM] castle: flip w.r.t. -1 to remember original
\r
1993 gs->wqrmoved = -gs->wqrmoved-2;
\r
1994 if (mt->fromFile == gs->wkrmoved)
\r
1995 gs->wkrmoved = -gs->wkrmoved-2;
\r
1997 if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == gs->ranks-1) && (gs->onMove == BLACK)) {
\r
1998 if (mt->fromFile == gs->bqrmoved)
\r
1999 gs->bqrmoved = -gs->bqrmoved-2;
\r
2000 if (mt->fromFile == gs->bkrmoved)
\r
2001 gs->bkrmoved = -gs->bkrmoved-2;
\r
2003 if (piecetype(movedPiece) == KING) {
\r
2004 if ((gs->onMove == WHITE) && (mt->fromFile == gs->wkmoved))
\r
2005 gs->wkmoved = -gs->wkmoved-2;
\r
2006 if ((gs->onMove == BLACK) && (mt->fromFile == gs->bkmoved))
\r
2007 gs->bkmoved = -gs->bkmoved-2;
\r
2010 if ((piecetype(movedPiece) == KING) &&
\r
2011 ((mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2)) &&
2012 mt->fromRank == mt->toRank) { /* Check for KS castling */
\r
2013 gs->board[gs->files-3][mt->toRank] = gs->board[gs->files-1][mt->toRank];
\r
2014 gs->board[gs->files-1][mt->toRank] = NOPIECE;
\r
2016 if ((piecetype(movedPiece) == KING) &&
\r
2017 ((mt->fromFile == gs->files/2) && (mt->toFile == 2)) &&
2018 mt->fromRank == mt->toRank) { /* Check for QS castling */
\r
2019 gs->board[3][mt->toRank] = gs->board[0][mt->toRank];
\r
2020 gs->board[0][mt->toRank] = NOPIECE;
\r
2024 if (gs->onMove == BLACK)
\r
2027 if (check_game_status) {
\r
2028 /* Does this move result in check? */
\r
2029 if (in_check(gs)) {
\r
2030 /* Check for checkmate */
\r
2031 gs->onMove = CToggle(gs->onMove);
\r
2032 if (!has_legal_move(gs))
\r
2033 return MOVE_CHECKMATE;
\r
2035 /* Check for stalemate */
\r
2036 gs->onMove = CToggle(gs->onMove);
\r
2037 if (!has_legal_move(gs))
\r
2038 return gs->stalemate ? MOVE_STALEMATE : MOVE_CHECKMATE; // [HGM] in XQ and shatranj stalemate loses
\r
2040 /* loon: check for insufficient mating material, first try */
\r
2041 foobar = wCnt = bCnt = 0;
\r
2042 for (i=0; i<gs->files; i++) {
\r
2043 for (j=0; j<gs->ranks; j++) {
2044 int p = gs->board[i][j];
\r
2045 switch(piecetype(p)) {
\r
2057 if(p != NOPIECE && iscolor(p, WHITE)) wCnt++;
2058 if(iscolor(p, BLACK)) bCnt++;
\r
2061 if(gs->bareKingLoses) { // [HGM] with bare-King-loses rule only KK is insuff. material
2062 if(gs->onMove == BLACK && wCnt == 1 && bCnt > 1) return MOVE_BARE;
2063 if(gs->onMove == WHITE && bCnt == 1 && wCnt > 1) return MOVE_BARE;
2064 if(bCnt == 1 && wCnt == 1) return MOVE_NOMATERIAL;
2065 } else if (foobar < 2)
\r
2066 return MOVE_NOMATERIAL;
\r
2068 gs->onMove = CToggle(gs->onMove);
\r
2074 int backup_move(int g, int mode)
2076 struct game_state_t *gs;
2077 struct move_t *m, *m1;
2080 if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */
2081 return MOVE_ILLEGAL;
2082 if (game_globals.garray[g].numHalfMoves < 1)
2083 return MOVE_ILLEGAL;
2084 gs = &game_globals.garray[g].game_state;
2085 m = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] :
2086 &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
2087 if (m->toFile < 0) {
2088 return MOVE_ILLEGAL;
2090 if(m->fromFile == ALG_CASTLE) {
2091 // [HGM] castling in new format. Derive K and R moves
2092 int rank, kingFromFile;
2093 if(m->color == WHITE) {
2095 kingFromFile = -gs->wkmoved-2;
2096 if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2097 gs->wkmoved = kingFromFile;
2098 if(m->toRank > m->toFile) gs->wqrmoved = m->fromRank;
2099 else gs->wkrmoved = m->fromRank;
2102 kingFromFile = -gs->bkmoved-2;
2103 if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2104 gs->bkmoved = kingFromFile;
2105 if(m->toRank > m->toFile) gs->bqrmoved = m->fromRank;
2106 else gs->bkrmoved = m->fromRank;
2108 // remove first, as one might come back to a square the other left
2109 gs->board[m->toFile ][rank] = NOPIECE; // King toSqr
2110 gs->board[m->toRank ][rank] = NOPIECE; // Rook toSqr
2111 gs->board[m->fromRank][rank] = ROOK | m->color; // Rook fromSqr
2112 gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
2115 gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
2116 if (m->piecePromotionTo != NOPIECE) {
2117 gs->board[m->fromFile][m->fromRank] = PAWN |
2118 colorval(gs->board[m->fromFile][m->fromRank]);
2121 When takeback a _first_ move of rook, the ??rmoved variable
2122 must be cleared . To check, if the move is first, we should
2124 *******************/
2125 if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
2126 if (m->color == WHITE) {
2127 if ((m->fromFile == -gs->wqrmoved-2) && (m->fromRank == 0)) {
2128 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
2129 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
2130 if ((m1->fromFile == -gs->wqrmoved-2) && (m1->fromRank == 0))
2133 if (i == game_globals.garray[g].numHalfMoves - 1)
2134 gs->wqrmoved = m->fromFile;
2136 if ((m->fromFile == -gs->wkrmoved-2) && (m->fromRank == 0)) {
\r
2137 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
\r
2138 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
\r
2139 if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == 0))
\r
2142 if (i == game_globals.garray[g].numHalfMoves - 1)
\r
2143 gs->wkrmoved = m->fromFile;
\r
2146 if ((m->fromFile == -gs->bqrmoved-2) && (m->fromRank == gs->ranks-1)) {
\r
2147 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
\r
2148 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
\r
2149 if ((m1->fromFile == -gs->bkrmoved-2) && (m1->fromRank == gs->ranks-1))
\r
2152 if (i == game_globals.garray[g].numHalfMoves - 1)
\r
2153 gs->bqrmoved = m->fromFile;
\r
2155 if ((m->fromFile == -gs->bkrmoved-2) && (m->fromRank == gs->ranks-1)) {
\r
2156 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
\r
2157 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
\r
2158 if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == gs->ranks-1))
\r
2161 if (i == game_globals.garray[g].numHalfMoves - 1)
\r
2162 gs->bkrmoved = m->fromFile;
\r
2166 if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
2167 gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2169 /* [HGM] castlings are already intercepted due to new format; this code wrecks knightmate! */
2170 if (m->toFile - m->fromFile == 2) {
2171 gs->board[7][m->fromRank] = ROOK |
2172 colorval(gs->board[m->fromFile][m->fromRank]);
2173 gs->board[5][m->fromRank] = NOPIECE;
2176 If takeback a castling, the appropriates ??moved variables
2179 if (m->color == WHITE) {
2188 if (m->fromFile - m->toFile == 2) {
2189 gs->board[0][m->fromRank] = ROOK |
2190 colorval(gs->board[m->fromFile][m->fromRank]);
2191 gs->board[3][m->fromRank] = NOPIECE;
2194 If takeback a castling, the appropriate ??moved variables
2197 if (m->color == WHITE) {
2208 When takeback a _first_ move of king (not the castling),
2209 the ?kmoved variable must be cleared . To check, if the move is first,
2210 we should scan moveList.
2211 *******************/
2213 if (m->color == WHITE) {
\r
2215 if ((m->fromFile == -gs->wkmoved-2) && (m->fromRank == 0)) {
\r
2216 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
\r
2217 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
\r
2218 if ((m1->fromFile == gs->wkmoved-2) && (m1->fromRank == 0))
\r
2221 if (i == game_globals.garray[g].numHalfMoves - 1)
\r
2222 gs->wkmoved = m->fromFile;
\r
2225 if ((m->fromFile == -gs->bkmoved-2) && (m->fromRank == gs->ranks-1)) {
\r
2226 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
\r
2227 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
\r
2228 if ((m1->fromFile == -gs->bkmoved-2) && (m1->fromRank == gs->ranks-1))
\r
2231 if (i == game_globals.garray[g].numHalfMoves - 1)
\r
2232 gs->bkmoved = m->fromFile;
\r
2236 if (m->enPassant) { /* Do enPassant */
2237 gs->board[m->toFile][m->fromRank] = PAWN |
2238 (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
2239 gs->board[m->toFile][m->toRank] = NOPIECE;
2240 /* Should set the enpassant array, but I don't care right now */
2243 gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2245 if (game_globals.garray[g].status != GAME_EXAMINE) {
2246 game_update_time(g);
2248 game_globals.garray[g].numHalfMoves--;
2249 if (game_globals.garray[g].status != GAME_EXAMINE) {
2250 if (game_globals.garray[g].wInitTime) { /* Don't update times in untimed games */
2253 if (m->color == WHITE) {
2254 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* white uses timeseal? */
2255 game_globals.garray[g].wRealTime += (m->tookTime * 100);
2256 game_globals.garray[g].wRealTime -= (game_globals.garray[g].wIncrement * 100);
2257 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2258 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2259 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2260 } else { /* opp has no timeseal */
2261 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2263 } else { /* white has no timeseal */
2264 game_globals.garray[g].wTime += m->tookTime;
2265 game_globals.garray[g].wTime -= game_globals.garray[g].wIncrement;
2266 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2267 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2268 } else { /* opp has no timeseal */
2269 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2273 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* black uses timeseal? */
2274 game_globals.garray[g].bRealTime += (m->tookTime * 100);
2275 game_globals.garray[g].bRealTime -= (game_globals.garray[g].wIncrement * 100);
2276 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2277 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2278 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2279 } else { /* opp has no timeseal */
2280 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2282 } else { /* black has no timeseal */
2283 game_globals.garray[g].bTime += m->tookTime;
2284 if (!game_globals.garray[g].bIncrement)
2285 game_globals.garray[g].bTime -= game_globals.garray[g].wIncrement;
2287 game_globals.garray[g].bTime -= game_globals.garray[g].bIncrement;
2288 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2289 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2290 } else { /* opp has no timeseal */
2291 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2296 if (game_globals.garray[g].numHalfMoves == 0)
2297 game_globals.garray[g].timeOfStart = now;
2298 game_globals.garray[g].lastMoveTime = now;
2299 game_globals.garray[g].lastDecTime = now;
2302 if (gs->onMove == BLACK)
2309 /******* Here begins the patch : ********************************
2310 Takeback of last move is done already, it's time to update enpassant
2311 array. (patch from Soso, added by Sparky 3/17/95)
2314 if (game_globals.garray[g].numHalfMoves > 0) {
\r
2315 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] :
\r
2316 &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
\r
2317 if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {
\r
2318 if ((m1->toRank - m1->fromRank) == 2) {
\r
2319 if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == B_PAWN) {
\r
2320 gs->ep_possible[1][m1->toFile + 1] = -1;
\r
2322 if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == B_PAWN) {
\r
2323 gs->ep_possible[1][m1->toFile - 1] = 1;
\r
2326 if ((m1->toRank - m1->fromRank) == -2) {
\r
2327 if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == W_PAWN) {
\r
2328 gs->ep_possible[0][m1->toFile + 1] = -1;
\r
2330 if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == W_PAWN) {
\r
2331 gs->ep_possible[0][m1->toFile - 1] = 1;
\r
2336 /************** and here's the end **************/