CPW-Engine move(0x88)

From Chessprogramming wiki
Jump to: navigation, search

Home * Engines * CPW-Engine * Move(0x88)

Both move_make and move_unmake call the functions fillSq(color, piece, square) and clearSq(square). They are meant to encapsulate all the incremental updates(material and pcsq calues, hash keys etc.) and can be viewed in CPW-Engine_board(0x88).Ideally this will make both make and unmake functions independent from the board representation. Beside that, incremental update code will be rather long, if not necessarily ugly.

Code

#include "stdafx.h"
#include "transposition.h"

int move_makeNull() {
  b.stm = !b.stm;
  b.hash ^= zobrist.color;
  b.ply++;
  if (b.ep != -1) {
    b.hash ^= zobrist.ep[b.ep];
    b.ep = -1;
  }
  return 0;
}

int move_unmakeNull(char ep) {
  b.stm = !b.stm;
  b.hash ^= zobrist.color;
  b.ply--;
  if (ep != -1) {
    b.hash ^= zobrist.ep[ep];
    b.ep = ep;
  }
  return 0;
}

int move_make(smove move) {

  /* switch the side to move */
  b.stm = !b.stm;
  b.hash ^= zobrist.color;

  /* a capture or a pawn move clears b.ply */
  b.ply++;
  if ((move.piece_from == PAWN) || move_iscapt(move))
    b.ply = 0;

  /* a piece vacates its initial square */
  clearSq(move.from);

  /* in case of a capture, the "to" square must be cleared,
  else incrementally updated stuff gets blown up
  */
  if (b.pieces[move.to] != PIECE_EMPTY)
    clearSq(move.to);

  /* a piece arrives to its destination square */
  fillSq(!b.stm, move.piece_to, move.to);

  /* castle flags
  if either a king or a rook leaves its initial square, the side looses its castling-right.
  The same happens if another piece moves to this square (eg.: captures a rook on its initial square)
  */
  switch (move.from) {
  case H1: b.castle &= ~CASTLE_WK; break;
  case E1: b.castle &= ~(CASTLE_WK | CASTLE_WQ); break;
  case A1: b.castle &= ~CASTLE_WQ; break;
  case H8: b.castle &= ~CASTLE_BK; break;
  case E8: b.castle &= ~(CASTLE_BK | CASTLE_BQ); break;
  case A8: b.castle &= ~CASTLE_BQ; break;
  }
  switch (move.to) {
  case H1: b.castle &= ~CASTLE_WK; break;
  case E1: b.castle &= ~(CASTLE_WK | CASTLE_WQ); break;
  case A1: b.castle &= ~CASTLE_WQ; break;
  case H8: b.castle &= ~CASTLE_BK; break;
  case E8: b.castle &= ~(CASTLE_BK | CASTLE_BQ); break;
  case A8: b.castle &= ~CASTLE_BQ; break;
  }
  b.hash ^= zobrist.castling[move.castle];
  b.hash ^= zobrist.castling[b.castle];

  /* castle-move
  in communication with the gui a castling move is represented through
  the king move. (eg.: e1g1 = White castles short) This king move already
  got executed in the code above with the fillSq() and clearSq() command.
  Whats missing now is the relating rook-move.
  */
  if (move.flags & MFLAG_CASTLE) {
    if (move.to == G1) {
      clearSq(H1);
      fillSq(WHITE, ROOK, F1);
    }
    else if (move.to == C1) {
      clearSq(A1);
      fillSq(WHITE, ROOK, D1);
    }
    else if (move.to == G8) {
      clearSq(H8);
      fillSq(BLACK, ROOK, F8);
    }
    else if (move.to == C8) {
      clearSq(A8);
      fillSq(BLACK, ROOK, D8);
    }
  }

  /* en-passant flag
  First erase the current state of the ep-flag, then set it again
  in  case there has been a two square pawn move that allows such
  capture. For example, 1.e4 in the initial position will not set
  the en passant flag, because there are no black pawns on d4 and f4.
  This soluion helps with opening book and increases the number of
  transposition table hits.
  */
  if (b.ep != -1) {
    b.hash ^= zobrist.ep[b.ep];
    b.ep = -1;
  }
  if ((move.piece_from == PAWN) && (abs(move.from - move.to) == 32) &&
    (pawnRecapture(!b.stm, (move.from + move.to) / 2))
    ) {
    b.ep = (move.from + move.to) / 2;
    b.hash ^= zobrist.ep[b.ep];
  }

  /* en-passant capture
  if the move is an en-passant capture, the captured pawn has to be removed manually
  */
  if (move.flags & MFLAG_EPCAPTURE) {
    if (!b.stm == WHITE) {
      clearSq(move.to - 16);
    }
    else {
      clearSq(move.to + 16);
    }
  }

  ++b.rep_index;
  b.rep_stack[b.rep_index] = b.hash;

  return 0;
}

int move_unmake(smove move) {

  b.stm = !b.stm;
  b.hash ^= zobrist.color;

  b.ply = move.ply;

  /* set en passant square */
  if (b.ep != -1)
    b.hash ^= zobrist.ep[b.ep];
  if (move.ep != -1)
    b.hash ^= zobrist.ep[move.ep];
  b.ep = move.ep;

  clearSq(move.to);

  fillSq(b.stm, move.piece_from, move.from);

  /* un-capture
  in case of a capture, put the captured piece back
  */
  if (move_iscapt(move))
    fillSq(!b.stm, move.piece_cap, move.to);

  /* un-castle
  the king has already been moved, now move the rook
  */
  if (move.flags & MFLAG_CASTLE) {
    if (move.to == G1) {
      clearSq(F1);
      fillSq(WHITE, ROOK, H1);
    }
    else if (move.to == C1) {
      clearSq(D1);
      fillSq(WHITE, ROOK, A1);
    }
    else if (move.to == G8) {
      clearSq(F8);
      fillSq(BLACK, ROOK, H8);
    }
    else if (move.to == C8) {
      clearSq(D8);
      fillSq(BLACK, ROOK, A8);
    }
  }

  /* adjust castling flags */
  b.hash ^= zobrist.castling[move.castle];
  b.hash ^= zobrist.castling[b.castle];
  b.castle = move.castle;

  /* en-passant-uncapture
  put the captured pawn back to its initial square
  */
  if (move.flags & MFLAG_EPCAPTURE) {
    if (b.stm == WHITE) {
      fillSq(BLACK, PAWN, move.to - 16);
    }
    else {
      fillSq(WHITE, PAWN, move.to + 16);
    }
  }

  --b.rep_index;

  return 0;
}

int move_iscapt(smove m) {
  return (m.piece_cap != PIECE_EMPTY);
}

int move_isprom(smove m) {
  return (m.piece_from != m.piece_to);
}

int move_canSimplify(smove m) {
  if (m.piece_cap == PAWN ||
    b.PieceMaterial[!b.stm] - e.PIECE_VALUE[m.piece_cap] > e.ENDGAME_MAT)
    return 0;
  else
    return 1;
}

// this function returns number of legal moves in the current position

int move_countLegal() {
  smove mlist[256];
  int mcount = movegen(mlist, 0xFF);
  int result = 0;

  for (int i = 0; i < mcount; i++) {

    // try a move...
    move_make(mlist[i]);

    // ...then increase the counter if it did not leave us in check
    if (!isAttacked(b.stm, b.KingLoc[!b.stm])) ++result;

    move_unmake(mlist[i]);
  }

  return result;
}

int move_isLegal(smove m) {
  smove movelist[256];
  int movecount = movegen(movelist, 0xFF);

  for (int i = 0; i < movecount; i++) {
    if (movelist[i].from == m.from &&
      movelist[i].to == m.to) {

      int result = 1;

      // test if the move in question leaves us in check

      move_make(movelist[i]);
      if (isAttacked(b.stm, b.KingLoc[!b.stm])) result = 0;
      move_unmake(movelist[i]);

      return result;
    }
  }

  return 0;
}

Up one Level