private static final String moveToString( Position pos, Move move, boolean longForm, List<Move> moves) { if (move.equals(new Move(0, 0, 0))) return "--"; StringBuilder ret = new StringBuilder(); int wKingOrigPos = Position.getSquare(4, 0); int bKingOrigPos = Position.getSquare(4, 7); if (move.from == wKingOrigPos && pos.getPiece(wKingOrigPos) == Piece.WKING) { // Check white castle if (move.to == Position.getSquare(6, 0)) { ret.append("O-O"); } else if (move.to == Position.getSquare(2, 0)) { ret.append("O-O-O"); } } else if (move.from == bKingOrigPos && pos.getPiece(bKingOrigPos) == Piece.BKING) { // Check white castle if (move.to == Position.getSquare(6, 7)) { ret.append("O-O"); } else if (move.to == Position.getSquare(2, 7)) { ret.append("O-O-O"); } } if (ret.length() == 0) { int p = pos.getPiece(move.from); ret.append(pieceToChar(p)); int x1 = Position.getX(move.from); int y1 = Position.getY(move.from); int x2 = Position.getX(move.to); int y2 = Position.getY(move.to); if (longForm) { ret.append((char) (x1 + 'a')); ret.append((char) (y1 + '1')); ret.append(isCapture(pos, move) ? 'x' : '-'); } else { if (p == (pos.whiteMove ? Piece.WPAWN : Piece.BPAWN)) { if (isCapture(pos, move)) { ret.append((char) (x1 + 'a')); } } else { int numSameTarget = 0; int numSameFile = 0; int numSameRow = 0; int mSize = moves.size(); for (int mi = 0; mi < mSize; mi++) { Move m = moves.get(mi); if ((pos.getPiece(m.from) == p) && (m.to == move.to)) { numSameTarget++; if (Position.getX(m.from) == x1) numSameFile++; if (Position.getY(m.from) == y1) numSameRow++; } } if (numSameTarget < 2) { // No file/row info needed } else if (numSameFile < 2) { ret.append((char) (x1 + 'a')); // Only file info needed } else if (numSameRow < 2) { ret.append((char) (y1 + '1')); // Only row info needed } else { ret.append((char) (x1 + 'a')); // File and row info needed ret.append((char) (y1 + '1')); } } if (isCapture(pos, move)) { ret.append('x'); } } ret.append((char) (x2 + 'a')); ret.append((char) (y2 + '1')); if (move.promoteTo != Piece.EMPTY) ret.append(pieceToChar(move.promoteTo)); } UndoInfo ui = new UndoInfo(); pos.makeMove(move, ui); boolean givesCheck = MoveGen.inCheck(pos); if (givesCheck) { ArrayList<Move> nextMoves = MoveGen.instance.pseudoLegalMoves(pos); // this should not be needed here // nextMoves = MoveGen.removeIllegal(pos, nextMoves); if (nextMoves.size() == 0) { ret.append('#'); } else { ret.append('+'); } } pos.unMakeMove(move, ui); return ret.toString(); }
/** Parse a FEN string and return a chess Position object. */ public static final Position readFEN(String fen) throws ChessParseError { Position pos = new Position(); String[] words = fen.split(" "); if (words.length < 2) { throw new ChessParseError(R.string.err_too_few_spaces); } for (int i = 0; i < words.length; i++) { words[i] = words[i].trim(); } // Piece placement int row = 7; int col = 0; for (int i = 0; i < words[0].length(); i++) { char c = words[0].charAt(i); switch (c) { case '1': col += 1; break; case '2': col += 2; break; case '3': col += 3; break; case '4': col += 4; break; case '5': col += 5; break; case '6': col += 6; break; case '7': col += 7; break; case '8': col += 8; break; case '/': row--; col = 0; break; case 'P': safeSetPiece(pos, col, row, Piece.WPAWN); col++; break; case 'N': safeSetPiece(pos, col, row, Piece.WKNIGHT); col++; break; case 'B': safeSetPiece(pos, col, row, Piece.WBISHOP); col++; break; case 'R': safeSetPiece(pos, col, row, Piece.WROOK); col++; break; case 'Q': safeSetPiece(pos, col, row, Piece.WQUEEN); col++; break; case 'K': safeSetPiece(pos, col, row, Piece.WKING); col++; break; case 'p': safeSetPiece(pos, col, row, Piece.BPAWN); col++; break; case 'n': safeSetPiece(pos, col, row, Piece.BKNIGHT); col++; break; case 'b': safeSetPiece(pos, col, row, Piece.BBISHOP); col++; break; case 'r': safeSetPiece(pos, col, row, Piece.BROOK); col++; break; case 'q': safeSetPiece(pos, col, row, Piece.BQUEEN); col++; break; case 'k': safeSetPiece(pos, col, row, Piece.BKING); col++; break; default: throw new ChessParseError(R.string.err_invalid_piece, pos); } } if (words[1].length() == 0) { throw new ChessParseError(R.string.err_invalid_side, pos); } pos.setWhiteMove(words[1].charAt(0) == 'w'); // Castling rights int castleMask = 0; if (words.length > 2) { for (int i = 0; i < words[2].length(); i++) { char c = words[2].charAt(i); switch (c) { case 'K': castleMask |= (1 << Position.H1_CASTLE); break; case 'Q': castleMask |= (1 << Position.A1_CASTLE); break; case 'k': castleMask |= (1 << Position.H8_CASTLE); break; case 'q': castleMask |= (1 << Position.A8_CASTLE); break; case '-': break; default: throw new ChessParseError(R.string.err_invalid_castling_flags, pos); } } } pos.setCastleMask(castleMask); removeBogusCastleFlags(pos); if (words.length > 3) { // En passant target square String epString = words[3]; if (!epString.equals("-")) { if (epString.length() < 2) { throw new ChessParseError(R.string.err_invalid_en_passant_square, pos); } pos.setEpSquare(getSquare(epString)); } } try { if (words.length > 4) { pos.halfMoveClock = Integer.parseInt(words[4]); } if (words.length > 5) { pos.fullMoveCounter = Integer.parseInt(words[5]); } } catch (NumberFormatException nfe) { // Ignore errors here, since the fields are optional } // Each side must have exactly one king int[] nPieces = new int[Piece.nPieceTypes]; for (int i = 0; i < Piece.nPieceTypes; i++) nPieces[i] = 0; for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) nPieces[pos.getPiece(Position.getSquare(x, y))]++; if (nPieces[Piece.WKING] != 1) throw new ChessParseError(R.string.err_white_num_kings, pos); if (nPieces[Piece.BKING] != 1) throw new ChessParseError(R.string.err_black_num_kings, pos); // White must not have too many pieces int maxWPawns = 8; maxWPawns -= Math.max(0, nPieces[Piece.WKNIGHT] - 2); maxWPawns -= Math.max(0, nPieces[Piece.WBISHOP] - 2); maxWPawns -= Math.max(0, nPieces[Piece.WROOK] - 2); maxWPawns -= Math.max(0, nPieces[Piece.WQUEEN] - 1); if (nPieces[Piece.WPAWN] > maxWPawns) throw new ChessParseError(R.string.err_too_many_white_pieces, pos); // Black must not have too many pieces int maxBPawns = 8; maxBPawns -= Math.max(0, nPieces[Piece.BKNIGHT] - 2); maxBPawns -= Math.max(0, nPieces[Piece.BBISHOP] - 2); maxBPawns -= Math.max(0, nPieces[Piece.BROOK] - 2); maxBPawns -= Math.max(0, nPieces[Piece.BQUEEN] - 1); if (nPieces[Piece.BPAWN] > maxBPawns) throw new ChessParseError(R.string.err_too_many_black_pieces, pos); // Make sure king can not be captured Position pos2 = new Position(pos); pos2.setWhiteMove(!pos.whiteMove); if (MoveGen.inCheck(pos2)) { throw new ChessParseError(R.string.err_king_capture_possible, pos); } fixupEPSquare(pos); return pos; }