/**
* Calculon - A Java chess-engine.
*
* Copyright (C) 2008-2009 Barry Smith
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package nl.zoidberg.calculon.notation;
import java.util.Arrays;
import java.util.List;
import nl.zoidberg.calculon.engine.BitBoard;
import nl.zoidberg.calculon.engine.EngineUtils;
import nl.zoidberg.calculon.model.Piece;
import org.apache.commons.lang.StringUtils;
public class FENUtils {
private static final String FILES = "abcdefgh";
public static String generate(BitBoard bitBoard) {
StringBuffer fen = new StringBuffer();
fen.append(generatePosition(bitBoard));
fen.append(" ").append(bitBoard.getPlayer() == Piece.WHITE ? "w" : "b");
fen.append(" ").append(generateCastling(bitBoard));
fen.append(" ").append(generateEnPassant(bitBoard));
fen.append(" ").append(bitBoard.getHalfMoveCount());
fen.append(" ").append(bitBoard.getMoveNumber());
return fen.toString();
}
public static String generateWithoutMoveCounts(BitBoard bitBoard) {
StringBuffer fen = new StringBuffer();
fen.append(generatePosition(bitBoard));
fen.append(" ").append(bitBoard.getPlayer() == Piece.WHITE ? "w" : "b");
fen.append(" ").append(generateCastling(bitBoard));
fen.append(" ").append(generateEnPassant(bitBoard));
return fen.toString();
}
public static String generateEnPassant(BitBoard board) {
if( ! board.isEnPassant()) {
return "-";
}
StringBuffer fen = new StringBuffer();
fen.append(Character.toLowerCase(EngineUtils.FILES.charAt(board.getEnPassantFile())));
fen.append(EngineUtils.RANKS.charAt(board.getEnPassantRank()));
return fen.toString();
}
public static String generateCastling(BitBoard board) {
StringBuffer fen = new StringBuffer();
if((board.getCastlingOptions() & BitBoard.CASTLE_WKS) != 0) {
fen.append("K");
}
if((board.getCastlingOptions() & BitBoard.CASTLE_WQS) != 0) {
fen.append("Q");
}
if((board.getCastlingOptions() & BitBoard.CASTLE_BKS) != 0) {
fen.append("k");
}
if((board.getCastlingOptions() & BitBoard.CASTLE_BQS) != 0) {
fen.append("q");
}
if(fen.length() == 0) {
fen.append("-");
}
return fen.toString();
}
public static String generatePosition(BitBoard board) {
StringBuffer fen = new StringBuffer();
for(int rank = 7; rank >= 0; rank--) {
int emptyCount = 0;
for(int file = 0; file < 8; file++) {
long pos = 1L<<(rank<<3)<<file;
String symbol = getSymbol((byte)
(((board.getBitmapBlack()&pos) == 0 ? Piece.WHITE : Piece.BLACK) | board.getPiece(pos)));
if(symbol == null) {
emptyCount++;
} else {
if(emptyCount > 0) {
fen.append(emptyCount);
emptyCount = 0;
}
fen.append(symbol);
}
}
if(emptyCount > 0) {
fen.append(emptyCount);
}
if(rank > 0) {
fen.append("/");
}
}
return fen.toString();
}
static String getSymbol(byte piece) {
byte pieceType = EngineUtils.getType(piece);
if(pieceType == Piece.EMPTY) {
return null;
}
String symbol = null;
if(pieceType == Piece.PAWN) {
symbol = "p";
} else if(pieceType == Piece.KNIGHT) {
symbol = "n";
} else if(pieceType == Piece.BISHOP) {
symbol = "b";
} else if(pieceType == Piece.ROOK) {
symbol = "r";
} else if(pieceType == Piece.QUEEN) {
symbol = "q";
} else if(pieceType == Piece.KING) {
symbol = "k";
}
if(EngineUtils.getColor(piece) == Piece.BLACK) {
return symbol;
} else {
return symbol.toUpperCase();
}
}
public static BitBoard loadPosition(String string, BitBoard board) {
board.clear();
String[] fields = StringUtils.split(string);
String[] ranks = StringUtils.split(fields[0], '/');
for(int rank = 7; rank >= 0; rank--) {
int file = 0;
for(int j = 0; j < ranks[7-rank].length(); j++) {
char c = ranks[7-rank].charAt(j);
switch(c) {
case 'P':
board.setPiece(file, rank, (byte) (Piece.PAWN | Piece.WHITE));
break;
case 'p':
board.setPiece(file, rank, (byte) (Piece.PAWN | Piece.BLACK));
break;
case 'R':
board.setPiece(file, rank, (byte) (Piece.ROOK | Piece.WHITE));
break;
case 'r':
board.setPiece(file, rank, (byte) (Piece.ROOK | Piece.BLACK));
break;
case 'N':
board.setPiece(file, rank, (byte) (Piece.KNIGHT | Piece.WHITE));
break;
case 'n':
board.setPiece(file, rank, (byte) (Piece.KNIGHT | Piece.BLACK));
break;
case 'B':
board.setPiece(file, rank, (byte) (Piece.BISHOP | Piece.WHITE));
break;
case 'b':
board.setPiece(file, rank, (byte) (Piece.BISHOP | Piece.BLACK));
break;
case 'Q':
board.setPiece(file, rank, (byte) (Piece.QUEEN | Piece.WHITE));
break;
case 'q':
board.setPiece(file, rank, (byte) (Piece.QUEEN | Piece.BLACK));
break;
case 'K':
board.setPiece(file, rank, (byte) (Piece.KING | Piece.WHITE));
break;
case 'k':
board.setPiece(file, rank, (byte) (Piece.KING | Piece.BLACK));
break;
}
if(c >= '1' && c <= '8') {
file += c - '1';
}
file++;
}
}
board.setPlayer("b".equals(fields[1]) ? Piece.BLACK : Piece.WHITE);
board.setCastlingOptions((byte)
((fields[2].contains("K") ? BitBoard.CASTLE_WKS : 0) |
(fields[2].contains("Q") ? BitBoard.CASTLE_WQS : 0) |
(fields[2].contains("k") ? BitBoard.CASTLE_BKS : 0) |
(fields[2].contains("q") ? BitBoard.CASTLE_BQS : 0)));
if(fields[3].length() == 2) {
board.setEnPassantFile(FILES.indexOf(fields[3].charAt(0)));
} else {
board.setEnPassantFile(-1);
}
board.setMoveNumber(Short.parseShort(fields[5]));
return board;
}
public static BitBoard getBoard(String fen) {
BitBoard board = new BitBoard();
loadPosition(fen, board);
return board;
}
public static String convertStyle12(String style12) {
return convertStyle12(Arrays.asList(StringUtils.split(style12)));
}
public static String convertStyle12(List<String> fields) {
StringBuffer fen = new StringBuffer();
for(int i = 0; i < 8; i++) {
int eCount = 0;
String line = fields.get(i + 1);
for(int j = 0; j < line.length(); j++) {
if(line.charAt(j) == '-') {
eCount++;
} else {
if(eCount > 0) {
fen.append(eCount);
eCount = 0;
}
fen.append(line.charAt(j));
}
}
if(eCount > 0) {
fen.append(eCount);
}
if(i < 7) {
fen.append("/");
}
}
fen.append(" ").append(fields.get(9).toLowerCase()).append(" ");
StringBuffer buf = new StringBuffer();
if("1".equals(fields.get(11))) {
buf.append("K");
}
if("1".equals(fields.get(12))) {
buf.append("Q");
}
if("1".equals(fields.get(13))) {
buf.append("k");
}
if("1".equals(fields.get(14))) {
buf.append("q");
}
fen.append(buf.length() == 0 ? "-" : buf.toString()).append(" ");
if("-1".equals(fields.get(10))) {
fen.append("- ");
} else {
fen.append(FILES.charAt(Integer.parseInt(fields.get(10))));
fen.append("B".equals(fields.get(9)) ? "3" : "6").append(" ");
}
fen.append(fields.get(15)).append(" ");
fen.append(fields.get(26));
return fen.toString();
}
}