From f266eaa4cd71586652d5778daae379b5251ca675 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 5 Aug 2019 21:02:54 +0200 Subject: [PATCH] Working on board loading from FEN-encoded string --- src/dev/kske/chess/board/Board.java | 105 +++++++++++++++++++++------- src/dev/kske/chess/board/Log.java | 2 + src/dev/kske/chess/board/Piece.java | 8 ++- src/dev/kske/chess/game/Game.java | 2 +- src/dev/kske/chess/ui/MenuBar.java | 12 ++++ 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java index 2d8ab94..ec597b1 100644 --- a/src/dev/kske/chess/board/Board.java +++ b/src/dev/kske/chess/board/Board.java @@ -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(); - } - 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; + 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.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]; } diff --git a/src/dev/kske/chess/board/Log.java b/src/dev/kske/chess/board/Log.java index e29c61e..b5aae82 100644 --- a/src/dev/kske/chess/board/Log.java +++ b/src/dev/kske/chess/board/Log.java @@ -69,6 +69,8 @@ public class Log implements Cloneable { public Color getActiveColor() { return activeColor; } + public void setActiveColor(Color activeColor) { this.activeColor = activeColor; } + public List getLoggedMoves() { return moves; } public static class LoggedMove { diff --git a/src/dev/kske/chess/board/Piece.java b/src/dev/kske/chess/board/Piece.java index 5df4314..d768f0a 100644 --- a/src/dev/kske/chess/board/Piece.java +++ b/src/dev/kske/chess/board/Piece.java @@ -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; + } } } diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java index dc30852..31443ae 100644 --- a/src/dev/kske/chess/game/Game.java +++ b/src/dev/kske/chess/game/Game.java @@ -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(); diff --git a/src/dev/kske/chess/ui/MenuBar.java b/src/dev/kske/chess/ui/MenuBar.java index ca1e6d3..812a86d 100644 --- a/src/dev/kske/chess/ui/MenuBar.java +++ b/src/dev/kske/chess/ui/MenuBar.java @@ -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); }