public bool AddMove(Move move) { // Add the piece that was there to the move stack _history.Push(new Square(move, _pieceArray[move.To], _colourArray[move.To], _enPassantTarget, _castling, _zobristHash)); // ORDINARY MOVE if (move.Bits == 0) { MovePieceWithZobrist(move.From, move.To); SetEnPassant(); } // EN PASSANT else if ((move.Bits & 4) != 0) { MovePieceWithZobrist(move.From, move.To); // Delete the en passant target square _zobristHash ^= _hashValues.PieceValue(_enPassantTarget - _turn * 10, _colourArray[_enPassantTarget - _turn * 10], _pieceArray[_enPassantTarget - _turn * 10]); _pieceArray[_enPassantTarget - _turn * 10] = Definitions.EMPTY; _colourArray[_enPassantTarget - _turn * 10] = Definitions.EMPTY; SetEnPassant(); } // CAPTURE (todo: implement 50 move rule) else if ((move.Bits & 1) != 0) { if (_pieceArray[move.To] == Definitions.K) { switch (_colourArray[move.To]) { case Definitions.WHITE: _whiteKing = Definitions.EMPTY; break; case Definitions.BLACK: _blackKing = Definitions.EMPTY; break; } } MovePieceWithZobrist(move.From, move.To); SetEnPassant(); } // DOUBLE PAWN PUSH (todo: implement 50 move rule) else if ((move.Bits & 8) != 0) { MovePieceWithZobrist(move.From, move.To); SetEnPassant(move.From + (10 * _turn)); } // PAWN PUSH (todo: implement 50 move rule) else if ((move.Bits & 16) != 0) { MovePieceWithZobrist(move.From, move.To); SetEnPassant(); } // CASTLING MOVE else if ((move.Bits & 2) != 0) { // move the king MovePieceWithZobrist(move.From, move.To); // figure out which rook to move switch (move.To) { case 27: // white king side MovePieceWithZobrist(28, 26); // right rook break; case 23: // white queen side MovePieceWithZobrist(21, 24); // left rook break; case 97: // black king side MovePieceWithZobrist(98, 96); // right rook break; case 93: // black queen size MovePieceWithZobrist(91, 94); // left rook break; } SetEnPassant(); } // PROMOTION (todo: implement 50 move rule) if ((move.Bits & 32) != 0) { // Everything else should be taken care of by this point. // Just overwrite the underlying piece. _zobristHash ^= _hashValues.PieceValue(move.To, _colourArray[move.To], _pieceArray[move.To]); _pieceArray[move.To] = move.Promote; _zobristHash ^= _hashValues.PieceValue(move.To, _colourArray[move.To], _pieceArray[move.To]); } // POST MOVE #region Remove castling rights and reset king if (_pieceArray[move.To] == Definitions.K) { if (_turn == Definitions.WHITE) { // remove white's ability to castle if ((_castling & 1) != 0) { _zobristHash ^= _hashValues.CastlingRights[0]; _castling = _castling - 1; } if ((_castling & 2) != 0) { _zobristHash ^= _hashValues.CastlingRights[1]; _castling = _castling - 2; } _whiteKing = move.To; } else { // remove black's ability to castle if ((_castling & 4) != 0) { _zobristHash ^= _hashValues.CastlingRights[2]; _castling = _castling - 4; } if ((_castling & 8) != 0) { _zobristHash ^= _hashValues.CastlingRights[3]; _castling = _castling - 8; } _blackKing = move.To; } } if ((move.From == 28 || move.To == 28) && (_castling & 1) != 0) { _zobristHash ^= _hashValues.CastlingRights[0]; _castling -= 1; } else if ((move.From == 21 || move.To == 21) && (_castling & 2) != 0) { _zobristHash ^= _hashValues.CastlingRights[1]; _castling -= 2; } else if ((move.From == 98 || move.To == 98) && (_castling & 4) != 0) { _zobristHash ^= _hashValues.CastlingRights[2]; _castling -= 4; } else if ((move.From == 91 || move.To == 91) && (_castling & 8) != 0) { _zobristHash ^= _hashValues.CastlingRights[3]; _castling -= 8; } #endregion // Increment the full move number after black if (_turn == Definitions.BLACK) _fullMoveNumber++; // Switch the active turn _turn = -1 * _turn; _zobristHash ^= _hashValues.IfBlackIsPlaying; // If the board is in check, subtract the move if (IsInCheck(-1 * _turn)) { SubtractMove(); return false; } return true; }
/// <summary> /// Given input such as "e2e4" it runs the appropriate move without the bits. /// Use the AddMoveNoBits() function with these moves. /// </summary> /// <param name="move"></param> /// <returns></returns> public static Move StringToMove(string movestring) { Move move = new Move(); move.From = ChessPieceToIndex(movestring.Substring(0, 2)); move.To = ChessPieceToIndex(movestring.Substring(2, 2)); if (movestring.EndsWith("q")) { move.Bits += 32; move.Promote = Definitions.Q; } else if (movestring.EndsWith("r")) { move.Bits += 32; move.Promote = Definitions.R; } else if (movestring.EndsWith("b")) { move.Bits += 32; move.Promote = Definitions.B; } else if (movestring.EndsWith("n")) { move.Bits += 32; move.Promote = Definitions.N; } return move; }
/// <summary> /// Add move without the bits field set. Determines the bit fields. /// Note: It does not attempt to determine promotion bits. That should /// be taken care of by StringToMove() /// </summary> /// <param name="move">Move without bits</param> /// <returns>whether the addition was successful</returns> public bool AddMoveNoBits(Move move) { // Capture if (_colourArray[move.To] == -1 * _turn) move.Bits += 1; // Castling if (move.From == 25 && (move.To == 27 || move.To == 23)) move.Bits += 2; else if (move.From == 95 && (move.To == 97 || move.To == 93)) move.Bits += 2; // En passant capture (rather naive for now) if (_pieceArray[move.From] == Definitions.P && (move.To == move.From + 9 * _turn || move.To == move.From + 11 * _turn) && _pieceArray[move.To] == Definitions.EMPTY) move.Bits += 4; // Double pawn push if (_pieceArray[move.From] == Definitions.P && move.To == move.From + 20 * _turn) move.Bits += 8; // Pawn move if (_pieceArray[move.From] == Definitions.P) move.Bits += 16; // Add to the opening book if we're in it if (!_book.OutOfOpeningBook) { _book.OpeningBookDepth++; _book.OpeningLine += Definitions.MoveToString(move); } return AddMove(move); }
public static string MoveToString(Move move) { string moveString = string.Empty; int fromColumn = GetColumn(move.From); int fromRow = GetRow(move.From); moveString += columnNames[fromColumn - 1] + fromRow; int toColumn = GetColumn(move.To); int toRow = GetRow(move.To); moveString += columnNames[toColumn - 1] + toRow; return moveString; }