diff --git a/src/dev/kske/chess/board/Bishop.java b/src/dev/kske/chess/board/Bishop.java index 4b2d8b0..9412a30 100644 --- a/src/dev/kske/chess/board/Bishop.java +++ b/src/dev/kske/chess/board/Bishop.java @@ -65,5 +65,5 @@ public class Bishop extends Piece { } @Override - public Type getType() { return Type.BISHOP; } + public int getValue() { return 30; } } diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java index 7304f64..d6c440f 100644 --- a/src/dev/kske/chess/board/Board.java +++ b/src/dev/kske/chess/board/Board.java @@ -10,7 +10,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import dev.kske.chess.board.Piece.Color; -import dev.kske.chess.board.Piece.Type; /** * Project: Chess
@@ -87,7 +86,7 @@ public class Board { move.execute(this); // Update the king's position if the moved piece is the king - if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.getDest()); + if (piece instanceof King) kingPos.put(piece.getColor(), move.getDest()); // Update log log.add(move, piece, capturePiece); @@ -118,29 +117,30 @@ public class Board { dest = Position.fromLAN(m.group("toSquare")); if (m.group("fromSquare") != null) pos = Position.fromLAN(m.group("fromSquare")); else { - Type type = Type.fromFirstChar(m.group("pieceType").charAt(0)); - char file; - int rank; + Class pieceClass = Piece.fromFirstChar(m.group("pieceType").charAt(0)); + char file; + int rank; if (m.group("fromFile") != null) { file = m.group("fromFile").charAt(0); - rank = get(type, file); + rank = get(pieceClass, file); pos = Position.fromLAN(String.format("%c%d", file, rank)); } else if (m.group("fromRank") != null) { rank = Integer.parseInt(m.group("fromRank").substring(0, 1)); - file = get(type, rank); + file = get(pieceClass, rank); pos = Position.fromLAN(String.format("%c%d", file, rank)); - } else pos = get(type, dest); + } else pos = get(pieceClass, dest); } move = new Move(pos, dest); break; case "pawnCapture": dest = Position.fromLAN(m.group("toSquare")); char file = m.group("fromFile").charAt(0); - int rank = m.group("fromRank") == null ? get(Type.PAWN, file) : Integer.parseInt(m.group("fromRank")); + int rank = m.group("fromRank") == null ? get(Pawn.class, file) : Integer.parseInt(m.group("fromRank")); pos = Position.fromLAN(String.format("%c%d", file, rank)); if (m.group("promotedTo") != null) { } + move = new Move(pos, dest); break; case "pawnPush": dest = Position.fromLAN(m.group("toSquare")); @@ -151,6 +151,7 @@ public class Board { if (boardArr[dest.x][dest.y + step] != null) pos = new Position(dest.x, dest.y + step); // Double step forward else pos = new Position(dest.x, dest.y + 2 * step); + move = new Move(pos, dest); break; case "castling": pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0); @@ -175,7 +176,7 @@ public class Board { move.revert(this, moveNode.capturedPiece); // Update the king's position if the moved piece is the king - if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.getPos()); + if (getPos(move) instanceof King) kingPos.put(getPos(move).getColor(), move.getPos()); // Update log log.removeLast(); @@ -322,30 +323,30 @@ public class Board { /** * Searches for a {@link Piece} inside a file (A - H). * - * @param type The {@link Type} of the piece to search for - * @param file The file in which to search for the piece + * @param pieceClass The class of the piece to search for + * @param file The file in which to search for the piece * @return The rank (1 - 8) of the first piece with the specified type and * current color in the file, or {@code -1} if there isn't any */ - public int get(Type type, char file) { + public int get(Class pieceClass, char file) { int x = file - 97; for (int i = 0; i < 8; i++) - if (boardArr[x][i] != null && boardArr[x][i].getType() == type && boardArr[x][i].getColor() == log.getActiveColor()) return 8 - i; + if (boardArr[x][i] != null && boardArr[x][i].getClass() == pieceClass && boardArr[x][i].getColor() == log.getActiveColor()) return 8 - i; return -1; } /** * Searches for a {@link Piece} inside a rank (1 - 8). * - * @param type The {@link Type} of the piece to search for - * @param rank The rank in which to search for the piece + * @param pieceClass The class of the piece to search for + * @param rank The rank in which to search for the piece * @return The file (A - H) of the first piece with the specified type and * current color in the file, or {@code -} if there isn't any */ - public char get(Type type, int rank) { + public char get(Class pieceClass, int rank) { int y = rank - 1; for (int i = 0; i < 8; i++) - if (boardArr[i][y] != null && boardArr[i][y].getType() == type && boardArr[i][y].getColor() == log.getActiveColor()) + if (boardArr[i][y] != null && boardArr[i][y].getClass() == pieceClass && boardArr[i][y].getColor() == log.getActiveColor()) return (char) (i + 97); return '-'; } @@ -353,14 +354,14 @@ public class Board { /** * Searches for a {@link Piece} that can move to a {@link Position}. * - * @param type The {@link Type} of the piece to search for - * @param dest The destination that the piece is required to reach + * @param pieceClass The class of the piece to search for + * @param dest The destination that the piece is required to reach * @return The position of a piece that can move to the specified destination */ - public Position get(Type type, Position dest) { + public Position get(Class pieceClass, Position dest) { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) - if (boardArr[i][j] != null && boardArr[i][j].getType() == type && boardArr[i][j].getColor() == log.getActiveColor()) { + if (boardArr[i][j] != null && boardArr[i][j].getClass() == pieceClass && boardArr[i][j].getColor() == log.getActiveColor()) { Position pos = new Position(i, j); if (boardArr[i][j].isValidMove(new Move(pos, dest))) return pos; } diff --git a/src/dev/kske/chess/board/FENString.java b/src/dev/kske/chess/board/FENString.java index 0dbb3e5..8f27140 100644 --- a/src/dev/kske/chess/board/FENString.java +++ b/src/dev/kske/chess/board/FENString.java @@ -164,7 +164,7 @@ public class FENString { } // Write piece character - char p = piece.getType().firstChar(); + char p = piece.firstChar(); sb.append(piece.getColor() == Color.WHITE ? Character.toUpperCase(p) : p); } } diff --git a/src/dev/kske/chess/board/King.java b/src/dev/kske/chess/board/King.java index cde5a98..6807bb3 100644 --- a/src/dev/kske/chess/board/King.java +++ b/src/dev/kske/chess/board/King.java @@ -63,10 +63,10 @@ public class King extends Piece { private boolean canCastle(Position kingPos, Position freeDest, Position rookPos, Position jumpPos) { Piece rook = board.get(rookPos); - return rook != null && rook.getType() == Type.ROOK && isFreePath(new Move(kingPos, freeDest)) - && !board.isAttacked(kingPos, getColor().opposite()) && !board.isAttacked(jumpPos, getColor().opposite()); + return rook != null && rook instanceof Rook && isFreePath(new Move(kingPos, freeDest)) && !board.isAttacked(kingPos, getColor().opposite()) + && !board.isAttacked(jumpPos, getColor().opposite()); } @Override - public Type getType() { return Type.KING; } -} + public int getValue() { return 0; } +} \ No newline at end of file diff --git a/src/dev/kske/chess/board/Knight.java b/src/dev/kske/chess/board/Knight.java index cbaf67a..9e54fd8 100644 --- a/src/dev/kske/chess/board/Knight.java +++ b/src/dev/kske/chess/board/Knight.java @@ -45,5 +45,8 @@ public class Knight extends Piece { } @Override - public Type getType() { return Type.KNIGHT; } + public int getValue() { return 35; } + + @Override + public char firstChar() { return 'n'; } } diff --git a/src/dev/kske/chess/board/Log.java b/src/dev/kske/chess/board/Log.java index a54b3bb..9d60002 100644 --- a/src/dev/kske/chess/board/Log.java +++ b/src/dev/kske/chess/board/Log.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.Objects; import dev.kske.chess.board.Piece.Color; -import dev.kske.chess.board.Piece.Type; /** * Project: Chess
@@ -78,14 +77,14 @@ public class Log implements Iterable { * @param capturedPiece The piece captured with the move */ public void add(Move move, Piece piece, Piece capturedPiece) { - enPassant = piece.getType() == Type.PAWN && move.getyDist() == 2 ? new Position(move.getPos().x, move.getPos().y + move.getySign()) : null; + enPassant = piece instanceof Pawn && move.getyDist() == 2 ? new Position(move.getPos().x, move.getPos().y + move.getySign()) : null; if (activeColor == Color.BLACK) ++fullmoveNumber; - if (piece.getType() == Type.PAWN || capturedPiece != null) halfmoveClock = 0; + if (piece instanceof Pawn || capturedPiece != null) halfmoveClock = 0; else++halfmoveClock; activeColor = activeColor.opposite(); // Disable castling rights if a king or a rook has been moved - if (piece.getType() == Type.KING || piece.getType() == Type.ROOK) disableCastlingRights(piece, move.getPos()); + if (piece instanceof King || piece instanceof Rook) disableCastlingRights(piece, move.getPos()); final MoveNode leaf = new MoveNode(move, capturedPiece, castlingRights.clone(), enPassant, activeColor, fullmoveNumber, halfmoveClock); @@ -170,11 +169,11 @@ public class Log implements Iterable { private void disableCastlingRights(Piece piece, Position initialPosition) { // Kingside - if (piece.getType() == Type.KING || piece.getType() == Type.ROOK && initialPosition.x == 7) + if (piece instanceof King || piece instanceof Rook && initialPosition.x == 7) castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_KINGSIDE : MoveNode.BLACK_KINGSIDE] = false; // Queenside - if (piece.getType() == Type.KING || piece.getType() == Type.ROOK && initialPosition.x == 0) + if (piece instanceof King || piece instanceof Rook && initialPosition.x == 0) castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_QUEENSIDE : MoveNode.BLACK_QUEENSIDE] = false; } diff --git a/src/dev/kske/chess/board/Pawn.java b/src/dev/kske/chess/board/Pawn.java index 3f7ddf9..177abba 100644 --- a/src/dev/kske/chess/board/Pawn.java +++ b/src/dev/kske/chess/board/Pawn.java @@ -82,5 +82,5 @@ public class Pawn extends Piece { } @Override - public Type getType() { return Type.PAWN; } + public int getValue() { return 10; } } diff --git a/src/dev/kske/chess/board/Piece.java b/src/dev/kske/chess/board/Piece.java index 5fc1fd6..848dca5 100644 --- a/src/dev/kske/chess/board/Piece.java +++ b/src/dev/kske/chess/board/Piece.java @@ -57,9 +57,7 @@ public abstract class Piece implements Cloneable { * @param move The move to check * @return {@code false} if the move's destination is from the same team */ - protected final boolean checkDestination(Move move) { - return board.getDest(move) == null || board.getDest(move).getColor() != getColor(); - } + protected final boolean checkDestination(Move move) { return board.getDest(move) == null || board.getDest(move).getColor() != getColor(); } @Override public Object clone() { @@ -72,14 +70,11 @@ public abstract class Piece implements Cloneable { return piece; } - public abstract Type getType(); - - public Color getColor() { return color; } + @Override + public String toString() { return getClass().getSimpleName(); } @Override - public int hashCode() { - return Objects.hash(color); - } + public int hashCode() { return Objects.hash(color); } @Override public boolean equals(Object obj) { @@ -90,52 +85,50 @@ public abstract class Piece implements Cloneable { return color == other.color; } - public static enum Type { + /** + * @return the standard value of this {@link Piece} that can be used for board + * evaluation + */ + public abstract int getValue(); - KING, QUEEN, ROOK, KNIGHT, BISHOP, PAWN; + /** + * @return The first character of this {@link Piece} in algebraic notation and + * lower case + */ + public char firstChar() { return Character.toLowerCase(toString().charAt(0)); } - /** - * @return The first character of this {@link Type} in algebraic notation and - * lower case - */ - public char firstChar() { - return this == KNIGHT ? 'n' : Character.toLowerCase(this.toString().charAt(0)); - } - - public static Type fromFirstChar(char firstChar) { - switch (Character.toLowerCase(firstChar)) { - case 'k': - return KING; - case 'q': - return QUEEN; - case 'r': - return ROOK; - case 'n': - return KNIGHT; - case 'b': - return BISHOP; - case 'p': - return PAWN; - default: - return null; - } + public static Class fromFirstChar(char firstChar) { + switch (Character.toLowerCase(firstChar)) { + case 'k': + return King.class; + case 'q': + return Queen.class; + case 'r': + return Rook.class; + case 'n': + return Knight.class; + case 'b': + return Bishop.class; + case 'p': + return Pawn.class; + default: + return null; } } + /** + * @return the {@link Color} of this {@link Piece} + */ + public Color getColor() { return color; } + public static enum Color { WHITE, BLACK; - public static Color fromFirstChar(char c) { - return Character.toLowerCase(c) == 'w' ? WHITE : BLACK; - } + public static Color fromFirstChar(char c) { return Character.toLowerCase(c) == 'w' ? WHITE : BLACK; } - public char firstChar() { - return this == WHITE ? 'w' : 'b'; - } + public char firstChar() { return this == WHITE ? 'w' : 'b'; } - public Color opposite() { - return this == WHITE ? BLACK : WHITE; - } + public Color opposite() { return this == WHITE ? BLACK : WHITE; } } } diff --git a/src/dev/kske/chess/board/Queen.java b/src/dev/kske/chess/board/Queen.java index 3932b95..b2482ce 100644 --- a/src/dev/kske/chess/board/Queen.java +++ b/src/dev/kske/chess/board/Queen.java @@ -101,5 +101,5 @@ public class Queen extends Piece { } @Override - public Type getType() { return Type.QUEEN; } + public int getValue() { return 90; } } diff --git a/src/dev/kske/chess/board/Rook.java b/src/dev/kske/chess/board/Rook.java index 590e49e..b2efd5c 100644 --- a/src/dev/kske/chess/board/Rook.java +++ b/src/dev/kske/chess/board/Rook.java @@ -65,5 +65,5 @@ public class Rook extends Piece { } @Override - public Type getType() { return Type.ROOK; } + public int getValue() { return 50; } } diff --git a/src/dev/kske/chess/game/ai/MoveProcessor.java b/src/dev/kske/chess/game/ai/MoveProcessor.java index 2c73ddd..112bc30 100644 --- a/src/dev/kske/chess/game/ai/MoveProcessor.java +++ b/src/dev/kske/chess/game/ai/MoveProcessor.java @@ -5,10 +5,16 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import dev.kske.chess.board.Bishop; import dev.kske.chess.board.Board; +import dev.kske.chess.board.King; +import dev.kske.chess.board.Knight; import dev.kske.chess.board.Move; +import dev.kske.chess.board.Pawn; +import dev.kske.chess.board.Piece; import dev.kske.chess.board.Piece.Color; -import dev.kske.chess.board.Piece.Type; +import dev.kske.chess.board.Queen; +import dev.kske.chess.board.Rook; /** * Project: Chess
@@ -28,35 +34,35 @@ public class MoveProcessor implements Callable { private Move bestMove; - private static final Map positionScores; + private static final Map, int[][]> positionScores; static { positionScores = new HashMap<>(); - positionScores.put(Type.KING, + positionScores.put(King.class, new int[][] { new int[] { -3, -4, -4, -5, -5, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -2, -3, -3, -2, -2, -2, -2, -1 }, new int[] { -1, -2, -2, -2, -2, -2, -2, -1 }, new int[] { 2, 2, 0, 0, 0, 0, 2, 2 }, new int[] { 2, 3, 1, 0, 0, 1, 3, 2 } }); - positionScores.put(Type.QUEEN, + positionScores.put(Queen.class, new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, -2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { 0, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 0, 0, 0, 0, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } }); - positionScores.put(Type.ROOK, + positionScores.put(Rook.class, new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { 0, 0, 0, 1, 1, 0, 0, 0 } }); - positionScores.put(Type.KNIGHT, + positionScores.put(Knight.class, new int[][] { new int[] { -5, -4, -3, -3, -3, -3, -4, -5 }, new int[] { -4, -2, 0, 0, 0, 0, -2, -4 }, new int[] { -3, 0, 1, 2, 2, 1, 0, -3 }, new int[] { -3, 1, 2, 2, 2, 2, 1, -3 }, new int[] { -3, 0, 2, 2, 2, 2, 0, -1 }, new int[] { -3, 1, 1, 2, 2, 1, 1, -3 }, new int[] { -4, -2, 0, 1, 1, 0, -2, -4 }, new int[] { -5, -4, -3, -3, -3, -3, -4, -5 } }); - positionScores.put(Type.BISHOP, + positionScores.put(Bishop.class, new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, 2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 1, 0, 0, 0, 0, 1, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } }); - positionScores.put(Type.PAWN, + positionScores.put(Pawn.class, new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 5, 5, 5, 5, 5, 5, 5, 5 }, new int[] { 1, 1, 2, 3, 3, 2, 1, 1 }, new int[] { 0, 0, 1, 3, 3, 1, 0, 0 }, new int[] { 0, 0, 0, 2, 2, 0, 0, 0 }, new int[] { 0, 0, -1, 0, 0, -1, 0, 0 }, new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } }); @@ -108,25 +114,9 @@ public class MoveProcessor implements Callable { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) if (board.getBoardArr()[i][j] != null && board.getBoardArr()[i][j].getColor() == color) { - switch (board.getBoardArr()[i][j].getType()) { - case QUEEN: - score += 90; - break; - case ROOK: - score += 50; - break; - case KNIGHT: - score += 30; - break; - case BISHOP: - score += 30; - break; - case PAWN: - score += 10; - break; - } - if (positionScores.containsKey(board.getBoardArr()[i][j].getType())) - score += positionScores.get(board.getBoardArr()[i][j].getType())[i][color == Color.WHITE ? j : 7 - j]; + score += board.getBoardArr()[i][j].getValue(); + if (positionScores.containsKey(board.getBoardArr()[i][j].getClass())) + score += positionScores.get(board.getBoardArr()[i][j].getClass())[i][color == Color.WHITE ? j : 7 - j]; } return score; } diff --git a/src/dev/kske/chess/io/TextureUtil.java b/src/dev/kske/chess/io/TextureUtil.java index 25ac288..79d251b 100644 --- a/src/dev/kske/chess/io/TextureUtil.java +++ b/src/dev/kske/chess/io/TextureUtil.java @@ -37,7 +37,7 @@ public class TextureUtil { * @return The fitting texture */ public static Image getPieceTexture(Piece piece) { - String key = piece.getType().toString().toLowerCase() + "_" + piece.getColor().toString().toLowerCase(); + String key = piece.toString().toLowerCase() + "_" + piece.getColor().toString().toLowerCase(); return scaledTextures.get(key); }