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 /* Simply tests if the input string is a move or not. */
24 /* If it matches patterns below */
25 /* Add to this list as you improve the move parser */
27 /* MS_COMPDASH e2-e4 */
28 /* MS_CASTLE o-o, o-o-o */
30 /* MS_ALG e4, Nd5 Ncd5 */
31 int is_move(const char *mstr)
33 int len = strlen(mstr);
34 if ((len > 3) && (mstr[len - 2] == '='))
37 /* remove the 'mates' marker */
38 if (mstr[len - 1] == '#')
41 if (len == 4) { /* Test for e2e4 */
42 if (isfile(mstr[0]) && isrank(mstr[1]) &&
43 isfile(mstr[2]) && isrank(mstr[3])) {
47 if (len == 5) { /* Test for e2-e4 */
48 if (isfile(mstr[0]) && isrank(mstr[1]) &&
50 isfile(mstr[3]) && isrank(mstr[4])) {
54 if (len == 3) { /* Test for o-o */
55 if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o')) {
58 if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O')) {
61 if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0')) {
65 if (len == 2) { /* Test for oo */
66 if ((mstr[0] == 'o') && (mstr[1] == 'o')) {
69 if ((mstr[0] == 'O') && (mstr[1] == 'O')) {
72 if ((mstr[0] == '0') && (mstr[1] == '0')) {
76 if (len == 5) { /* Test for o-o-o */
77 if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o') && (mstr[3] == '-') && (mstr[4] == 'o')) {
80 if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O') && (mstr[3] == '-') && (mstr[4] == 'O')) {
83 if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0') && (mstr[3] == '-') && (mstr[4] == '0')) {
87 if (len == 3) { /* Test for ooo */
88 if ((mstr[0] == 'o') && (mstr[1] == 'o') && (mstr[2] == 'o')) {
91 if ((mstr[0] == 'O') && (mstr[1] == 'O') && (mstr[2] == 'O')) {
94 if ((mstr[0] == '0') && (mstr[1] == '0') && (mstr[2] == '0')) {
98 return alg_is_move(mstr);
102 int NextPieceLoop(board_t b, int *f, int *r, int color)
112 if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color))
118 int InitPieceLoop(board_t b, int *f, int *r, int color)
125 /* All of the routines assume that the obvious problems have been checked */
126 /* See legal_move() */
127 static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr )
130 if (gs->board[tf][tr] != NOPIECE) return 0;
131 if (gs->onMove == WHITE) {
132 if (tr - fr == 1) return 1;
133 if ((fr == 1) && (tr - fr == 2) && gs->board[ff][2]==NOPIECE) return 1;
135 if (fr - tr == 1) return 1;
136 if ((fr == 6) && (fr - tr == 2) && gs->board[ff][5]==NOPIECE) return 1;
140 if (ff != tf) { /* Capture ? */
141 if ((ff - tf != 1) && (tf - ff != 1)) return 0;
142 if ((fr - tr != 1) && (tr - fr != 1)) return 0;
143 if (gs->onMove == WHITE) {
144 if (fr > tr) return 0;
145 if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK))
147 if (gs->ep_possible[0][ff] == 1) {
148 if ((tf==ff+1) && (gs->board[ff+1][fr] == B_PAWN)) return 1;
149 } else if (gs->ep_possible[0][ff] == -1) {
150 if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1;
153 if (tr > fr) return 0;
154 if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE))
156 if (gs->ep_possible[1][ff] == 1) {
157 if ((tf==ff+1) && (gs->board[ff+1][fr] == W_PAWN)) return 1;
158 } else if (gs->ep_possible[1][ff] == -1) {
159 if ((tf==ff-1) && (gs->board[ff-1][fr] == W_PAWN)) return 1;
166 static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
183 static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
207 return 0; /* Not diagonal */
209 return 1; /* One square, ok */
211 for (x = startx, y = starty; count; x += incx, y += incy, count--) {
212 if (gs->board[x][y] != NOPIECE)
218 static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
224 if (abs(fr - tr) == 1)
233 for (i = start; i <= stop; i++) {
234 if (gs->board[ff][i] != NOPIECE)
238 } else if (fr == tr) {
239 if (abs(ff - tf) == 1)
248 for (i = start; i <= stop; i++) {
249 if (gs->board[i][fr] != NOPIECE)
258 static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
260 return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
263 /* Ckeck, if square (kf,kr) is attacked by enemy piece.
264 * Used in castling from/through check testing.
267 /* new one from soso: */
268 static int is_square_attacked (struct game_state_t *gs, int kf, int kr)
270 struct game_state_t fakeMove;
273 fakeMove.board[4][kr] = NOPIECE;
274 fakeMove.board[kf][kr] = KING | fakeMove.onMove;
275 fakeMove.onMove = CToggle (fakeMove.onMove);
276 if (in_check(&fakeMove)) return 1;
281 static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
284 gs->onMove = CToggle(gs->onMove);
286 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
287 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
288 if (legal_move(gs, f, r, kf, kr)) {
289 gs->onMove = CToggle(gs->onMove);
293 gs->onMove = CToggle(gs->onMove);
298 static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
300 if (gs->onMove == WHITE) {
301 /* King side castling */
302 if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && !gs->wkmoved
303 && (!gs->wkrmoved) && (gs->board[5][0] == NOPIECE) &&
304 (gs->board[6][0] == NOPIECE) && (gs->board[7][0] == W_ROOK) &&
305 (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) {
308 /* Queen side castling */
309 if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && !gs->wkmoved
310 && (!gs->wqrmoved) && (gs->board[3][0] == NOPIECE) &&
311 (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&
312 (gs->board[0][0] == W_ROOK) &&
313 (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) {
317 /* King side castling */
318 if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && !gs->bkmoved
319 && (!gs->bkrmoved) && (gs->board[5][7] == NOPIECE) &&
320 (gs->board[6][7] == NOPIECE) && (gs->board[7][7] == B_ROOK) &&
321 (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) {
324 /* Queen side castling */
325 if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && (!gs->bkmoved)
326 && (!gs->bqrmoved) && (gs->board[3][7] == NOPIECE) &&
327 (gs->board[2][7] == NOPIECE) && (gs->board[1][7] == NOPIECE) &&
328 (gs->board[0][7] == B_ROOK) &&
329 (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) {
333 if (abs(ff - tf) > 1)
335 if (abs(fr - tr) > 1)
340 static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos)
347 static void possible_pawn_moves(struct game_state_t * gs,
349 int *posf, int *posr, int *numpos)
351 if (gs->onMove == WHITE) {
352 if (gs->board[onf][onr + 1] == NOPIECE) {
353 add_pos(onf, onr + 1, posf, posr, numpos);
354 if ((onr == 1) && (gs->board[onf][onr + 2] == NOPIECE))
355 add_pos(onf, onr + 2, posf, posr, numpos);
357 if ((onf > 0) && (gs->board[onf - 1][onr + 1] != NOPIECE) &&
358 (iscolor(gs->board[onf - 1][onr + 1], BLACK)))
359 add_pos(onf - 1, onr + 1, posf, posr, numpos);
360 if ((onf < 7) && (gs->board[onf + 1][onr + 1] != NOPIECE) &&
361 (iscolor(gs->board[onf + 1][onr + 1], BLACK)))
362 add_pos(onf + 1, onr + 1, posf, posr, numpos);
363 if (gs->ep_possible[0][onf] == -1)
364 add_pos(onf - 1, onr + 1, posf, posr, numpos);
365 if (gs->ep_possible[0][onf] == 1)
366 add_pos(onf + 1, onr + 1, posf, posr, numpos);
368 if (gs->board[onf][onr - 1] == NOPIECE) {
369 add_pos(onf, onr - 1, posf, posr, numpos);
370 if ((onr == 6) && (gs->board[onf][onr - 2] == NOPIECE))
371 add_pos(onf, onr - 2, posf, posr, numpos);
373 if ((onf > 0) && (gs->board[onf - 1][onr - 1] != NOPIECE) &&
374 (iscolor(gs->board[onf - 1][onr - 1], WHITE)))
375 add_pos(onf - 1, onr - 1, posf, posr, numpos);
376 /* loon: changed what looks like a typo, here's the original line:
377 add_pos(onf - 1, onr + 1, posf, posr, numpos);
379 if ((onf < 7) && (gs->board[onf + 1][onr - 1] != NOPIECE) &&
380 (iscolor(gs->board[onf + 1][onr - 1], WHITE)))
381 add_pos(onf + 1, onr - 1, posf, posr, numpos);
382 if (gs->ep_possible[1][onf] == -1)
383 add_pos(onf - 1, onr - 1, posf, posr, numpos);
384 if (gs->ep_possible[1][onf] == 1)
385 add_pos(onf + 1, onr - 1, posf, posr, numpos);
389 static void possible_knight_moves(struct game_state_t * gs,
391 int *posf, int *posr, int *numpos)
393 static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},
394 {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};
398 for (j = 0; j < 8; j++) {
399 f = knightJumps[j][0] + onf;
400 r = knightJumps[j][1] + onr;
401 if ((f < 0) || (f > 7))
403 if ((r < 0) || (r > 7))
405 if ((gs->board[f][r] == NOPIECE) ||
406 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
407 add_pos(f, r, posf, posr, numpos);
411 static void possible_bishop_moves(struct game_state_t * gs,
413 int *posf, int *posr, int *numpos)
423 if ((f < 0) || (f > 7))
425 if ((r < 0) || (r > 7))
427 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
429 add_pos(f, r, posf, posr, numpos);
430 if (gs->board[f][r] != NOPIECE)
439 if ((f < 0) || (f > 7))
441 if ((r < 0) || (r > 7))
443 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
445 add_pos(f, r, posf, posr, numpos);
446 if (gs->board[f][r] != NOPIECE)
455 if ((f < 0) || (f > 7))
457 if ((r < 0) || (r > 7))
459 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
461 add_pos(f, r, posf, posr, numpos);
462 if (gs->board[f][r] != NOPIECE)
471 if ((f < 0) || (f > 7))
473 if ((r < 0) || (r > 7))
475 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
477 add_pos(f, r, posf, posr, numpos);
478 if (gs->board[f][r] != NOPIECE)
483 static void possible_rook_moves(struct game_state_t * gs,
485 int *posf, int *posr, int *numpos)
494 if ((f < 0) || (f > 7))
496 if ((r < 0) || (r > 7))
498 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
500 add_pos(f, r, posf, posr, numpos);
501 if (gs->board[f][r] != NOPIECE)
509 if ((f < 0) || (f > 7))
511 if ((r < 0) || (r > 7))
513 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
515 add_pos(f, r, posf, posr, numpos);
516 if (gs->board[f][r] != NOPIECE)
524 if ((f < 0) || (f > 7))
526 if ((r < 0) || (r > 7))
528 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
530 add_pos(f, r, posf, posr, numpos);
531 if (gs->board[f][r] != NOPIECE)
539 if ((f < 0) || (f > 7))
541 if ((r < 0) || (r > 7))
543 if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
545 add_pos(f, r, posf, posr, numpos);
546 if (gs->board[f][r] != NOPIECE)
551 static void possible_queen_moves(struct game_state_t * gs,
553 int *posf, int *posr, int *numpos)
555 possible_rook_moves(gs, onf, onr, posf, posr, numpos);
556 possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
559 static void possible_king_moves(struct game_state_t * gs,
561 int *posf, int *posr, int *numpos)
563 static int kingJumps[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 1},
564 {0, 1}, {1, 1}, {-1, 0}, {1, 0}};
568 for (j = 0; j < 8; j++) {
569 f = kingJumps[j][0] + onf;
570 r = kingJumps[j][1] + onr;
571 if ((f < 0) || (f > 7))
573 if ((r < 0) || (r > 7))
575 if ((gs->board[f][r] == NOPIECE) ||
576 (iscolor(gs->board[f][r], CToggle(gs->onMove))))
577 add_pos(f, r, posf, posr, numpos);
581 /* Doesn't check for check */
582 int legal_move(struct game_state_t * gs,
583 int fFile, int fRank,
584 int tFile, int tRank)
589 if (fFile == ALG_DROP) {
591 if (move_piece == KING)
593 if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
595 if (gs->board[tFile][tRank] != NOPIECE)
597 if (move_piece == PAWN && (tRank == 0 || tRank == 7))
601 move_piece = piecetype(gs->board[fFile][fRank]);
603 if (gs->board[fFile][fRank] == NOPIECE)
605 if (!iscolor(gs->board[fFile][fRank], gs->onMove)) /* Wrong color */
607 if ((gs->board[tFile][tRank] != NOPIECE) &&
608 iscolor(gs->board[tFile][tRank], gs->onMove)) /* Can't capture own */
610 if ((fFile == tFile) && (fRank == tRank)) /* Same square */
612 switch (move_piece) {
614 legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank);
617 legal = legal_knight_move(gs, fFile, fRank, tFile, tRank);
620 legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank);
623 legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
626 legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
629 legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
638 #define DROP_CHAR '@'
640 /* This fills in the rest of the mt structure once it is determined that
641 * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
642 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
644 struct game_state_t fakeMove;
646 mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];
647 mt->enPassant = 0; /* Don't know yet, let execute move take care
649 if (mt->fromFile == ALG_DROP) {
650 mt->piecePromotionTo = NOPIECE;
651 sprintf(mt->moveString, "%s/%c%c-%c%d",
652 wpstring[mt->fromRank],
653 DROP_CHAR, DROP_CHAR,
654 mt->toFile + 'a', mt->toRank + 1);
656 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
657 ((mt->toRank == 0) || (mt->toRank == 7))) {
658 mt->piecePromotionTo = promote |
659 (colorval(gs->board[mt->fromFile][mt->fromRank]));
661 mt->piecePromotionTo = NOPIECE;
663 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
664 ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {
665 mt->doublePawn = mt->fromFile;
669 if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
670 (mt->fromFile == 4) && (mt->toFile == 2)) {
671 sprintf(mt->moveString, "o-o-o");
672 } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
673 (mt->fromFile == 4) && (mt->toFile == 6)) {
674 sprintf(mt->moveString, "o-o");
676 sprintf(mt->moveString, "%s/%c%d-%c%d",
677 wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],
678 mt->fromFile + 'a', mt->fromRank + 1,
679 mt->toFile + 'a', mt->toRank + 1);
682 /* Replace this with an algabraic de-parser */
684 sprintf(mt->algString, alg_unparse(gs, mt));
686 /* Calculates enPassant also */
687 execute_move(&fakeMove, mt, 0);
689 /* Does making this move leave ME in check? */
690 if (in_check(&fakeMove))
692 /* IanO: bughouse variants: drop cannot be check/checkmate */
697 int legal_andcheck_move(struct game_state_t * gs,
698 int fFile, int fRank,
699 int tFile, int tRank)
702 if (!legal_move(gs, fFile, fRank, tFile, tRank))
704 mt.color = gs->onMove;
709 /* This should take into account a pawn promoting to another piece */
710 if (move_calculate(gs, &mt, QUEEN) == MOVE_OK)
716 /* in_check: checks if the side that is NOT about to move is in check
718 int in_check(struct game_state_t * gs)
721 int kf = -1, kr = -1;
724 if (gs->onMove == WHITE) {
725 for (f = 0; f < 8 && kf < 0; f++)
726 for (r = 0; r < 8 && kf < 0; r++)
727 if (gs->board[f][r] == B_KING) {
732 for (f = 0; f < 8 && kf < 0; f++)
733 for (r = 0; r < 8 && kf < 0; r++)
734 if (gs->board[f][r] == W_KING) {
740 d_printf( "CHESSD: Error game with no king!\n");
743 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
744 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
745 if (legal_move(gs, f, r, kf, kr)) { /* In Check? */
752 int has_legal_move(struct game_state_t * gs)
757 int possiblef[500], possibler[500];
760 for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
761 NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
762 switch (piecetype(gs->board[f][r])) {
764 possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
767 possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
770 possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
773 possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
776 possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
781 possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
784 if (numpossible >= 500) {
785 d_printf( "CHESSD: Possible move overrun\n");
787 for (i = 0; i < numpossible; i++)
788 if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) {
793 /* IanO: if we got here, then kf and kr must be set */
794 if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0) {
795 /* bughouse: potential drops as check interpositions */
796 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;
797 for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {
798 if (f>=0 && f<8 && r>=0 && r<8 && gs->board[f][r] == NOPIECE) {
799 /* try a drop next to the king */
800 if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {
801 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
806 gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
812 /* This will end up being a very complicated function */
813 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
815 int type = is_move(mstr);
818 mt->piecePromotionTo = NOPIECE;
819 mt->color = gs->onMove;
825 mt->fromFile = mstr[0] - 'a';
826 mt->fromRank = mstr[1] - '1';
827 mt->toFile = mstr[2] - 'a';
828 mt->toRank = mstr[3] - '1';
831 mt->fromFile = mstr[0] - 'a';
832 mt->fromRank = mstr[1] - '1';
833 mt->toFile = mstr[3] - 'a';
834 mt->toRank = mstr[4] - '1';
839 if (gs->onMove == WHITE) {
850 if (gs->onMove == WHITE) {
859 /* Fills in the mt structure */
860 if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)
867 if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) {
871 if (mt->piecePromotionTo != NOPIECE) {
872 promote = piecetype(mt->piecePromotionTo);
875 return move_calculate(gs, mt, promote);
878 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
879 /* check_game_status prevents recursion */
880 int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_status)
886 if (mt->fromFile == ALG_DROP) {
887 movedPiece = mt->fromRank;
889 gs->holding[gs->onMove==WHITE ? 0 : 1][movedPiece-1]--;
890 gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
891 if (gs->gameNum >= 0)
892 gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
894 movedPiece = gs->board[mt->fromFile][mt->fromRank];
895 tookPiece = gs->board[mt->toFile][mt->toRank];
896 if (mt->piecePromotionTo == NOPIECE) {
897 gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
899 gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
901 gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
902 /* Check if irreversable */
903 if ((piecetype(movedPiece) == PAWN) || (tookPiece != NOPIECE)) {
904 if (gs->gameNum >= 0)
905 gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
907 /* Check if this move is en-passant */
908 if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
909 (tookPiece == NOPIECE)) {
910 if (gs->onMove == WHITE) {
911 mt->pieceCaptured = B_PAWN;
913 mt->pieceCaptured = W_PAWN;
915 if (mt->fromFile > mt->toFile) {
920 gs->board[mt->toFile][mt->fromRank] = NOPIECE;
922 /* Check en-passant flags for next moves */
923 for (i = 0; i < 8; i++) {
924 gs->ep_possible[0][i] = 0;
925 gs->ep_possible[1][i] = 0;
927 /* Added by Sparky 3/16/95
929 From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
930 Subject: Re: To DAV: enpassant prob. again
931 To: chess@caissa.onenet.net (ICS)
932 Date: Thu, 16 Mar 1995 20:06:20 +0100 (MET)
935 There was bug in other part of code:
937 movecheck.c , line about 800:
939 if (gs->onMove == WHITE) {
940 if ((mt->toFile+1 < 7 ) .... should be : (mt->toFile < 7 ) }
943 if ((piecetype(movedPiece) == PAWN) &&
944 ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {
945 /* Should turn on enpassent flag if possible */
946 if (gs->onMove == WHITE) {
947 if ((mt->toFile < 7) && gs->board[mt->toFile + 1][3] == B_PAWN) {
948 gs->ep_possible[1][mt->toFile + 1] = -1;
950 if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][3] == B_PAWN) {
951 gs->ep_possible[1][mt->toFile - 1] = 1;
954 if ((mt->toFile < 7) && gs->board[mt->toFile + 1][4] == W_PAWN) {
955 gs->ep_possible[0][mt->toFile + 1] = -1;
957 if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][4] == W_PAWN) {
958 gs->ep_possible[0][mt->toFile - 1] = 1;
962 if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 0)) {
963 if ((mt->fromRank == 0) && (gs->onMove == WHITE))
965 if ((mt->fromRank == 7) && (gs->onMove == BLACK))
968 if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 7)) {
969 if ((mt->fromRank == 0) && (gs->onMove == WHITE))
971 if ((mt->fromRank == 7) && (gs->onMove == BLACK))
974 if (piecetype(movedPiece) == KING) {
975 if (gs->onMove == WHITE)
980 if ((piecetype(movedPiece) == KING) &&
981 ((mt->fromFile == 4) && ((mt->toFile == 6)))) { /* Check for KS castling */
982 gs->board[5][mt->toRank] = gs->board[7][mt->toRank];
983 gs->board[7][mt->toRank] = NOPIECE;
985 if ((piecetype(movedPiece) == KING) &&
986 ((mt->fromFile == 4) && ((mt->toFile == 2)))) { /* Check for QS castling */
987 gs->board[3][mt->toRank] = gs->board[0][mt->toRank];
988 gs->board[0][mt->toRank] = NOPIECE;
991 if (gs->onMove == BLACK)
994 if (check_game_status) {
995 /* Does this move result in check? */
997 /* Check for checkmate */
998 gs->onMove = CToggle(gs->onMove);
999 if (!has_legal_move(gs))
1000 return MOVE_CHECKMATE;
1002 /* Check for stalemate */
1003 gs->onMove = CToggle(gs->onMove);
1004 if (!has_legal_move(gs))
1005 return MOVE_STALEMATE;
1006 /* loon: check for insufficient mating material, first try */
1008 for (i=0; i<8; i++) {
1009 for (j=0; j<8; j++) {
1010 switch(piecetype(gs->board[i][j])) {
1025 return MOVE_NOMATERIAL;
1028 gs->onMove = CToggle(gs->onMove);
1033 int backup_move(int g, int mode)
1035 struct game_state_t *gs;
1036 struct move_t *m, *m1;
1039 if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */
1040 return MOVE_ILLEGAL;
1041 if (game_globals.garray[g].numHalfMoves < 1)
1042 return MOVE_ILLEGAL;
1043 gs = &game_globals.garray[g].game_state;
1044 m = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] :
1045 &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
1046 if (m->toFile < 0) {
1047 return MOVE_ILLEGAL;
1049 gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
1050 if (m->piecePromotionTo != NOPIECE) {
1051 gs->board[m->fromFile][m->fromRank] = PAWN |
1052 colorval(gs->board[m->fromFile][m->fromRank]);
1055 When takeback a _first_ move of rook, the ??rmoved variable
1056 must be cleared . To check, if the move is first, we should
1058 *******************/
1059 if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
1060 if (m->color == WHITE) {
1061 if ((m->fromFile == 0) && (m->fromRank == 0)) {
1062 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1063 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1064 if ((m1->fromFile == 0) && (m1->fromRank == 0))
1067 if (i == game_globals.garray[g].numHalfMoves - 1)
1070 if ((m->fromFile == 7) && (m->fromRank == 0)) {
1071 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1072 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1073 if ((m1->fromFile == 7) && (m1->fromRank == 0))
1076 if (i == game_globals.garray[g].numHalfMoves - 1)
1080 if ((m->fromFile == 0) && (m->fromRank == 7)) {
1081 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1082 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1083 if ((m1->fromFile == 0) && (m1->fromRank == 0))
1086 if (i == game_globals.garray[g].numHalfMoves - 1)
1089 if ((m->fromFile == 7) && (m->fromRank == 7)) {
1090 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1091 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1092 if ((m1->fromFile == 7) && (m1->fromRank == 0))
1095 if (i == game_globals.garray[g].numHalfMoves - 1)
1100 if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
1101 gs->board[m->toFile][m->toRank] = m->pieceCaptured;
1103 if (m->toFile - m->fromFile == 2) {
1104 gs->board[7][m->fromRank] = ROOK |
1105 colorval(gs->board[m->fromFile][m->fromRank]);
1106 gs->board[5][m->fromRank] = NOPIECE;
1109 If takeback a castling, the appropriates ??moved variables
1112 if (m->color == WHITE) {
1121 if (m->fromFile - m->toFile == 2) {
1122 gs->board[0][m->fromRank] = ROOK |
1123 colorval(gs->board[m->fromFile][m->fromRank]);
1124 gs->board[3][m->fromRank] = NOPIECE;
1127 If takeback a castling, the appropriate ??moved variables
1130 if (m->color == WHITE) {
1140 When takeback a _first_ move of king (not the castling),
1141 the ?kmoved variable must be cleared . To check, if the move is first,
1142 we should scan moveList.
1143 *******************/
1145 if (m->color == WHITE) {
1147 if ((m->fromFile == 4) && (m->fromRank == 0)) {
1148 for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1149 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1150 if ((m1->fromFile == 4) && (m1->fromRank == 0))
1153 if (i == game_globals.garray[g].numHalfMoves - 1)
1157 if ((m->fromFile == 4) && (m->fromRank == 7)) {
1158 for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1159 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1160 if ((m1->fromFile == 4) && (m1->fromRank == 7))
1163 if (i == game_globals.garray[g].numHalfMoves - 1)
1168 if (m->enPassant) { /* Do enPassant */
1169 gs->board[m->toFile][m->fromRank] = PAWN |
1170 (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
1171 gs->board[m->toFile][m->toRank] = NOPIECE;
1172 /* Should set the enpassant array, but I don't care right now */
1175 gs->board[m->toFile][m->toRank] = m->pieceCaptured;
1177 if (game_globals.garray[g].status != GAME_EXAMINE) {
1178 game_update_time(g);
1180 game_globals.garray[g].numHalfMoves--;
1181 if (game_globals.garray[g].status != GAME_EXAMINE) {
1182 if (game_globals.garray[g].wInitTime) { /* Don't update times in untimed games */
1185 if (m->color == WHITE) {
1186 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* white uses timeseal? */
1187 game_globals.garray[g].wRealTime += (m->tookTime * 100);
1188 game_globals.garray[g].wRealTime -= (game_globals.garray[g].wIncrement * 100);
1189 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1190 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
1191 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1192 } else { /* opp has no timeseal */
1193 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1195 } else { /* white has no timeseal */
1196 game_globals.garray[g].wTime += m->tookTime;
1197 game_globals.garray[g].wTime -= game_globals.garray[g].wIncrement;
1198 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
1199 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1200 } else { /* opp has no timeseal */
1201 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1205 if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* black uses timeseal? */
1206 game_globals.garray[g].bRealTime += (m->tookTime * 100);
1207 game_globals.garray[g].bRealTime -= (game_globals.garray[g].wIncrement * 100);
1208 game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1209 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
1210 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1211 } else { /* opp has no timeseal */
1212 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1214 } else { /* black has no timeseal */
1215 game_globals.garray[g].bTime += m->tookTime;
1216 if (!game_globals.garray[g].bIncrement)
1217 game_globals.garray[g].bTime -= game_globals.garray[g].wIncrement;
1219 game_globals.garray[g].bTime -= game_globals.garray[g].bIncrement;
1220 if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
1221 game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1222 } else { /* opp has no timeseal */
1223 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1228 if (game_globals.garray[g].numHalfMoves == 0)
1229 game_globals.garray[g].timeOfStart = now;
1230 game_globals.garray[g].lastMoveTime = now;
1231 game_globals.garray[g].lastDecTime = now;
1234 if (gs->onMove == BLACK)
1241 /******* Here begins the patch : ********************************
1242 Takeback of last move is done already, it's time to update enpassant
1243 array. (patch from Soso, added by Sparky 3/17/95)
1246 if (game_globals.garray[g].numHalfMoves > 0) {
1247 m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] :
1248 &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
1249 if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {
1250 if ((m1->toRank - m1->fromRank) == 2) {
1251 if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) {
1252 gs->ep_possible[1][m1->toFile + 1] = -1;
1254 if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) {
1255 gs->ep_possible[1][m1->toFile - 1] = 1;
1258 if ((m1->toRank - m1->fromRank) == -2) {
1259 if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) {
1260 gs->ep_possible[0][m1->toFile + 1] = -1;
1262 if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) {
1263 gs->ep_possible[0][m1->toFile - 1] = 1;
1268 /************** and here's the end **************/