Added pawn promotion #11

Merged
CyB3RC0nN0R merged 5 commits from f/pawn_promotion into master 2019-11-05 05:44:11 +01:00
12 changed files with 97 additions and 111 deletions
Showing only changes of commit e955f05016 - Show all commits

View File

@ -65,5 +65,5 @@ public class Bishop extends Piece {
}
@Override
public Type getType() { return Type.BISHOP; }
public int getValue() { return 30; }
}

View File

@ -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: <strong>Chess</strong><br>
@ -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<? extends Piece> 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<? extends Piece> 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<? extends Piece> 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<? extends Piece> 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;
}

View File

@ -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);
}
}

View File

@ -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; }
}

View File

@ -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'; }
}

View File

@ -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: <strong>Chess</strong><br>
@ -78,14 +77,14 @@ public class Log implements Iterable<MoveNode> {
* @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<MoveNode> {
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;
}

View File

@ -82,5 +82,5 @@ public class Pawn extends Piece {
}
@Override
public Type getType() { return Type.PAWN; }
public int getValue() { return 10; }
}

View File

@ -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<? extends Piece> 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; }
}
}

View File

@ -101,5 +101,5 @@ public class Queen extends Piece {
}
@Override
public Type getType() { return Type.QUEEN; }
public int getValue() { return 90; }
}

View File

@ -65,5 +65,5 @@ public class Rook extends Piece {
}
@Override
public Type getType() { return Type.ROOK; }
public int getValue() { return 50; }
}

View File

@ -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: <strong>Chess</strong><br>
@ -28,35 +34,35 @@ public class MoveProcessor implements Callable<ProcessingResult> {
private Move bestMove;
private static final Map<Type, int[][]> positionScores;
private static final Map<Class<? extends Piece>, 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<ProcessingResult> {
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;
}

View File

@ -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);
}