Example #1
0
 /** checks draw by fiftymoves rule and threefold repetition */
 public boolean isDraw() {
   if (fiftyMovesRule >= 100) {
     return true;
   }
   int repetitions = 0;
   // logger.debug("My keys key0=" + key[0] + " " + " key1=" + key[1]);
   for (int i = 0; i < (moveNumber - 1); i++) {
     if (keyHistory[i][0] == key[0] && keyHistory[i][1] == key[1]) {
       repetitions++;
     }
     if (repetitions >= 2) { // with the last one they are 3
       return true;
     }
   }
   // Draw by no material to mate
   return (pawns == 0 && rooks == 0 && queens == 0)
       && ((bishops == 0 && knights == 0)
           || //
           (bishops == 0 && BitboardUtils.popCount(knights) == 1)
           || //
           (knights == 0 && BitboardUtils.popCount(bishops) == 1));
 }
Example #2
0
 /** Converts board to its fen notation */
 public String getFen() {
   StringBuilder sb = new StringBuilder();
   long i = BitboardUtils.A8;
   int j = 0;
   while (i != 0) {
     char p = getPieceAt(i);
     if (p == '.') {
       j++;
     }
     if ((j != 0) && (p != '.' || ((i & BitboardUtils.b_r) != 0))) {
       sb.append(j);
       j = 0;
     }
     if (p != '.') {
       sb.append(p);
     }
     if ((i != 1) && (i & BitboardUtils.b_r) != 0) {
       sb.append("/");
     }
     i >>>= 1;
   }
   sb.append(" ");
   sb.append((getTurn() ? "w" : "b"));
   sb.append(" ");
   if (getWhiteKingsideCastling()) {
     sb.append("K");
   }
   if (getWhiteQueensideCastling()) {
     sb.append("Q");
   }
   if (getBlackKingsideCastling()) {
     sb.append("k");
   }
   if (getBlackQueensideCastling()) {
     sb.append("q");
   }
   if (!getWhiteQueensideCastling()
       && !getWhiteKingsideCastling()
       && !getBlackQueensideCastling()
       && !getBlackKingsideCastling()) {
     sb.append("-");
   }
   sb.append(" ");
   sb.append((getPassantSquare() != 0 ? BitboardUtils.square2Algebraic(getPassantSquare()) : "-"));
   sb.append(" ");
   sb.append(fiftyMovesRule);
   sb.append(" ");
   sb.append((moveNumber >> 1) + 1); // 0,1->1.. 2,3->2
   return sb.toString();
 }
Example #3
0
  /** The SWAP algorithm https://chessprogramming.wikispaces.com/SEE+-+The+Swap+Algorithm */
  public int see(int fromIndex, int toIndex, int pieceMoved, int targetPiece) {
    int d = 0;
    long mayXray = pawns | bishops | rooks | queens; // not kings nor knights
    long fromSquare = 0x1L << fromIndex;
    long all = getAll();
    long attacks = bbAttacks.getIndexAttacks(this, toIndex);
    long fromCandidates;

    seeGain[d] = SEE_PIECE_VALUES[targetPiece];
    do {
      long side = (d & 1) == 0 ? getOthers() : getMines();
      d++; // next depth and side
      // speculative store, if defended
      seeGain[d] = SEE_PIECE_VALUES[pieceMoved] - seeGain[d - 1];
      attacks ^= fromSquare; // reset bit in set to traverse
      all ^= fromSquare; // reset bit in temporary occupancy (for X-Rays)
      if ((fromSquare & mayXray) != 0) {
        attacks |= bbAttacks.getXrayAttacks(this, toIndex, all);
      }

      // Gets the next attacker
      if ((fromCandidates = attacks & pawns & side) != 0) {
        pieceMoved = Piece.PAWN;
      } else if ((fromCandidates = attacks & knights & side) != 0) {
        pieceMoved = Piece.KNIGHT;
      } else if ((fromCandidates = attacks & bishops & side) != 0) {
        pieceMoved = Piece.BISHOP;
      } else if ((fromCandidates = attacks & rooks & side) != 0) {
        pieceMoved = Piece.ROOK;
      } else if ((fromCandidates = attacks & queens & side) != 0) {
        pieceMoved = Piece.QUEEN;
      } else if ((fromCandidates = attacks & kings & side) != 0) {
        pieceMoved = Piece.KING;
      }
      fromSquare = BitboardUtils.lsb(fromCandidates);

    } while (fromSquare != 0);

    while (--d != 0) {
      seeGain[d - 1] = -Math.max(-seeGain[d - 1], seeGain[d]);
    }
    return seeGain[0];
  }
Example #4
0
  /**
   * Moves and also updates the board's zobrist key verify legality, if not legal undo move and
   * return false 0 is the null move
   */
  public boolean doMove(int move, boolean verify, boolean fillSanInfo) {
    if (move == -1) {
      return false;
    }
    // Save history
    saveHistory(move, fillSanInfo);

    int fromIndex = Move.getFromIndex(move);
    int toIndex = Move.getToIndex(move);
    long from = Move.getFromSquare(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);
    boolean turn = getTurn();
    int color = (turn ? 0 : 1);

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

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

    if (move != 0) {
      assert (from & getMines()) != 0 : "Origin square not valid";

      // 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.pawnUpwards[toIndex - 8] & pawns & getOthers()) != 0) { // white
            flags |= (from << 8);
          }
          if (((from >>> 16) & to) != 0
              && (bbAttacks.pawnDownwards[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 (verify) {
      if (isValid()) {
        setCheckFlags();

        if (fillSanInfo) {
          if (isMate()) { // Append # when mate
            sanMoves.put(moveNumber - 1, sanMoves.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;
  }
Example #5
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 = BitboardUtils.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
      sanMoves.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;
      }
    }
  }