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 b6cfb5674c
commit 9d7d84302e
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
5 changed files with 102 additions and 27 deletions

View File

@ -64,7 +64,7 @@ public class Board implements Cloneable {
kingPos = new HashMap<>();
castlingRights = new HashMap<>();
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.
*/
public void initializeDefaultPositions() {
public void initDefaultPositions() {
// Initialize pawns
for (int i = 0; i < 8; i++) {
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
* {@code kingPos} and {code boardArr}
* Initialized the board with a position specified in a FEN-encoded string.
*
* @param fen The FEN-encoded string representing target state of the board
*/
@Override
public Object clone() {
Board board = null;
try {
board = (Board) super.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
public void initFromFEN(String fen) {
String[] parts = fen.split(" ");
log.reset();
// Piece placement (from white's perspective)
String[] rows = parts[0].split("/");
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<>();
board.kingPos.putAll(kingPos);
board.log = (Log) log.clone();
// Active color
log.setActiveColor(Color.fromFirstChar(parts[1].charAt(0)));
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() {
StringBuilder sb = new StringBuilder();
@ -458,6 +487,7 @@ public class Board implements Cloneable {
// Active color
sb.append(" " + log.getActiveColor().firstChar());
// Castling Rights
sb.append(' ');
StringBuilder castlingSb = new StringBuilder();
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();
// En passant availabillity
// En passant availability
sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));
// Halfmove clock
@ -481,6 +511,33 @@ public class Board implements Cloneable {
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) {
return boardArr[pos.x][pos.y];
}

View File

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

View File

@ -91,12 +91,16 @@ public abstract class Piece implements Cloneable {
public static enum Color {
WHITE, BLACK;
public Color opposite() {
return this == WHITE ? BLACK : WHITE;
public static Color fromFirstChar(char c) {
return Character.toLowerCase(c) == 'w' ? WHITE : BLACK;
}
public char firstChar() {
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() {
players.values().forEach(Player::cancelMove);
board.initializeDefaultPositions();
board.initDefaultPositions();
boardComponent.repaint();
overlayComponent.clearDots();
overlayComponent.clearArrow();

View File

@ -82,6 +82,18 @@ public class MenuBar extends JMenuBar {
.setContents(new StringSelection(mainWindow.getGame().getBoard().toFEN()), null));
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);
}