public void setPieceAt(long square, char piece) { pawns &= ~square; queens &= ~square; rooks &= ~square; bishops &= ~square; knights &= ~square; kings &= ~square; if (piece == ' ' || piece == '.') { whites &= ~square; blacks &= ~square; return; } else if (piece == Character.toLowerCase(piece)) { whites &= ~square; blacks |= square; } else { whites |= square; blacks &= ~square; } switch (Character.toLowerCase(piece)) { case 'p': pawns |= square; break; case 'q': queens |= square; break; case 'r': rooks |= square; break; case 'b': bishops |= square; break; case 'n': knights |= square; break; case 'k': kings |= square; break; } key = ZobristKey.getKey(this); setCheckFlags(); }
/** Sets fen without destroying move history. If lastMove = null destroy the move history */ public void setFenMove(String fen, String lastMove) { long tmpWhites = 0; long tmpBlacks = 0; long tmpPawns = 0; long tmpRooks = 0; long tmpQueens = 0; long tmpBishops = 0; long tmpKnights = 0; long tmpKings = 0; long tmpFlags; int tmpFiftyMovesRule = 0; long tmpCastlingRooks[] = {0, 0, 0, 0}; int fenMoveNumber = 0; int i = 0; long j = Square.A8; String[] tokens = fen.split("[ \\t\\n\\x0B\\f\\r]+"); String board = tokens[0]; while ((i < board.length()) && (j != 0)) { char p = board.charAt(i++); if (p != '/') { int number = 0; try { number = Integer.parseInt(String.valueOf(p)); } catch (Exception ignored) { } for (int k = 0; k < (number == 0 ? 1 : number); k++) { tmpWhites = (tmpWhites & ~j) | ((number == 0) && (p == Character.toUpperCase(p)) ? j : 0); tmpBlacks = (tmpBlacks & ~j) | ((number == 0) && (p == Character.toLowerCase(p)) ? j : 0); tmpPawns = (tmpPawns & ~j) | (Character.toUpperCase(p) == 'P' ? j : 0); tmpRooks = (tmpRooks & ~j) | (Character.toUpperCase(p) == 'R' ? j : 0); tmpQueens = (tmpQueens & ~j) | (Character.toUpperCase(p) == 'Q' ? j : 0); tmpBishops = (tmpBishops & ~j) | (Character.toUpperCase(p) == 'B' ? j : 0); tmpKnights = (tmpKnights & ~j) | (Character.toUpperCase(p) == 'N' ? j : 0); tmpKings = (tmpKings & ~j) | (Character.toUpperCase(p) == 'K' ? j : 0); j >>>= 1; if (j == 0) { break; // security } } } } // Now the rest ... String turn = tokens[1]; tmpFlags = 0; if ("b".equals(turn)) { tmpFlags |= FLAG_TURN; } if (tokens.length > 2) { // Set castling rights supporting XFEN to disambiguate positions in Chess960 String castlings = tokens[2]; chess960 = false; // Squares to the sides of the kings {White Kingside, White Queenside, Black Kingside, Black // Queenside} long whiteKingLateralSquares[] = { BitboardUtils.b_d & ((tmpKings & tmpWhites) - 1), BitboardUtils.b_d & ~(((tmpKings & tmpWhites) - 1) | tmpKings & tmpWhites), BitboardUtils.b_u & ((tmpKings & tmpBlacks) - 1), BitboardUtils.b_u & ~(((tmpKings & tmpBlacks) - 1) | tmpKings & tmpBlacks) }; // Squares where we can find a castling rook long possibleCastlingRookSquares[] = {0, 0, 0, 0}; for (int k = 0; k < castlings.length(); k++) { char c = castlings.charAt(k); switch (c) { case 'K': possibleCastlingRookSquares[0] = whiteKingLateralSquares[0]; break; case 'Q': possibleCastlingRookSquares[1] = whiteKingLateralSquares[1]; break; case 'k': possibleCastlingRookSquares[2] = whiteKingLateralSquares[2]; break; case 'q': possibleCastlingRookSquares[3] = whiteKingLateralSquares[3]; break; default: // Shredder-FEN receives the name of the file where the castling rook is int whiteFile = "ABCDEFGH".indexOf(c); int blackFile = "abcdefgh".indexOf(c); if (whiteFile >= 0) { long rookSquare = BitboardUtils.b_d & BitboardUtils.FILE[whiteFile]; if ((rookSquare & whiteKingLateralSquares[0]) != 0) { possibleCastlingRookSquares[0] = rookSquare; } else if ((rookSquare & whiteKingLateralSquares[1]) != 0) { possibleCastlingRookSquares[1] = rookSquare; } } else if (blackFile >= 0) { long rookSquare = BitboardUtils.b_u & BitboardUtils.FILE[blackFile]; if ((rookSquare & whiteKingLateralSquares[2]) != 0) { possibleCastlingRookSquares[2] = rookSquare; } else if ((rookSquare & whiteKingLateralSquares[3]) != 0) { possibleCastlingRookSquares[3] = rookSquare; } } } } // Now store the squares of the castling rooks tmpCastlingRooks[0] = BitboardUtils.lsb(tmpRooks & tmpWhites & possibleCastlingRookSquares[0]); tmpCastlingRooks[1] = BitboardUtils.msb(tmpRooks & tmpWhites & possibleCastlingRookSquares[1]); tmpCastlingRooks[2] = BitboardUtils.lsb(tmpRooks & tmpBlacks & possibleCastlingRookSquares[2]); tmpCastlingRooks[3] = BitboardUtils.msb(tmpRooks & tmpBlacks & possibleCastlingRookSquares[3]); // Set the castling flags and detect Chess960 if (tmpCastlingRooks[0] != 0) { tmpFlags |= FLAG_WHITE_KINGSIDE_CASTLING; if ((tmpWhites & tmpKings) != 1L << 3 || tmpCastlingRooks[0] != 1L) { chess960 = true; } } if (tmpCastlingRooks[1] != 0) { tmpFlags |= FLAG_WHITE_QUEENSIDE_CASTLING; if ((tmpWhites & tmpKings) != 1L << 3 || tmpCastlingRooks[1] != 1L << 7) { chess960 = true; } } if (tmpCastlingRooks[2] != 0) { tmpFlags |= FLAG_BLACK_KINGSIDE_CASTLING; if ((tmpBlacks & tmpKings) != 1L << 59 || tmpCastlingRooks[2] != 1L << 56) { chess960 = true; } } if (tmpCastlingRooks[3] != 0) { tmpFlags |= FLAG_BLACK_QUEENSIDE_CASTLING; if ((tmpBlacks & tmpKings) != 1L << 59 || tmpCastlingRooks[3] != 1L << 63) { chess960 = true; } } // END FEN castlings if (tokens.length > 3) { String passant = tokens[3]; tmpFlags |= FLAGS_PASSANT & BitboardUtils.algebraic2Square(passant); if (tokens.length > 4) { try { tmpFiftyMovesRule = Integer.parseInt(tokens[4]); } catch (Exception e) { tmpFiftyMovesRule = 0; } if (tokens.length > 5) { String moveNumberString = tokens[5]; int aux = Integer.parseInt(moveNumberString); fenMoveNumber = ((aux > 0 ? aux - 1 : aux) << 1) + ((tmpFlags & FLAG_TURN) == 0 ? 0 : 1); if (fenMoveNumber < 0) { fenMoveNumber = 0; } } } } } // try to apply the last move to see if we are advancing or undoing moves if ((moveNumber + 1) == fenMoveNumber && lastMove != null) { doMove(Move.getFromString(this, lastMove, true)); } else if (fenMoveNumber < moveNumber) { for (int k = moveNumber; k > fenMoveNumber; k--) { undoMove(); } } // Check if board changed or if we can keep the history if (whites != tmpWhites // || blacks != tmpBlacks // || pawns != tmpPawns // || rooks != tmpRooks // || queens != tmpQueens // || bishops != tmpBishops // || knights != tmpKnights // || kings != tmpKings // || (flags & FLAG_TURN) != (tmpFlags & FLAG_TURN)) { // board reset movesSan.clear(); initialFen = fen; initialMoveNumber = fenMoveNumber; moveNumber = fenMoveNumber; outBookMove = Integer.MAX_VALUE; whites = tmpWhites; blacks = tmpBlacks; pawns = tmpPawns; rooks = tmpRooks; queens = tmpQueens; bishops = tmpBishops; knights = tmpKnights; kings = tmpKings; fiftyMovesRule = tmpFiftyMovesRule; // Flags are not completed till verify, so skip checking flags = tmpFlags; castlingRooks[0] = tmpCastlingRooks[0]; castlingRooks[1] = tmpCastlingRooks[1]; castlingRooks[2] = tmpCastlingRooks[2]; castlingRooks[3] = tmpCastlingRooks[3]; // Set zobrist key and check flags key = ZobristKey.getKey(this); setCheckFlags(); // and save history resetHistory(); saveHistory(0, false); } else { if (moveNumber < outBookMove) { outBookMove = Integer.MAX_VALUE; } } }