Working on board loading from FEN-encoded string

This commit is contained in:
Kai S. K. Engelbart 2019-08-05 21:02:54 +02:00
parent 1923dbf27a
commit f266eaa4cd
5 changed files with 102 additions and 27 deletions

View File

@ -64,7 +64,7 @@ public class Board implements Cloneable {
kingPos = new HashMap<>(); kingPos = new HashMap<>();
castlingRights = new HashMap<>(); castlingRights = new HashMap<>();
log = new Log(); log = new Log();
initializeDefaultPositions(); initDefaultPositions();
} }
/** /**
@ -327,7 +327,7 @@ public class Board implements Cloneable {
/** /**
* Initialized the board array with the default chess pieces and positions. * Initialized the board array with the default chess pieces and positions.
*/ */
public void initializeDefaultPositions() { public void initDefaultPositions() {
// Initialize pawns // Initialize pawns
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
boardArr[i][1] = new Pawn(Color.BLACK, this); boardArr[i][1] = new Pawn(Color.BLACK, this);
@ -383,34 +383,63 @@ public class Board implements Cloneable {
} }
/** /**
* @return A new instance of this class with a shallow copy of both * Initialized the board with a position specified in a FEN-encoded string.
* {@code kingPos} and {code boardArr} *
* @param fen The FEN-encoded string representing target state of the board
*/ */
@Override public void initFromFEN(String fen) {
public Object clone() { String[] parts = fen.split(" ");
Board board = null; log.reset();
try {
board = (Board) super.clone(); // Piece placement (from white's perspective)
} catch (CloneNotSupportedException ex) { String[] rows = parts[0].split("/");
ex.printStackTrace(); for (int i = 0; i < 8; i++) {
char[] places = rows[i].toCharArray();
for (int j = 0, k = 0; k < places.length; j++, k++) {
if (Character.isDigit(places[k])) {
for (int l = j; l < Character.digit(places[k], 10); l++, j++)
boardArr[j][i] = null;
--j;
}
else {
Color color = Character.isUpperCase(places[k]) ? Color.WHITE : Color.BLACK;
switch (Character.toLowerCase(places[k])) {
case 'k':
boardArr[j][i] = new King(color, this);
kingPos.put(color, new Position(j, i));
break;
case 'q':
boardArr[j][i] = new Queen(color, this);
break;
case 'r':
boardArr[j][i] = new Rook(color, this);
break;
case 'n':
boardArr[j][i] = new Knight(color, this);
break;
case 'b':
boardArr[j][i] = new Bishop(color, this);
break;
case 'p':
boardArr[j][i] = new Pawn(color, this);
break;
default:
System.err.printf("Unknown character '%c' in board declaration of FEN string '%s'%n",
places[k],
fen);
}
}
} }
board.boardArr = new Piece[8][8];
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
if (boardArr[i][j] == null) continue;
board.boardArr[i][j] = (Piece) boardArr[i][j].clone();
board.boardArr[i][j].board = board;
} }
board.kingPos = new HashMap<>(); // Active color
board.kingPos.putAll(kingPos); log.setActiveColor(Color.fromFirstChar(parts[1].charAt(0)));
board.log = (Log) log.clone();
return board; // TODO: other fields, synchronize with log and game
} }
/** /**
* @return A FEN string representing the board * @return A FEN-encoded string representing the board
*/ */
public String toFEN() { public String toFEN() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -458,6 +487,7 @@ public class Board implements Cloneable {
// Active color // Active color
sb.append(" " + log.getActiveColor().firstChar()); sb.append(" " + log.getActiveColor().firstChar());
// Castling Rights
sb.append(' '); sb.append(' ');
StringBuilder castlingSb = new StringBuilder(); StringBuilder castlingSb = new StringBuilder();
if (castlingRights.get(Color.WHITE).get(Type.KING)) castlingSb.append('K'); if (castlingRights.get(Color.WHITE).get(Type.KING)) castlingSb.append('K');
@ -469,7 +499,7 @@ public class Board implements Cloneable {
final LoggedMove lastMove = log.getLast(); final LoggedMove lastMove = log.getLast();
// En passant availabillity // En passant availability
sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN())); sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));
// Halfmove clock // Halfmove clock
@ -481,6 +511,33 @@ public class Board implements Cloneable {
return sb.toString(); return sb.toString();
} }
/**
* @return A new instance of this class with a shallow copy of both
* {@code kingPos} and {code boardArr}
*/
@Override
public Object clone() {
Board board = null;
try {
board = (Board) super.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
board.boardArr = new Piece[8][8];
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
if (boardArr[i][j] == null) continue;
board.boardArr[i][j] = (Piece) boardArr[i][j].clone();
board.boardArr[i][j].board = board;
}
board.kingPos = new HashMap<>();
board.kingPos.putAll(kingPos);
board.log = (Log) log.clone();
return board;
}
public Piece get(Position pos) { public Piece get(Position pos) {
return boardArr[pos.x][pos.y]; return boardArr[pos.x][pos.y];
} }

View File

@ -69,6 +69,8 @@ public class Log implements Cloneable {
public Color getActiveColor() { return activeColor; } public Color getActiveColor() { return activeColor; }
public void setActiveColor(Color activeColor) { this.activeColor = activeColor; }
public List<LoggedMove> getLoggedMoves() { return moves; } public List<LoggedMove> getLoggedMoves() { return moves; }
public static class LoggedMove { public static class LoggedMove {

View File

@ -91,12 +91,16 @@ public abstract class Piece implements Cloneable {
public static enum Color { public static enum Color {
WHITE, BLACK; WHITE, BLACK;
public Color opposite() { public static Color fromFirstChar(char c) {
return this == WHITE ? BLACK : WHITE; return Character.toLowerCase(c) == 'w' ? WHITE : BLACK;
} }
public char firstChar() { public char firstChar() {
return this == WHITE ? 'w' : 'b'; return this == WHITE ? 'w' : 'b';
} }
public Color opposite() {
return this == WHITE ? BLACK : WHITE;
}
} }
} }

View File

@ -89,7 +89,7 @@ public class Game {
public void reset() { public void reset() {
players.values().forEach(Player::cancelMove); players.values().forEach(Player::cancelMove);
board.initializeDefaultPositions(); board.initDefaultPositions();
boardComponent.repaint(); boardComponent.repaint();
overlayComponent.clearDots(); overlayComponent.clearDots();
overlayComponent.clearArrow(); overlayComponent.clearArrow();

View File

@ -82,6 +82,18 @@ public class MenuBar extends JMenuBar {
.setContents(new StringSelection(mainWindow.getGame().getBoard().toFEN()), null)); .setContents(new StringSelection(mainWindow.getGame().getBoard().toFEN()), null));
toolsMenu.add(exportFENMenuItem); toolsMenu.add(exportFENMenuItem);
// TODO: Synchronize with game
JMenuItem loadFromFENMenuItem = new JMenuItem("Load board from FEN");
loadFromFENMenuItem.addActionListener((evt) -> {
mainWindow.getGame().reset();
mainWindow.getGame()
.getBoard()
.initFromFEN(JOptionPane.showInputDialog("Enter a FEN string: "));
mainWindow.getBoardPane().getBoardComponent().repaint();
});
toolsMenu.add(loadFromFENMenuItem);
add(toolsMenu); add(toolsMenu);
} }