Logo Search packages:      
Sourcecode: yics version File versions  Download package

movecheck.c

/*
 * YICS: Connect a FICS interface to the Yahoo! Chess server.
 * Copyright (C) 2004  Chris Howie
 *
 * This file is derived from the public FICS sources (movecheck.c).
 * Copyright (C) 1993  Richard V. Nash
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/* (crazycomputers) I've cleaned up the FICS sources a lot.  Indentation and
 * spacing between operators should be consistent now. */

#include <stdio.h>
#include <string.h>
#include "movecheck.h"
#include "types.h"

char *wpstring[] = {" ", "P", "N", "B", "R", "Q", "K"};
char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"};

int NextPieceLoop(Board b, int *f, int *r, int color) {
      for (;;) {
            (*r) = (*r) + 1;

            if (*r > 7) {
                  *r = 0;
                  *f = *f + 1;
                  if (*f > 7)
                        break;
            }

            if ((b[*f][*r] != EMPTY) && iscolor(b[*f][*r], color))
                  return 1;
      }

      return 0;
}

int InitPieceLoop(Board b, int *f, int *r, int color) {
      *f = 0;
      *r = -1;
      return 1;
}

/* All of the routines assume that the obvious problems have been checked */
/* See legal_move() */
int legal_pawn_move(Game *gs, int ff, int fr, int tf, int tr) {
      if (ff == tf) {
            if (gs->board[tf][tr] != EMPTY)
                  return 0;
            if (gs->turn == WHITE) {
                  if (tr - fr == 1)
                        return 1;
                  if ((fr == 1) && (tr - fr == 2) && (gs->board[ff][2] == EMPTY))
                        return 1;
            } else {
                  if (fr - tr == 1)
                        return 1;
                  if ((fr == 6) && (fr - tr == 2) && (gs->board[ff][5] == EMPTY))
                        return 1;
            }
            return 0;
      } else { /* Capture ? */
            if ((ff - tf != 1) && (tf - ff != 1))
                  return 0;
            if ((fr - tr != 1) && (tr - fr != 1))
                  return 0;
            if (gs->turn == WHITE) {
                  if (fr > tr)
                        return 0;
                  if ((gs->board[tf][tr] != EMPTY) &&
                              iscolor(gs->board[tf][tr], BLACK))
                        return 1;
                  if (gs->dpush == tf) {
                        if (gs->board[tf][fr] == B_PAWN)
                              return 1;
                  }
            } else {
                  if (tr > fr)
                        return 0;
                  if ((gs->board[tf][tr] != EMPTY) && iscolor(gs->board[tf][tr], WHITE))
                        return 1;
                  if (gs->dpush == tf) {
                        if (gs->board[tf][fr] == W_PAWN)
                              return 1;
                  }
            }
      }
      return 0;
}

int legal_knight_move(Game *gs, int ff, int fr, int tf, int tr) {
      int dx, dy;

      dx = ff - tf;
      dy = fr - tr;

      if ((dx == 2) || (dx == -2)) {
            if ((dy == -1) || (dy == 1))
                  return 1;
      }

      if ((dy == 2) || (dy == -2)) {
            if ((dx == -1) || (dx == 1))
                  return 1;
      }

      return 0;
}

int legal_bishop_move(Game *gs, int ff, int fr, int tf, int tr) {
      int dx, dy, x, y;
      int startx, starty;
      int count;
      int incx, incy;

      if (ff > tf) {
            dx = ff - tf;
            incx = -1;
      } else {
            dx = tf - ff;
            incx = 1;
      }

      startx = ff + incx;
      if (fr > tr) {
            dy = fr - tr;
            incy = -1;
      } else {
            dy = tr - fr;
            incy = 1;
      }

      starty = fr + incy;
      if (dx != dy)
            return 0;   /* Not diagonal */
      if (dx == 1)
            return 1;   /* One square, ok */

      count = dx - 1;
      for (x = startx, y = starty; count; x += incx, y += incy, count--) {
            if (gs->board[x][y] != EMPTY)
                  return 0;
      }

      return 1;
}

int legal_rook_move(Game *gs, int ff, int fr, int tf, int tr) {
      int i;
      int start, stop;

      if (ff == tf) {
            if (((fr - tr) == 1) || ((tr - fr) == 1))
                  return 1;

            if (fr < tr) {
                  start = fr + 1;
                  stop = tr - 1;
            } else {
                  start = tr + 1;
                  stop = fr - 1;
            }

            for (i = start; i <= stop; i++) {
                  if (gs->board[ff][i] != EMPTY)
                        return 0;
            }

            return 1;
      } else if (fr == tr) {
            if (((ff - tf) == 1) || ((tf - ff) == 1))
                  return 1;

            if (ff < tf) {
                  start = ff + 1;
                  stop = tf - 1;
            } else {
                  start = tf + 1;
                  stop = ff - 1;
            }

            for (i = start; i <= stop; i++) {
                  if (gs->board[i][fr] != EMPTY)
                        return 0;
            }

            return 1;
      }

      return 0;
}

/* (crazycomputers) Why wasn't this a macro in the first place?  =/ */
#define legal_queen_move(gs, ff, fr, tf, tr) \
      (legal_rook_move((gs), (ff), (fr), (tf), (tr)) || \
       legal_bishop_move((gs), (ff), (fr), (tf), (tr)))

#if 0
int legal_queen_move(game_state_t *gs, int ff, int fr, int tf, int tr) {
      return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
}
#endif


/* Ckeck, if square (kf,kr) is attacked by enemy piece.
 * Used in castling from/through check testing.
 */

/* new one from soso: */
int is_square_attacked (Game *gs, int kf, int kr) {
      Game fakeMove;

      fakeMove = *gs;
      fakeMove.movelist = NULL;
      fakeMove.repetitions = NULL;
      fakeMove.board[4][kr] = EMPTY;
      fakeMove.board[kf][kr] = (Piece)(KING | fakeMove.turn);
      fakeMove.turn = CToggle(fakeMove.turn);

      /* (crazycomputers) Haha, gotta love redundant code!  =)  Original:

            if (in_check(&fakeMove)) return 1;
            else return 0;

      Let's try this instead... */

      return in_check(&fakeMove);
}

int legal_king_move(Game *gs, int ff, int fr, int tf, int tr) {
      if (gs->turn == WHITE) {
            /* King side castling */
            if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && gs->castlewh
                  && (gs->board[5][0] == EMPTY) && (gs->board[6][0] == EMPTY) &&
                  (gs->board[7][0] == W_ROOK) &&
                  (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) {
                        return 1;
            }

            /* Queen side castling */
            if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && gs->castlewa
                  && (gs->board[3][0] == EMPTY) && (gs->board[2][0] == EMPTY) &&
                  (gs->board[1][0] == EMPTY) && (gs->board[0][0] == W_ROOK) &&
                  (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) {
                        return 1;
            }
      } else {    /* Black */
            /* King side castling */
            if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && gs->castlebh
                  && (gs->board[5][7] == EMPTY) && (gs->board[6][7] == EMPTY) &&
                  (gs->board[7][7] == B_ROOK) &&
                  (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) {
                        return 1;
            }

            /* Queen side castling */
            if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && gs->castleba
                  && (gs->board[3][7] == EMPTY) && (gs->board[2][7] == EMPTY) &&
                  (gs->board[1][7] == EMPTY) && (gs->board[0][7] == B_ROOK) &&
                  (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) {
                        return 1;
            }
      }

      if (((ff - tf) > 1) || ((tf - ff) > 1))
            return 0;

      if (((fr - tr) > 1) || ((tr - fr) > 1))
            return 0;

      return 1;
}

void add_pos(int tof, int tor, int *posf, int *posr, int *numpos) {
      posf[*numpos] = tof;
      posr[*numpos] = tor;
      (*numpos)++;
}

void possible_pawn_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      if (gs->turn == WHITE) {
            if (gs->board[onf][onr + 1] == EMPTY) {
                  add_pos(onf, onr + 1, posf, posr, numpos);
                  if ((onr == 1) && (gs->board[onf][onr + 2] == EMPTY))
                        add_pos(onf, onr + 2, posf, posr, numpos);
            }
            if ((onf > 0) && (gs->board[onf - 1][onr + 1] != EMPTY) &&
                  (iscolor(gs->board[onf - 1][onr + 1], BLACK)))
                        add_pos(onf - 1, onr + 1, posf, posr, numpos);
            if ((onf < 7) && (gs->board[onf + 1][onr + 1] != EMPTY) &&
                  (iscolor(gs->board[onf + 1][onr + 1], BLACK)))
                        add_pos(onf + 1, onr + 1, posf, posr, numpos);
            if (gs->dpush != -1) {
                  if ((onf - gs->dpush) == -1)
                        add_pos(onf + 1, onr + 1, posf, posr, numpos);
                  else if ((onf - gs->dpush) == 1)
                        add_pos(onf - 1, onr + 1, posf, posr, numpos);
            }
      } else {
            if (gs->board[onf][onr - 1] == EMPTY) {
                  add_pos(onf, onr - 1, posf, posr, numpos);
                  if ((onr == 6) && (gs->board[onf][onr - 2] == EMPTY))
                        add_pos(onf, onr - 2, posf, posr, numpos);
            }
            if ((onf > 0) && (gs->board[onf - 1][onr - 1] != EMPTY) &&
                  (iscolor(gs->board[onf - 1][onr - 1], WHITE)))
                        add_pos(onf - 1, onr - 1, posf, posr, numpos);
            if ((onf < 7) && (gs->board[onf + 1][onr - 1] != EMPTY) &&
                  (iscolor(gs->board[onf + 1][onr - 1], WHITE)))
                        add_pos(onf + 1, onr - 1, posf, posr, numpos);
            if (gs->dpush != -1) {
                  if ((onf - gs->dpush) == -1)
                        add_pos(onf + 1, onr - 1, posf, posr, numpos);
                  else if ((onf - gs->dpush) == 1)
                        add_pos(onf - 1, onr - 1, posf, posr, numpos);
            }
      }
}

void possible_knight_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      static int knightJumps[8][2] = {
            {-1,  2},
            { 1,  2},
            { 2, -1},
            { 2,  1},
            {-1, -2},
            { 1, -2},
            {-2,  1},
            {-2, -1}
      };
      int f, r;
      int j;

      for (j = 0; j < 8; j++) {
            f = knightJumps[j][0] + onf;
            r = knightJumps[j][1] + onr;
            if ((f < 0) || (f > 7))
                  continue;
            if ((r < 0) || (r > 7))
                  continue;
            if ((gs->board[f][r] == EMPTY) ||
                  (iscolor(gs->board[f][r], CToggle(gs->turn))))
                        add_pos(f, r, posf, posr, numpos);
      }
}

void possible_bishop_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      static const int bishopJumps[4][2] = {
            {-1,  1},
            { 1,  1},
            {-1, -1},
            { 1, -1}
      };
      int f, r, i;

      for (i = 0; i < 4; i++) {
            f = onf;
            r = onr;
            for (;;) {
                  f += bishopJumps[i][0];
                  r += bishopJumps[i][1];
                  if ((f < 0) || (f > 7))
                        break;
                  if ((r < 0) || (r > 7))
                        break;
                  if ((gs->board[f][r] != EMPTY) && (iscolor(gs->board[f][r], gs->turn)))
                        break;
                  add_pos(f, r, posf, posr, numpos);
                  if (gs->board[f][r] != EMPTY)
                        break;
            }
      }
}

void possible_rook_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      static const int rookJumps[4][2] = {
            {-1,  0},
            { 1,  0},
            { 0, -1},
            { 0,  1}
      };
      int f, r, i;

      for (i = 0; i < 4; i++) {
            f = onf;
            r = onr;
            for (;;) {
                  f += rookJumps[i][0];
                  r += rookJumps[i][1];
                  if ((f < 0) || (f > 7))
                        break;
                  if ((r < 0) || (r > 7))
                        break;
                  if ((gs->board[f][r] != EMPTY) && (iscolor(gs->board[f][r], gs->turn)))
                        break;
                  add_pos(f, r, posf, posr, numpos);
                  if (gs->board[f][r] != EMPTY)
                        break;
            }
      }
}

/* (crazycomputers) Another macro candidate... */
#define possible_queen_moves(gs, onf, onr, posf, posr, numpos) \
      possible_rook_moves((gs), (onf), (onr), (posf), (posr), (numpos)); \
      possible_bishop_moves((gs), (onf), (onr), (posf), (posr), (numpos));

/*void possible_queen_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      possible_rook_moves(gs, onf, onr, posf, posr, numpos);
      possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
} */



void possible_king_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) {
      static const int kingJumps[8][2] = {
            {-1, -1}, 
            { 0, -1},
            { 1, -1},
            {-1,  1},
            { 0,  1},
            { 1,  1},
            {-1,  0},
            { 1,  0}
      };
      int f, r;
      int j;

      for (j = 0; j < 8; j++) {
            f = kingJumps[j][0] + onf;
            r = kingJumps[j][1] + onr;
            if ((f < 0) || (f > 7))
                  continue;
            if ((r < 0) || (r > 7))
                  continue;
            if ((gs->board[f][r] == EMPTY) ||
                  (iscolor(gs->board[f][r], CToggle(gs->turn))))
                        add_pos(f, r, posf, posr, numpos);
      }
}

/* Doesn't check for check */
int legal_move(Game *gs, int fFile, int fRank,int tFile, int tRank) {
      int move_piece;

      /* (crazycomputers) Removed bughouse code. */

      move_piece = piecetype(gs->board[fFile][fRank]);

      if (gs->board[fFile][fRank] == EMPTY)
            return 0;

      if (!iscolor(gs->board[fFile][fRank], gs->turn))      /* Wrong color */
            return 0;

      if ((gs->board[tFile][tRank] != EMPTY) &&
            iscolor(gs->board[tFile][tRank], gs->turn))     /* Can't capture own */
                  return 0;

      if ((fFile == tFile) && (fRank == tRank)) /* Same square */
            return 0;

      switch (move_piece) {
      case PAWN:
            return legal_pawn_move(gs, fFile, fRank, tFile, tRank);
      case KNIGHT:
            return legal_knight_move(gs, fFile, fRank, tFile, tRank);
      case BISHOP:
            return legal_bishop_move(gs, fFile, fRank, tFile, tRank);
      case ROOK:
            return legal_rook_move(gs, fFile, fRank, tFile, tRank);
      case QUEEN:
            return legal_queen_move(gs, fFile, fRank, tFile, tRank);
      case KING:
            return legal_king_move(gs, fFile, fRank, tFile, tRank);
      default:
            return 0;
      }
}

/* Based on alg_unparse from algcheck.c of the public FICS sources. */
static void alg_unparse(Game *game, Move *move) {
      int piece = piecetype(game->board[move->x1][move->y1]);
      bool ambig, ambig_x, ambig_y;
      uchar x, y;
      Game fakeMove;
      char *out = move->alg;

      /*
       * Longest output:
       *
       *  Castling (6): O-O-O+
       * Ambiguous (7): Re1xe2+
       * Promotion (7): exf8=Q+
       *
       * So we need 8 bytes for an alg string.
       */
      if ((piece == KING) && (move->x1 == 4) && ((move->x2 == 6) || (move->x2 == 2))) {
            strcpy(out, (move->x2 == 6) ? "O-O" : "O-O-O");
            while (*(++out) != '\0');
      } else {
            switch (piece) {
            case PAWN:
                  if (move->x1 != move->x2)
                        *(out++) = move->x1 + 'a';
                  break;

            case KNIGHT:
                  *(out++) = 'N';
                  break;

            case BISHOP:
                  *(out++) = 'B';
                  break;

            case ROOK:
                  *(out++) = 'R';
                  break;

            case QUEEN:
                  *(out++) = 'Q';
                  break;

            case KING:
                  *(out++) = 'K';
                  break;
            }

            if (piece != PAWN) {
                  ambig = false;
                  ambig_x = false;
                  ambig_y = false;

                  for (x = 0; x < 8; x++) {
                        for (y = 0; y < 8; y++) {
                              if (((x != move->x1) || (y != move->y1)) &&
                              (game->board[x][y] != EMPTY) &&
                              iscolor(game->board[x][y], game->turn) &&
                              (piecetype(game->board[x][y]) == piece) &&
                              legal_move(game, x, y, move->x2, move->y2)) {
                                    game->turn = CToggle(game->turn);
                                    fakeMove = *game;
                                    fakeMove.board[x][y] = EMPTY;

                                    /*
                                     * This is in algparse.c...
                                     * what does it do?!
                                     */
                                    /* if (in_check(game) || !in_check(&fakeMove))
                                          ambig = true; */

                                    ambig = true;
                                    if (x == move->x1)
                                          ambig_x = true;
                                    if (y == move->y1)
                                          ambig_y = true;

                                    game->turn = CToggle(game->turn);
                              }
                        }
                  }

                  if (ambig) {
                        if (!ambig_x)
                              *(out++) = move->x1 + 'a';
                        else if (!ambig_y)
                              *(out++) = move->y1 + '1';
                        else {
                              *(out++) = move->x1 + 'a';
                              *(out++) = move->y1 + '1';
                        }
                  }
            }

            if (game->board[move->x2][move->y2] != EMPTY)
                  *(out++) = 'x';

            *(out++) = move->x2 + 'a';
            *(out++) = move->y2 + '1';

            if (move->promoteTo != EMPTY) {
                  *(out++) = '=';
                  *(out++) = *wpstring[move->promoteTo];
            }
      }

      fakeMove = *game;
      execute_move(&fakeMove, move, 0);
      fakeMove.turn = CToggle(fakeMove.turn);
      if (in_check(&fakeMove))
            *(out++) = '+';

      *out = '\0';
}

int move_calculate(Game *gs, Move *move, int promote) {
      Game fakeMove;

      move->promoteTo = ((piecetype(gs->board[move->x1][move->y1]) == PAWN)
                  && ((move->y2 != 0) || (move->y2 != 7))) ? promote : EMPTY; 

      if ((piecetype(gs->board[move->x1][move->y1]) == KING) &&
            (move->x1 == 4) && ((move->x2 == 2) || (move->x2 == 6))) {
            sprintf(move->desc, (move->x2 == 6) ? "o-o" : "o-o-o");
      } else {
            snprintf(move->desc, sizeof(move->desc), "%c/%c%c-%c%c",
                        *wpstring[piecetype(gs->board[move->x1][move->y1])],
                        move->x1 + 'a', move->y1 + '1',
                        move->x2 + 'a', move->y2 + '1');

            if (move->promoteTo != EMPTY) {
                  move->desc[7] = '=';
                  move->desc[8] = *wpstring[move->promoteTo];
                  move->desc[9] = '\0';
            }
      }

      alg_unparse(gs, move);

      fakeMove = *gs;

      /* Just in case */
      fakeMove.movelist = NULL;
      fakeMove.repetitions = NULL;

      /* Calculates enPassant also */
      execute_move(&fakeMove, move, 0);

      /* Does making this move leave ME in check? */
      return in_check(&fakeMove) ? MOVE_ILLEGAL : MOVE_OK;
}

int legal_andcheck_move(Game *gs, int fFile, int fRank, int tFile, int tRank) {
      Move move;

      if (!legal_move(gs, fFile, fRank, tFile, tRank))
            return 0;

      move.x1 = fFile;
      move.y1 = fRank;
      move.x2 = tFile;
      move.y2 = tRank;

      /* This should take into account a pawn promoting to another piece */
      return (move_calculate(gs, &move, QUEEN) == MOVE_OK) ? 1 : 0;
}

/* in_check: checks if the side that is NOT about to move is in check 
 */
int in_check(Game *gs) {
      int f, r;
      int kf = -1, kr = -1;
      Piece target = (Piece)(KING | CToggle(gs->turn));

      /* Find the king */
      for (f = 0; f < 8 && kf < 0; f++) {
            for (r = 0; r < 8 && kf < 0; r++) {
                  if (gs->board[f][r] == target) {
                        kf = f;
                        kr = r;
                  }
            }
      }

      if (kf < 0)
            return 0;

      for (InitPieceLoop(gs->board, &f, &r, gs->turn);
            NextPieceLoop(gs->board, &f, &r, gs->turn);) {
                  if (legal_move(gs, f, r, kf, kr))   /* In Check? */
                        return 1;
      }

      return 0;
}

int has_legal_move(Game *gs) {
      int i;
      int f, r;
      int possiblef[500], possibler[500];
      int numpossible = 0;

      for (InitPieceLoop(gs->board, &f, &r, gs->turn);
                  NextPieceLoop(gs->board, &f, &r, gs->turn);) {
            switch (piecetype(gs->board[f][r])) {
            case PAWN:
                  possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
                  break;
            case KNIGHT:
                  possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
                  break;
            case BISHOP:
                  possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
                  break;
            case ROOK:
                  possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
                  break;
            case QUEEN:
                  possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
                  break;
            case KING:
                  possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
            }

            for (i = 0; i < numpossible; i++)
                  if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i]))
                        return 1;
      }

      return 0;
}

/* This will end up being a very complicated function */
/* (crazycomputers) And an unneeded one here -- we have our own parsing, */
#if 0
int parse_move(char *mstr, game_state_t * gs, move_t * mt, int promote)
{
  int type = is_move(mstr);
  int result;

  mt->color = gs->turn;
  switch (type) {
  case MS_NOTMOVE:
    return MOVE_ILLEGAL;
    break;
  case MS_COMP:
    mt->fromFile = mstr[0] - 'a';
    mt->fromRank = mstr[1] - '1';
    mt->toFile = mstr[2] - 'a';
    mt->toRank = mstr[3] - '1';
    break;
  case MS_COMPDASH:
    mt->fromFile = mstr[0] - 'a';
    mt->fromRank = mstr[1] - '1';
    mt->toFile = mstr[3] - 'a';
    mt->toRank = mstr[4] - '1';
    break;
  case MS_KCASTLE:
    mt->fromFile = 4;
    mt->toFile = 6;
    if (gs->turn == WHITE) {
      mt->fromRank = 0;
      mt->toRank = 0;
    } else {
      mt->fromRank = 7;
      mt->toRank = 7;
    }
    break;
  case MS_QCASTLE:
    mt->fromFile = 4;
    mt->toFile = 2;
    if (gs->turn == WHITE) {
      mt->fromRank = 0;
      mt->toRank = 0;
    } else {
      mt->fromRank = 7;
      mt->toRank = 7;
    }
    break;
  case MS_ALG:
    /* Fills in the mt structure */
    if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)
      return result;
    break;
  default:
    return MOVE_ILLEGAL;
    break;
  }
  if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) {
    return MOVE_ILLEGAL;
  }
  return move_calculate(gs, mt, promote);
}
#endif

/* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
/* check_game_status prevents recursion */
int execute_move(Game *gs, Move *move, int check_game_status) {
      Piece movedPiece;
      Piece tookPiece;
      int i, j, foobar;

/* I'd rather do this than make the code unreadable. */
#define fromFile (move->x1)
#define fromRank (move->y1)
#define toFile (move->x2)
#define toRank (move->y2)

      /* (crazycomputers) Removed bughouse code. */

      movedPiece = gs->board[fromFile][fromRank];
      tookPiece = gs->board[toFile][toRank];
      gs->board[toFile][toRank] = (move->promoteTo == EMPTY) ?
            gs->board[fromFile][fromRank] : (move->promoteTo | gs->turn);
      gs->board[fromFile][fromRank] = EMPTY;

      /* Check if irreversable */
      if ((piecetype(movedPiece) == PAWN) || (tookPiece != EMPTY))
            gs->lastirrev = gs->halfmoves;

      /* Check if this move is en-passant */
      if ((piecetype(movedPiece) == PAWN) && (fromFile != toFile) &&
                  (tookPiece == EMPTY))
            gs->board[toFile][fromRank] = EMPTY;

      gs->dpush = ((piecetype(movedPiece) == PAWN) &&
                  ((fromRank == toRank + 2) ||
                  (fromRank + 2 == toRank))) ? fromFile : -1;

      if ((piecetype(movedPiece) == ROOK) && (fromFile == 0)) {
            if ((fromRank == 0) && (gs->turn == WHITE))
                  gs->castlewa = 0;
            else if ((fromRank == 7) && (gs->turn == BLACK))
                  gs->castleba = 0;
      } else if ((piecetype(movedPiece) == ROOK) && (fromFile == 7)) {
            if ((fromRank == 0) && (gs->turn == WHITE))
                  gs->castlewh = 0;
            else if ((fromRank == 7) && (gs->turn == BLACK))
                  gs->castlebh = 0;
      } else if (piecetype(movedPiece) == KING) {
            if (gs->turn == WHITE)
                  gs->castlewa = gs->castlewh = 0;
            else
                  gs->castleba = gs->castlebh = 0;
      }

      if ((piecetype(movedPiece) == KING) &&
                  ((fromFile == 4) && ((toFile == 6)))) {   /* Check for KS castling */
            gs->board[5][toRank] = gs->board[7][toRank];
            gs->board[7][toRank] = EMPTY;
      }
      if ((piecetype(movedPiece) == KING) &&
                  ((fromFile == 4) && ((toFile == 2)))) {   /* Check for QS castling */
            gs->board[3][toRank] = gs->board[0][toRank];
            gs->board[0][toRank] = EMPTY;
      }

      if (check_game_status) {
            /* Does this move result in check? */
            if (in_check(gs)) {
                  /* Check for checkmate */
                  gs->turn = CToggle(gs->turn);
                  if (!has_legal_move(gs))
                        return MOVE_CHECKMATE;
            } else {
                  /* Check for stalemate */
                  gs->turn = CToggle(gs->turn);
                  if (!has_legal_move(gs))
                        return MOVE_STALEMATE;
                  /* loon: check for insufficient mating material, first try */
                  foobar = 0;
                  for (i = 0; i < 8; i++) {
                        for (j = 0; j < 8; j++) {
                              switch(piecetype(gs->board[i][j])) {
                              case KNIGHT:
                              case BISHOP:
                                    foobar++;
                                    break;
                              case KING:
                              case EMPTY:
                                    break;
                              default:
                                    foobar = 2;
                              }
                        }
                  }
                  if (foobar < 2)
                        return MOVE_NOMATERIAL;
            }
      } else {
            gs->turn = CToggle(gs->turn);
      }

      return MOVE_OK;

#undef fromFile
#undef fromRank
#undef toFile
#undef toRank
}

/* (crazycomputers) I'll worry about this one later. */
#if 0
int backup_move(int g, int mode) {
      game_state_t *gs;
      move_t *m, *m1;
      int now, i;

      if (garray[g].numHalfMoves < 1)
            return MOVE_ILLEGAL;
      gs = &garray[g].game_state;
      m = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : 
            &garray[g].examMoveList[garray[g].numHalfMoves - 1];
      if (m->toFile < 0)
            return MOVE_ILLEGAL;
      gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
      if (m->piecePromotionTo != NOPIECE) {
            gs->board[m->fromFile][m->fromRank] = PAWN |
                  colorval(gs->board[m->fromFile][m->fromRank]);
      }
      /******************
            When takeback a _first_ move of rook, the ??rmoved variable
            must be cleared . To check, if the move is first, we should
            scan moveList.
      *******************/
      if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
            if (m->color == WHITE) {
                  if ((m->fromFile == 0) && (m->fromRank == 0)) {
                        for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 0) && (m1->fromRank == 0))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->wqrmoved = 0;
                  }
                  if ((m->fromFile == 7) && (m->fromRank == 0)) {
                        for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 7) && (m1->fromRank == 0))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->wkrmoved = 0;
                  }
            } else {
                  if ((m->fromFile == 0) && (m->fromRank == 7)) {
                        for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 0) && (m1->fromRank == 0))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->bqrmoved = 0;
                  }
                  if ((m->fromFile == 7) && (m->fromRank == 7)) {
                        for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 7) && (m1->fromRank == 0))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->bkrmoved = 0;
                  }
            }
      }

      if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
            gs->board[m->toFile][m->toRank] = m->pieceCaptured;

            if (m->toFile - m->fromFile == 2) {
                  gs->board[7][m->fromRank] = ROOK |
                        colorval(gs->board[m->fromFile][m->fromRank]);
                  gs->board[5][m->fromRank] = NOPIECE;

                  /********
                        If takeback a castling, the appropriates ??moved variables
                        must be cleared
                  ********/
                  if (m->color == WHITE) {
                        gs->wkmoved = 0;
                        gs->wkrmoved = 0;
                  } else {
                        gs->bkmoved = 0;
                        gs->bkrmoved = 0;
                  }

                  goto cleanupMove;
            }
            if (m->fromFile - m->toFile == 2) {
                  gs->board[0][m->fromRank] = ROOK |
                        colorval(gs->board[m->fromFile][m->fromRank]);
                  gs->board[3][m->fromRank] = NOPIECE;

                  /**********
                        If takeback a castling, the appropriate ??moved variables
                        must be cleared
                  ***********/
                  if (m->color == WHITE) {
                        gs->wkmoved = 0;
                        gs->wqrmoved = 0;
                  } else {
                        gs->bkmoved = 0;
                        gs->bqrmoved = 0;
                  }

                  goto cleanupMove;
            }

            /******************
                  When takeback a _first_ move of king (not the castling),
                  the ?kmoved variable must be cleared . To check, if the move is first,
                  we should scan moveList.
            *******************/

            if (m->color == WHITE) {
                  if ((m->fromFile == 4) && (m->fromRank == 0)) {
                        for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 4) && (m1->fromRank == 0))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->wkmoved = 0;
                  }
            } else {
                  if ((m->fromFile == 4) && (m->fromRank == 7)) {
                        for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) {
                              m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i];
                              if ((m1->fromFile == 4) && (m1->fromRank == 7))
                                    break;
                        }
                        if (i == garray[g].numHalfMoves - 1)
                              gs->bkmoved = 0;
                  }
            }
      }

      if (m->enPassant) {           /* Do enPassant */
            gs->board[m->toFile][m->fromRank] = PAWN |
                  (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
            gs->board[m->toFile][m->toRank] = NOPIECE;
            goto cleanupMove;
      }

      gs->board[m->toFile][m->toRank] = m->pieceCaptured;
cleanupMove:
      garray[g].numHalfMoves--;

      if (gs->turn == BLACK)
            gs->turn = WHITE;
      else {
            gs->turn = BLACK;
            gs->moveNum--;
      }

      if (garray[g].numHalfMoves > 0) {
            m1 = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : 
                  &garray[g].examMoveList[garray[g].numHalfMoves - 1];
            if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {
                  if ((m1->toRank - m1->fromRank) == 2) {
                        if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) {
                              gs->ep_possible[1][m1->toFile + 1] = -1;
                        }
                        if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) {
                              gs->ep_possible[1][m1->toFile - 1] = 1;
                        }
                  }
                  if ((m1->toRank - m1->fromRank) == -2) {
                        if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) {
                              gs->ep_possible[0][m1->toFile + 1] = -1;
                        }
                        if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) {
                              gs->ep_possible[0][m1->toFile - 1] = 1;
                        }
                  }
            }
      }

      /************** and here's the end **************/
      return MOVE_OK;
}
#endif

Generated by  Doxygen 1.6.0   Back to index