Exemplo n.º 1
0
  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();
  }
Exemplo n.º 2
0
  /**
   * Moves and also updates the board's zobrist key verify legality, if not legal undo move and
   * return false
   */
  public boolean doMove(int move, boolean verifyCheck, boolean fillSanInfo) {
    if (move == Move.NONE) {
      return false;
    }
    // Save history
    saveHistory(move, fillSanInfo);

    // Count consecutive moves without capture or without pawn move
    fiftyMovesRule++;
    moveNumber++; // Count Ply moves

    boolean turn = getTurn();
    int color = turn ? Color.W : Color.B;

    if ((flags & FLAGS_PASSANT) != 0) {
      // Remove passant flags: from the zobrist key
      key[1 - color] ^= ZobristKey.passantFile[BitboardUtils.getFile(flags & FLAGS_PASSANT)];
      // and from the flags
      flags &= ~FLAGS_PASSANT;
    }

    if (move == Move.NULL) {
      // Change turn
      flags ^= FLAG_TURN;
      key[0] ^= ZobristKey.whiteMove;
      return true;
    }

    int fromIndex = Move.getFromIndex(move);
    long from = Move.getFromSquare(move);

    // Check if we are applying a move in the other turn
    if ((from & getMines()) == 0) {
      undoMove();
      return false;
    }

    int toIndex = Move.getToIndex(move);
    long to = Move.getToSquare(move);
    long moveMask =
        from
            | to; // Move is as easy as xor with this mask (exceptions are promotions, captures and
                  // en-passant captures)
    int moveType = Move.getMoveType(move);
    int pieceMoved = Move.getPieceMoved(move);
    boolean capture = Move.isCapture(move);

    // Is it is a capture, remove pieces in destination square
    if (capture) {
      fiftyMovesRule = 0;
      // En-passant pawn captures remove captured pawn, put the pawn in to
      int toIndexCapture = toIndex;
      if (moveType == Move.TYPE_PASSANT) {
        to = (getTurn() ? (to >>> 8) : (to << 8));
        toIndexCapture += (getTurn() ? -8 : 8);
      }
      key[1 - color] ^= ZobristKey.getKeyPieceIndex(toIndexCapture, getPieceAt(to));

      whites &= ~to;
      blacks &= ~to;
      pawns &= ~to;
      queens &= ~to;
      rooks &= ~to;
      bishops &= ~to;
      knights &= ~to;
    }

    // Pawn movements
    switch (pieceMoved) {
      case Piece.PAWN:
        fiftyMovesRule = 0;
        // Set new passant flags if pawn is advancing two squares (marks
        // the destination square where the pawn can be captured)
        // Set only passant flags when the other side can capture
        if (((from << 16) & to) != 0
            && (bbAttacks.pawn[Color.W][toIndex - 8] & pawns & getOthers()) != 0) { // white
          flags |= (from << 8);
        }
        if (((from >>> 16) & to) != 0
            && (bbAttacks.pawn[Color.B][toIndex + 8] & pawns & getOthers()) != 0) { // blask
          flags |= (from >>> 8);
        }
        if ((flags & FLAGS_PASSANT) != 0) {
          key[color] ^= ZobristKey.passantFile[BitboardUtils.getFile(flags & FLAGS_PASSANT)];
        }

        if (moveType == Move.TYPE_PROMOTION_QUEEN
            || moveType == Move.TYPE_PROMOTION_KNIGHT
            || moveType == Move.TYPE_PROMOTION_BISHOP
            || moveType == Move.TYPE_PROMOTION_ROOK) { // Promotions:
          // change
          // the piece
          pawns &= ~from;
          key[color] ^= ZobristKey.pawn[color][fromIndex];
          switch (moveType) {
            case Move.TYPE_PROMOTION_QUEEN:
              queens |= to;
              key[color] ^= ZobristKey.queen[color][toIndex];
              break;
            case Move.TYPE_PROMOTION_KNIGHT:
              knights |= to;
              key[color] ^= ZobristKey.knight[color][toIndex];
              break;
            case Move.TYPE_PROMOTION_BISHOP:
              bishops |= to;
              key[color] ^= ZobristKey.bishop[color][toIndex];
              break;
            case Move.TYPE_PROMOTION_ROOK:
              rooks |= to;
              key[color] ^= ZobristKey.rook[color][toIndex];
              break;
          }
        } else {
          pawns ^= moveMask;
          key[color] ^= ZobristKey.pawn[color][fromIndex] ^ ZobristKey.pawn[color][toIndex];
        }
        break;
      case Piece.ROOK:
        rooks ^= moveMask;
        key[color] ^= ZobristKey.rook[color][fromIndex] ^ ZobristKey.rook[color][toIndex];
        break;
      case Piece.BISHOP:
        bishops ^= moveMask;
        key[color] ^= ZobristKey.bishop[color][fromIndex] ^ ZobristKey.bishop[color][toIndex];
        break;
      case Piece.KNIGHT:
        knights ^= moveMask;
        key[color] ^= ZobristKey.knight[color][fromIndex] ^ ZobristKey.knight[color][toIndex];
        break;
      case Piece.QUEEN:
        queens ^= moveMask;
        key[color] ^= ZobristKey.queen[color][fromIndex] ^ ZobristKey.queen[color][toIndex];
        break;
      case Piece.KING: // if castling, moves rooks too
        if (moveType == Move.TYPE_KINGSIDE_CASTLING || moveType == Move.TYPE_QUEENSIDE_CASTLING) {
          // {White Kingside, White Queenside, Black Kingside, Black Queenside}
          int j = (color << 1) + (moveType == Move.TYPE_QUEENSIDE_CASTLING ? 1 : 0);

          toIndex = CASTLING_KING_DESTINY_INDEX[j];
          int originRookIndex = BitboardUtils.square2Index(castlingRooks[j]);
          int destinyRookIndex = CASTLING_ROOK_DESTINY_INDEX[j];
          // Recalculate move mask for chess960 castlings
          moveMask = from ^ (1L << toIndex);
          long rookMoveMask = (1L << originRookIndex) ^ (1L << destinyRookIndex);
          key[color] ^=
              ZobristKey.rook[color][originRookIndex] ^ ZobristKey.rook[color][destinyRookIndex];

          if (getTurn()) {
            whites ^= rookMoveMask;
          } else {
            blacks ^= rookMoveMask;
          }
          rooks ^= rookMoveMask;
        }
        kings ^= moveMask;
        key[color] ^= ZobristKey.king[color][fromIndex] ^ ZobristKey.king[color][toIndex];
        break;
    }
    // Move pieces in colour fields
    if (getTurn()) {
      whites ^= moveMask;
    } else {
      blacks ^= moveMask;
    }

    // Tests to disable castling
    if ((flags & FLAG_WHITE_KINGSIDE_CASTLING) != 0
        && //
        ((turn && pieceMoved == Piece.KING)
            || from == castlingRooks[0]
            || to == castlingRooks[0])) {
      flags &= ~FLAG_WHITE_KINGSIDE_CASTLING;
      key[0] ^= ZobristKey.whiteKingSideCastling;
    }
    if ((flags & FLAG_WHITE_QUEENSIDE_CASTLING) != 0
        && //
        ((turn && pieceMoved == Piece.KING)
            || from == castlingRooks[1]
            || to == castlingRooks[1])) {
      flags &= ~FLAG_WHITE_QUEENSIDE_CASTLING;
      key[0] ^= ZobristKey.whiteQueenSideCastling;
    }
    if ((flags & FLAG_BLACK_KINGSIDE_CASTLING) != 0
        && //
        ((!turn && pieceMoved == Piece.KING)
            || from == castlingRooks[2]
            || to == castlingRooks[2])) {
      flags &= ~FLAG_BLACK_KINGSIDE_CASTLING;
      key[1] ^= ZobristKey.blackKingSideCastling;
    }
    if ((flags & FLAG_BLACK_QUEENSIDE_CASTLING) != 0
        && //
        ((!turn && pieceMoved == Piece.KING)
            || from == castlingRooks[3]
            || to == castlingRooks[3])) {
      flags &= ~FLAG_BLACK_QUEENSIDE_CASTLING;
      key[1] ^= ZobristKey.blackQueenSideCastling;
    }
    // Change turn
    flags ^= FLAG_TURN;
    key[0] ^= ZobristKey.whiteMove;

    if (verifyCheck) {
      if (isValid()) {
        setCheckFlags();

        if (fillSanInfo) {
          if (isMate()) { // Append # when mate
            movesSan.put(moveNumber - 1, movesSan.get(moveNumber - 1).replace("+", "#"));
          }
        }
      } else {
        undoMove();
        return false;
      }
    } else {
      // Trust move check flag
      if (Move.isCheck(move)) {
        flags |= FLAG_CHECK;
      } else {
        flags &= ~FLAG_CHECK;
      }
    }
    return true;
  }
Exemplo n.º 3
0
  /** 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;
      }
    }
  }