Added pawn promotion #11

Merged
CyB3RC0nN0R merged 5 commits from f/pawn_promotion into master 2019-11-05 05:44:11 +01:00
18 changed files with 424 additions and 317 deletions

View File

@ -65,5 +65,5 @@ public class Bishop extends Piece {
} }
@Override @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 java.util.regex.Pattern;
import dev.kske.chess.board.Piece.Color; import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Piece.Type;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
@ -61,9 +60,6 @@ public class Board {
Piece piece = getPos(move); Piece piece = getPos(move);
if (piece == null || !piece.isValidMove(move)) return false; if (piece == null || !piece.isValidMove(move)) return false;
else { else {
// Set type after validation
if (move.type == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL;
// Move piece // Move piece
move(move); move(move);
@ -86,40 +82,11 @@ public class Board {
Piece piece = getPos(move); Piece piece = getPos(move);
Piece capturePiece = getDest(move); Piece capturePiece = getDest(move);
switch (move.type) { // Execute the move
case PAWN_PROMOTION: move.execute(this);
setPos(move, null);
// TODO: Select promotion
setDest(move, new Queen(piece.getColor(), this));
break;
case EN_PASSANT:
setDest(move, piece);
setPos(move, null);
boardArr[move.dest.x][move.dest.y - move.ySign] = null;
break;
case CASTLING:
// Move the king
setDest(move, piece);
setPos(move, null);
// Move the rook
Move rookMove = move.dest.x == 6 ? new Move(7, move.pos.y, 5, move.pos.y) // Kingside
: new Move(0, move.pos.y, 3, move.pos.y); // Queenside
setDest(rookMove, getPos(rookMove));
setPos(rookMove, null);
break;
case UNKNOWN:
System.err.printf("Move of unknown type %s found!%n", move);
case NORMAL:
setDest(move, piece);
setPos(move, null);
break;
default:
System.err.printf("Move %s of unimplemented type found!%n", move);
}
// Update the king's position if the moved piece is the king // Update the king's position if the moved piece is the king
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest); if (piece instanceof King) kingPos.put(piece.getColor(), move.getDest());
// Update log // Update log
log.add(move, piece, capturePiece); log.add(move, piece, capturePiece);
@ -136,57 +103,75 @@ public class Board {
Pattern.compile( Pattern.compile(
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$")); "^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
patterns.put("pawnCapture", patterns.put("pawnCapture",
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)?$")); Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)?$"));
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)$")); patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)$"));
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$")); patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
patterns.forEach((patternName, pattern) -> { patterns.forEach((patternName, pattern) -> {
Matcher m = pattern.matcher(sanMove); Matcher m = pattern.matcher(sanMove);
if (m.find()) { if (m.find()) {
Position pos = null, dest = null; Position pos = null, dest = null;
Move.Type moveType = Move.Type.NORMAL; Move move = null;
switch (patternName) { switch (patternName) {
case "pieceMove": case "pieceMove":
dest = Position.fromLAN(m.group("toSquare")); dest = Position.fromLAN(m.group("toSquare"));
if (m.group("fromSquare") != null) pos = Position.fromLAN(m.group("fromSquare")); if (m.group("fromSquare") != null) pos = Position.fromLAN(m.group("fromSquare"));
else { else {
Type type = Type.fromFirstChar(m.group("pieceType").charAt(0)); Class<? extends Piece> pieceClass = Piece.fromFirstChar(m.group("pieceType").charAt(0));
char file; char file;
int rank; int rank;
if (m.group("fromFile") != null) { if (m.group("fromFile") != null) {
file = m.group("fromFile").charAt(0); file = m.group("fromFile").charAt(0);
rank = get(type, file); rank = get(pieceClass, file);
pos = Position.fromLAN(String.format("%c%d", file, rank)); pos = Position.fromLAN(String.format("%c%d", file, rank));
} else if (m.group("fromRank") != null) { } else if (m.group("fromRank") != null) {
rank = Integer.parseInt(m.group("fromRank").substring(0, 1)); 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)); 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; break;
case "pawnCapture": case "pawnCapture":
dest = Position.fromLAN(m.group("toSquare"));
char file = m.group("fromFile").charAt(0); 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"));
dest = Position.fromLAN(m.group("toSquare"));
pos = Position.fromLAN(String.format("%c%d", file, rank)); pos = Position.fromLAN(String.format("%c%d", file, rank));
if (m.group("promotedTo") != null) {
try {
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
e.printStackTrace();
}
} else move = new Move(pos, dest);
break; break;
case "pawnPush": case "pawnPush":
dest = Position.fromLAN(m.group("toSquare")); dest = Position.fromLAN(m.group("toSquare"));
// TODO: Pawn promotion
int step = log.getActiveColor() == Color.WHITE ? 1 : -1; int step = log.getActiveColor() == Color.WHITE ? 1 : -1;
// One step forward // One step forward
if (boardArr[dest.x][dest.y + step] != null) pos = new Position(dest.x, dest.y + step); if (boardArr[dest.x][dest.y + step] != null) pos = new Position(dest.x, dest.y + step);
// Double step forward // Double step forward
else pos = new Position(dest.x, dest.y + 2 * step); else pos = new Position(dest.x, dest.y + 2 * step);
if (m.group("promotedTo") != null) {
try {
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
e.printStackTrace();
}
} else move = new Move(pos, dest);
break; break;
case "castling": case "castling":
pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0); pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0);
dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y); dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y);
moveType = Move.Type.CASTLING; move = new Castling(pos, dest);
break; break;
} }
move(new Move(pos, dest, moveType)); move(move);
return; return;
} }
}); });
@ -196,43 +181,14 @@ public class Board {
* Reverts the last move and removes it from the log. * Reverts the last move and removes it from the log.
*/ */
public void revert() { public void revert() {
MoveNode moveNode = log.getLast(); MoveNode moveNode = log.getLast();
Move move = moveNode.move; Move move = moveNode.move;
Piece capturedPiece = moveNode.capturedPiece;
switch (move.type) { // Revert the move
case PAWN_PROMOTION: move.revert(this, moveNode.capturedPiece);
setPos(move, new Pawn(getDest(move).getColor(), this));
setDest(move, capturedPiece);
break;
case EN_PASSANT:
setPos(move, getDest(move));
setDest(move, null);
boardArr[move.dest.x][move.dest.y - move.ySign] = new Pawn(getPos(move).getColor().opposite(), this);
break;
case CASTLING:
// Move the king
setPos(move, getDest(move));
setDest(move, null);
// Move the rook
Move rookMove = move.dest.x == 6 ? new Move(5, move.pos.y, 7, move.pos.y) // Kingside
: new Move(3, move.pos.y, 0, move.pos.y); // Queenside
setDest(rookMove, getPos(rookMove));
setPos(rookMove, null);
break;
case UNKNOWN:
System.err.printf("Move of unknown type %s found!%n", move);
case NORMAL:
setPos(move, getDest(move));
setDest(move, capturedPiece);
break;
default:
System.err.printf("Move %s of unimplemented type found!%n", move);
}
// Update the king's position if the moved piece is the king // Update the king's position if the moved piece is the king
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos); if (getPos(move) instanceof King) kingPos.put(getPos(move).getColor(), move.getPos());
// Update log // Update log
log.removeLast(); log.removeLast();
@ -379,30 +335,30 @@ public class Board {
/** /**
* Searches for a {@link Piece} inside a file (A - H). * Searches for a {@link Piece} inside a file (A - H).
* *
* @param type The {@link Type} of the piece to search for * @param pieceClass The class of the piece to search for
* @param file The file in which to search for the piece * @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 * @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 * 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; int x = file - 97;
for (int i = 0; i < 8; i++) 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; return -1;
} }
/** /**
* Searches for a {@link Piece} inside a rank (1 - 8). * Searches for a {@link Piece} inside a rank (1 - 8).
* *
* @param type The {@link Type} of the piece to search for * @param pieceClass The class of the piece to search for
* @param rank The rank in which to search for the piece * @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 * @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 * 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; int y = rank - 1;
for (int i = 0; i < 8; i++) 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 (char) (i + 97);
return '-'; return '-';
} }
@ -410,14 +366,14 @@ public class Board {
/** /**
* Searches for a {@link Piece} that can move to a {@link Position}. * Searches for a {@link Piece} that can move to a {@link Position}.
* *
* @param type The {@link Type} of the piece to search for * @param pieceClass The class of the piece to search for
* @param dest The destination that the piece is required to reach * @param dest The destination that the piece is required to reach
* @return The position of a piece that can move to the specified destination * @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 i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) 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); Position pos = new Position(i, j);
if (boardArr[i][j].isValidMove(new Move(pos, dest))) return pos; if (boardArr[i][j].isValidMove(new Move(pos, dest))) return pos;
} }
@ -436,13 +392,13 @@ public class Board {
* @param move The move from which position to return a piece * @param move The move from which position to return a piece
* @return The piece at the position of the move * @return The piece at the position of the move
*/ */
public Piece getPos(Move move) { return get(move.pos); } public Piece getPos(Move move) { return get(move.getPos()); }
/** /**
* @param move The move from which destination to return a piece * @param move The move from which destination to return a piece
* @return The piece at the destination of the move * @return The piece at the destination of the move
*/ */
public Piece getDest(Move move) { return get(move.dest); } public Piece getDest(Move move) { return get(move.getDest()); }
/** /**
* Places a piece at the position of a move. * Places a piece at the position of a move.
@ -450,7 +406,7 @@ public class Board {
* @param move The move at which position to place the piece * @param move The move at which position to place the piece
* @param piece The piece to place * @param piece The piece to place
*/ */
public void setPos(Move move, Piece piece) { set(move.pos, piece); } public void setPos(Move move, Piece piece) { set(move.getPos(), piece); }
/** /**
* Places a piece at the destination of a move. * Places a piece at the destination of a move.
@ -458,7 +414,7 @@ public class Board {
* @param move The move at which destination to place the piece * @param move The move at which destination to place the piece
* @param piece The piece to place * @param piece The piece to place
*/ */
public void setDest(Move move, Piece piece) { set(move.dest, piece); } public void setDest(Move move, Piece piece) { set(move.getDest(), piece); }
/** /**
* @return The board array * @return The board array

View File

@ -0,0 +1,35 @@
package dev.kske.chess.board;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>Castling.java</strong><br>
* Created: <strong>2 Nov 2019</strong><br>
*
* @since Chess v0.5-alpha
* @author Kai S. K. Engelbart
*/
public class Castling extends Move {
private final Move rookMove;
public Castling(Position pos, Position dest) {
super(pos, dest);
rookMove = dest.x == 6 ? new Move(7, pos.y, 5, pos.y) : new Move(0, pos.y, 3, pos.y);
}
public Castling(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
@Override
public void execute(Board board) {
// Move the king and the rook
super.execute(board);
rookMove.execute(board);
}
@Override
public void revert(Board board, Piece capturedPiece) {
// Move the king and the rook
super.revert(board, capturedPiece);
rookMove.revert(board, null);
}
}

View File

@ -0,0 +1,35 @@
package dev.kske.chess.board;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>EnPassant.java</strong><br>
* Created: <strong>2 Nov 2019</strong><br>
*
* @since Chess v0.5-alpha
* @author Kai S. K. Engelbart
*/
public class EnPassant extends Move {
private final Position capturePos;
public EnPassant(Position pos, Position dest) {
super(pos, dest);
capturePos = new Position(dest.x, dest.y - ySign);
}
public EnPassant(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
@Override
public void execute(Board board) {
super.execute(board);
board.set(capturePos, null);
}
@Override
public void revert(Board board, Piece capturedPiece) {
super.revert(board, capturedPiece);
board.set(capturePos, new Pawn(board.get(pos).getColor().opposite(), board));
}
public Position getCapturePos() { return capturePos; }
}

View File

@ -164,7 +164,7 @@ public class FENString {
} }
// Write piece character // Write piece character
char p = piece.getType().firstChar(); char p = piece.firstChar();
sb.append(piece.getColor() == Color.WHITE ? Character.toUpperCase(p) : p); sb.append(piece.getColor() == Color.WHITE ? Character.toUpperCase(p) : p);
} }
} }

View File

@ -17,18 +17,9 @@ public class King extends Piece {
@Override @Override
public boolean isValidMove(Move move) { public boolean isValidMove(Move move) {
// Castling return (move.getxDist() == 2 && move.getyDist() == 0
if (move.xDist == 2 && move.yDist == 0) { && (move.getDest().x == 6 && canCastleKingside() || move.getDest().x == 2 && canCastleQueenside()))
if (canCastleKingside()) { || move.getxDist() <= 1 && move.getyDist() <= 1 && checkDestination(move);
move.type = Move.Type.CASTLING;
return true;
}
if (canCastleQueenside()) {
move.type = Move.Type.CASTLING;
return true;
}
}
return move.xDist <= 1 && move.yDist <= 1 && checkDestination(move);
} }
@Override @Override
@ -42,8 +33,8 @@ public class King extends Piece {
} }
// Castling // Castling
if (canCastleKingside()) moves.add(new Move(pos, new Position(6, pos.y), Move.Type.CASTLING)); if (canCastleKingside()) moves.add(new Castling(pos, new Position(6, pos.y)));
if (canCastleQueenside()) moves.add(new Move(pos, new Position(2, pos.y), Move.Type.CASTLING)); if (canCastleQueenside()) moves.add(new Castling(pos, new Position(2, pos.y)));
return moves; return moves;
} }
@ -72,10 +63,10 @@ public class King extends Piece {
private boolean canCastle(Position kingPos, Position freeDest, Position rookPos, Position jumpPos) { private boolean canCastle(Position kingPos, Position freeDest, Position rookPos, Position jumpPos) {
Piece rook = board.get(rookPos); Piece rook = board.get(rookPos);
return rook != null && rook.getType() == Type.ROOK && isFreePath(new Move(kingPos, freeDest)) return rook != null && rook instanceof Rook && isFreePath(new Move(kingPos, freeDest)) && !board.isAttacked(kingPos, getColor().opposite())
&& !board.isAttacked(kingPos, getColor().opposite()) && !board.isAttacked(jumpPos, getColor().opposite()); && !board.isAttacked(jumpPos, getColor().opposite());
} }
@Override @Override
public Type getType() { return Type.KING; } public int getValue() { return 0; }
} }

View File

@ -19,8 +19,8 @@ public class Knight extends Piece {
@Override @Override
public boolean isValidMove(Move move) { public boolean isValidMove(Move move) {
return Math.abs(move.xDist - move.yDist) == 1 return Math.abs(move.getxDist() - move.getyDist()) == 1
&& (move.xDist == 1 && move.yDist == 2 || move.xDist == 2 && move.yDist == 1) && checkDestination(move); && (move.getxDist() == 1 && move.getyDist() == 2 || move.getxDist() == 2 && move.getyDist() == 1) && checkDestination(move);
} }
private void checkAndInsertMove(List<Move> moves, Position pos, int offsetX, int offsetY) { private void checkAndInsertMove(List<Move> moves, Position pos, int offsetX, int offsetY) {
@ -45,5 +45,8 @@ public class Knight extends Piece {
} }
@Override @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 java.util.Objects;
import dev.kske.chess.board.Piece.Color; import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Piece.Type;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
@ -78,14 +77,14 @@ public class Log implements Iterable<MoveNode> {
* @param capturedPiece The piece captured with the move * @param capturedPiece The piece captured with the move
*/ */
public void add(Move move, Piece piece, Piece capturedPiece) { public void add(Move move, Piece piece, Piece capturedPiece) {
enPassant = piece.getType() == Type.PAWN && move.yDist == 2 ? new Position(move.pos.x, move.pos.y + move.ySign) : 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 (activeColor == Color.BLACK) ++fullmoveNumber;
if (piece.getType() == Type.PAWN || capturedPiece != null) halfmoveClock = 0; if (piece instanceof Pawn || capturedPiece != null) halfmoveClock = 0;
else++halfmoveClock; else++halfmoveClock;
activeColor = activeColor.opposite(); activeColor = activeColor.opposite();
// Disable castling rights if a king or a rook has been moved // Disable castling rights if a king or a rook has been moved
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK) disableCastlingRights(piece, move.pos); if (piece instanceof King || piece instanceof Rook) disableCastlingRights(piece, move.getPos());
final MoveNode leaf = new MoveNode(move, capturedPiece, castlingRights.clone(), enPassant, activeColor, fullmoveNumber, halfmoveClock); 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) { private void disableCastlingRights(Piece piece, Position initialPosition) {
// Kingside // 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; castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_KINGSIDE : MoveNode.BLACK_KINGSIDE] = false;
// Queenside // 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; castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_QUEENSIDE : MoveNode.BLACK_QUEENSIDE] = false;
} }

View File

@ -12,52 +12,58 @@ import java.util.Objects;
*/ */
public class Move { public class Move {
public final Position pos, dest; protected final Position pos, dest;
public final int xDist, yDist, xSign, ySign; protected final int xDist, yDist, xSign, ySign;
public Type type;
public Move(Position pos, Position dest, Type type) { public Move(Position pos, Position dest) {
this.pos = pos; this.pos = pos;
this.dest = dest; this.dest = dest;
this.type = type;
xDist = Math.abs(dest.x - pos.x); xDist = Math.abs(dest.x - pos.x);
yDist = Math.abs(dest.y - pos.y); yDist = Math.abs(dest.y - pos.y);
xSign = (int) Math.signum(dest.x - pos.x); xSign = (int) Math.signum(dest.x - pos.x);
ySign = (int) Math.signum(dest.y - pos.y); ySign = (int) Math.signum(dest.y - pos.y);
} }
public Move(Position pos, Position dest) { public Move(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
this(pos, dest, Type.NORMAL);
public void execute(Board board) {
// Move the piece to the move's destination square and clean the old position
board.set(dest, board.get(pos));
board.set(pos, null);
} }
public Move(int xPos, int yPos, int xDest, int yDest) { public void revert(Board board, Piece capturedPiece) {
this(new Position(xPos, yPos), new Position(xDest, yDest)); // Move the piece to the move's position square and clean the destination
board.set(pos, board.get(dest));
board.set(dest, capturedPiece);
} }
public static Move fromLAN(String move) { public static Move fromLAN(String move) {
return new Move(Position.fromLAN(move.substring(0, 2)), Position pos = Position.fromLAN(move.substring(0, 2));
Position.fromLAN(move.substring(2))); Position dest = Position.fromLAN(move.substring(2));
if (move.length() == 5) {
try {
return new PawnPromotion(pos, dest, Piece.fromFirstChar(move.charAt(4)));
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
e.printStackTrace();
return null;
}
} else return new Move(pos, dest);
} }
public String toLAN() { public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
return pos.toLAN() + dest.toLAN();
}
public boolean isHorizontal() { return yDist == 0; } public boolean isHorizontal() { return getyDist() == 0; }
public boolean isVertical() { return xDist == 0; } public boolean isVertical() { return getxDist() == 0; }
public boolean isDiagonal() { return xDist == yDist; } public boolean isDiagonal() { return getxDist() == getyDist(); }
@Override @Override
public String toString() { public String toString() { return toLAN(); }
return String.format("%s -> %s", pos, dest);
}
@Override @Override
public int hashCode() { public int hashCode() { return Objects.hash(getDest(), getPos(), getxDist(), getxSign(), getyDist(), getySign()); }
return Objects.hash(dest, pos, type, xDist, xSign, yDist, ySign);
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -65,11 +71,19 @@ public class Move {
if (obj == null) return false; if (obj == null) return false;
if (getClass() != obj.getClass()) return false; if (getClass() != obj.getClass()) return false;
Move other = (Move) obj; Move other = (Move) obj;
return Objects.equals(dest, other.dest) && Objects.equals(pos, other.pos) && type == other.type return Objects.equals(getDest(), other.getDest()) && Objects.equals(getPos(), other.getPos()) && getxDist() == other.getxDist()
&& xDist == other.xDist && xSign == other.xSign && yDist == other.yDist && ySign == other.ySign; && getxSign() == other.getxSign() && getyDist() == other.getyDist() && getySign() == other.getySign();
} }
public static enum Type { public Position getPos() { return pos; }
NORMAL, PAWN_PROMOTION, CASTLING, EN_PASSANT, UNKNOWN
} public Position getDest() { return dest; }
public int getxDist() { return xDist; }
public int getyDist() { return yDist; }
public int getxSign() { return xSign; }
public int getySign() { return ySign; }
} }

View File

@ -13,87 +13,74 @@ import java.util.List;
*/ */
public class Pawn extends Piece { public class Pawn extends Piece {
public Pawn(Color color, Board board) { public Pawn(Color color, Board board) { super(color, board); }
super(color, board);
}
@Override @Override
public boolean isValidMove(Move move) { public boolean isValidMove(Move move) {
boolean step = move.isVertical() && move.yDist == 1; boolean step = move.isVertical() && move.getyDist() == 1;
boolean doubleStep = move.isVertical() && move.yDist == 2; boolean doubleStep = move.isVertical() && move.getyDist() == 2;
boolean strafe = move.isDiagonal() && move.xDist == 1; boolean strafe = move.isDiagonal() && move.getxDist() == 1;
boolean enPassant = false; boolean enPassant = strafe && move.getDest().equals(board.getLog().getEnPassant());
if (getColor() == Color.WHITE) doubleStep &= move.pos.y == 6; if (getColor() == Color.WHITE) doubleStep &= move.getPos().y == 6;
else doubleStep &= move.pos.y == 1; else doubleStep &= move.getPos().y == 1;
// Mark move as pawn promotion if necessary return enPassant || (step ^ doubleStep ^ strafe) && move.getySign() == (getColor() == Color.WHITE ? -1 : 1) && isFreePath(move);
if (move.ySign == 1 && move.pos.y == 6 || move.ySign == -1 && move.pos.y == 1)
move.type = Move.Type.PAWN_PROMOTION;
// Mark the move as en passant if necessary
if (strafe && move.dest.equals(board.getLog().getEnPassant())) {
enPassant = true;
move.type = Move.Type.EN_PASSANT;
}
return enPassant || (step ^ doubleStep ^ strafe) && move.ySign == (getColor() == Color.WHITE ? -1 : 1)
&& isFreePath(move);
} }
@Override @Override
protected boolean isFreePath(Move move) { protected boolean isFreePath(Move move) {
// Two steps forward // Two steps forward
if (move.yDist == 2) if (move.getyDist() == 2)
return board.getBoardArr()[move.pos.x][move.dest.y - move.ySign] == null && board.getDest(move) == null; return board.getBoardArr()[move.getPos().x][move.getDest().y - move.getySign()] == null && board.getDest(move) == null;
// One step forward // One step forward
else if (move.xDist == 0) return board.getDest(move) == null; else if (move.getxDist() == 0) return board.getDest(move) == null;
// Capture move // Capture move
else return board.getDest(move) != null && board.getDest(move).getColor() != getColor(); else return board.getDest(move) != null && board.getDest(move).getColor() != getColor();
} }
@Override @Override
protected List<Move> getPseudolegalMoves(Position pos) { protected List<Move> getPseudolegalMoves(Position pos) {
List<Move> moves = new ArrayList<>(); List<Move> moves = new ArrayList<>();
int sign = getColor() == Color.WHITE ? -1 : 1;
int sign = getColor() == Color.WHITE ? -1 : 1; boolean pawnPromotion = sign == 1 && pos.y == 6 || sign == -1 && pos.y == 1;
// Strafe left // Strafe left
if (pos.x > 0) { if (pos.x > 0) addMoveIfValid(moves, pos, new Position(pos.x - 1, pos.y + sign), pawnPromotion);
Move move = new Move(pos, new Position(pos.x - 1, pos.y + sign));
if (isFreePath(move)) moves.add(move);
}
// Strafe right // Strafe right
if (pos.x < 7) { if (pos.x < 7) addMoveIfValid(moves, pos, new Position(pos.x + 1, pos.y + sign), pawnPromotion);
Move move = new Move(pos, new Position(pos.x + 1, pos.y + sign));
if (isFreePath(move)) moves.add(move);
}
// Step forward // Step forward
if (sign == 1 && pos.y < 7 || sign == -1 && pos.y > 0) { if (sign == 1 && pos.y < 7 || sign == -1 && pos.y > 0) addMoveIfValid(moves, pos, new Position(pos.x, pos.y + sign), pawnPromotion);
Move move = new Move(pos, new Position(pos.x, pos.y + sign));
if (isFreePath(move)) moves.add(move);
}
// Double step forward // Double step forward
if (sign == 1 && pos.y == 1 || sign == -1 && pos.y == 6) { if (sign == 1 && pos.y == 1 || sign == -1 && pos.y == 6) addMoveIfValid(moves, pos, new Position(pos.x, pos.y + 2 * sign), pawnPromotion);
Move move = new Move(pos, new Position(pos.x, pos.y + 2 * sign));
if (isFreePath(move)) moves.add(move);
}
// Mark moves as pawn promotion if necessary
if (sign == 1 && pos.y == 6 || sign == -1 && pos.y == 1)
moves.parallelStream().forEach(m -> m.type = Move.Type.PAWN_PROMOTION);
// Add en passant move if necessary // Add en passant move if necessary
if (board.getLog().getEnPassant() != null) { if (board.getLog().getEnPassant() != null) {
Move move = new Move(pos, board.getLog().getEnPassant(), Move.Type.EN_PASSANT); Move move = new EnPassant(pos, board.getLog().getEnPassant());
if (move.isDiagonal() && move.xDist == 1) moves.add(move); if (move.isDiagonal() && move.getxDist() == 1) moves.add(move);
} }
return moves; return moves;
} }
private void addMoveIfValid(List<Move> moves, Position pos, Position dest, boolean pawnPromotion) {
Move move = new Move(pos, dest);
if (isFreePath(move)) {
if (pawnPromotion) {
try {
moves.add(new PawnPromotion(pos, dest, Queen.class));
moves.add(new PawnPromotion(pos, dest, Rook.class));
moves.add(new PawnPromotion(pos, dest, Knight.class));
moves.add(new PawnPromotion(pos, dest, Bishop.class));
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
e.printStackTrace();
}
} else moves.add(move);
}
}
@Override @Override
public Type getType() { return Type.PAWN; } public int getValue() { return 10; }
} }

View File

@ -0,0 +1,81 @@
package dev.kske.chess.board;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import dev.kske.chess.board.Piece.Color;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>PawnPromotion.java</strong><br>
* Created: <strong>2 Nov 2019</strong><br>
*
* @since Chess v0.5-alpha
* @author Kai S. K. Engelbart
*/
public class PawnPromotion extends Move {
private final Class<? extends Piece> promotionPieceClass;
private final Constructor<? extends Piece> promotionPieceConstructor;
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass) throws NoSuchMethodException, SecurityException {
super(pos, dest);
this.promotionPieceClass = promotionPieceClass;
// Cache piece constructor
promotionPieceConstructor = promotionPieceClass.getDeclaredConstructor(Color.class, Board.class);
promotionPieceConstructor.setAccessible(true);
}
public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPiece)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
InstantiationException {
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPiece);
}
@Override
public void execute(Board board) {
try {
board.set(pos, promotionPieceConstructor.newInstance(board.get(pos).getColor(), board));
super.execute(board);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
e.printStackTrace();
}
}
@Override
public void revert(Board board, Piece capturedPiece) {
board.set(dest, new Pawn(board.get(dest).getColor(), board));
super.revert(board, capturedPiece);
}
@Override
public String toLAN() {
char promotionPieceChar = '-';
try {
promotionPieceChar = (char) promotionPieceClass.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException
| InstantiationException e) {
e.printStackTrace();
}
return pos.toLAN() + dest.toLAN() + promotionPieceChar;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Objects.hash(promotionPieceClass);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!super.equals(obj)) return false;
if (getClass() != obj.getClass()) return false;
PawnPromotion other = (PawnPromotion) obj;
return Objects.equals(promotionPieceClass, other.promotionPieceClass);
}
}

View File

@ -44,8 +44,8 @@ public abstract class Piece implements Cloneable {
* @param move The move to check * @param move The move to check
*/ */
protected boolean isFreePath(Move move) { protected boolean isFreePath(Move move) {
for (int i = move.pos.x + move.xSign, j = move.pos.y + move.ySign; i != move.dest.x for (int i = move.getPos().x + move.getxSign(), j = move.getPos().y + move.getySign(); i != move.getDest().x
|| j != move.dest.y; i += move.xSign, j += move.ySign) || j != move.getDest().y; i += move.getxSign(), j += move.getySign())
if (board.getBoardArr()[i][j] != null) return false; if (board.getBoardArr()[i][j] != null) return false;
return checkDestination(move); return checkDestination(move);
} }
@ -57,9 +57,7 @@ public abstract class Piece implements Cloneable {
* @param move The move to check * @param move The move to check
* @return {@code false} if the move's destination is from the same team * @return {@code false} if the move's destination is from the same team
*/ */
protected final boolean checkDestination(Move move) { protected final boolean checkDestination(Move move) { return board.getDest(move) == null || board.getDest(move).getColor() != getColor(); }
return board.getDest(move) == null || board.getDest(move).getColor() != getColor();
}
@Override @Override
public Object clone() { public Object clone() {
@ -72,14 +70,11 @@ public abstract class Piece implements Cloneable {
return piece; return piece;
} }
public abstract Type getType(); @Override
public String toString() { return getClass().getSimpleName(); }
public Color getColor() { return color; }
@Override @Override
public int hashCode() { public int hashCode() { return Objects.hash(color); }
return Objects.hash(color);
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -90,52 +85,50 @@ public abstract class Piece implements Cloneable {
return color == other.color; 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)); }
/** public static Class<? extends Piece> fromFirstChar(char firstChar) {
* @return The first character of this {@link Type} in algebraic notation and switch (Character.toLowerCase(firstChar)) {
* lower case case 'k':
*/ return King.class;
public char firstChar() { case 'q':
return this == KNIGHT ? 'n' : Character.toLowerCase(this.toString().charAt(0)); return Queen.class;
} case 'r':
return Rook.class;
public static Type fromFirstChar(char firstChar) { case 'n':
switch (Character.toLowerCase(firstChar)) { return Knight.class;
case 'k': case 'b':
return KING; return Bishop.class;
case 'q': case 'p':
return QUEEN; return Pawn.class;
case 'r': default:
return ROOK; return null;
case 'n':
return KNIGHT;
case 'b':
return BISHOP;
case 'p':
return PAWN;
default:
return null;
}
} }
} }
/**
* @return the {@link Color} of this {@link Piece}
*/
public Color getColor() { return color; }
public static enum Color { public static enum Color {
WHITE, BLACK; WHITE, BLACK;
public static Color fromFirstChar(char c) { public static Color fromFirstChar(char c) { return Character.toLowerCase(c) == 'w' ? WHITE : BLACK; }
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() { public Color opposite() { return this == WHITE ? BLACK : WHITE; }
return this == WHITE ? BLACK : WHITE;
}
} }
} }

View File

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

View File

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

View File

@ -5,9 +5,11 @@ import java.awt.event.MouseListener;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import dev.kske.chess.board.Board; import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import dev.kske.chess.board.Move; import dev.kske.chess.board.Move;
import dev.kske.chess.board.Move.Type; import dev.kske.chess.board.Piece;
import dev.kske.chess.board.Piece.Color; import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Position; import dev.kske.chess.board.Position;
import dev.kske.chess.ui.OverlayComponent; import dev.kske.chess.ui.OverlayComponent;
@ -25,7 +27,8 @@ public class NaturalPlayer extends Player implements MouseListener {
private final OverlayComponent overlayComponent; private final OverlayComponent overlayComponent;
private boolean moveRequested; private boolean moveRequested;
private Position pos; private Piece selectedPiece;
private List<Move> possibleMoves;
public NaturalPlayer(Color color, OverlayComponent overlayComponent) { public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
super(color); super(color);
@ -37,43 +40,63 @@ public class NaturalPlayer extends Player implements MouseListener {
} }
@Override @Override
public void requestMove() { public void requestMove() { moveRequested = true; }
moveRequested = true;
}
@Override @Override
public void cancelMove() { public void cancelMove() { moveRequested = false; }
moveRequested = false;
}
@Override @Override
public void disconnect() { public void disconnect() { overlayComponent.removeMouseListener(this); }
overlayComponent.removeMouseListener(this);
}
@Override @Override
public void mousePressed(MouseEvent evt) { public void mousePressed(MouseEvent evt) {
if (!moveRequested) return; if (!moveRequested) return;
if (pos == null) { if (selectedPiece == null) {
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(),
evt.getPoint().y / overlayComponent.getTileSize());
Board board = new Board(this.board); // Get selected Piece
if (board.get(pos) != null && board.get(pos).getColor() == color) { final Position pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
List<Position> positions = board.getMoves(pos) selectedPiece = board.get(pos);
.stream()
.map(move -> move.dest) // Check if a piece was selected
.collect(Collectors.toList()); if (selectedPiece != null) {
overlayComponent.displayDots(positions);
} else pos = null; // Discard selection if the piece has the wrong color
if (selectedPiece.getColor() == color.opposite()) selectedPiece = null;
else {
// Generate all moves possible with the selected piece and display their
// destinations
possibleMoves = selectedPiece.getMoves(pos);
overlayComponent.displayDots(possibleMoves.stream().map(move -> move.getDest()).collect(Collectors.toList()));
}
}
} else { } else {
Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(), Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
evt.getPoint().y / overlayComponent.getTileSize());
// Get all moves leading to the specified destination
List<Move> selectedMoves = possibleMoves.stream().filter(m -> m.getDest().equals(dest)).collect(Collectors.toList());
if (!selectedMoves.isEmpty()) {
Move move;
// Process pawn promotion if necessary
if (selectedMoves.size() > 1) {
// Let the user select a promotion piece
JComboBox<Move> comboBox = new JComboBox<Move>(selectedMoves.toArray(new Move[0]));
JOptionPane.showMessageDialog(overlayComponent, comboBox, "Select a promotion", JOptionPane.QUESTION_MESSAGE);
move = selectedMoves.get(comboBox.getSelectedIndex());
} else move = selectedMoves.get(0);
// Tell the game to execute the move
moveRequested = false;
game.onMove(NaturalPlayer.this, move);
}
// Discard the selection
overlayComponent.clearDots(); overlayComponent.clearDots();
moveRequested = false; selectedPiece = null;
game.onMove(NaturalPlayer.this, new Move(pos, dest, Type.UNKNOWN)); possibleMoves = null;
pos = null;
} }
} }

View File

@ -5,10 +5,16 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import dev.kske.chess.board.Bishop;
import dev.kske.chess.board.Board; 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.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.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> * Project: <strong>Chess</strong><br>
@ -28,35 +34,35 @@ public class MoveProcessor implements Callable<ProcessingResult> {
private Move bestMove; private Move bestMove;
private static final Map<Type, int[][]> positionScores; private static final Map<Class<? extends Piece>, int[][]> positionScores;
static { static {
positionScores = new HashMap<>(); 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[][] { 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[] { -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, -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 } }); 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[][] { 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, 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[] { -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 } }); 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[][] { 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[] { -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 } }); 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[][] { 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, 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[] { -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 } }); 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[][] { 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, 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[] { -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 } }); 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[][] { 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, 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 } }); 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 i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) for (int j = 0; j < 8; j++)
if (board.getBoardArr()[i][j] != null && board.getBoardArr()[i][j].getColor() == color) { if (board.getBoardArr()[i][j] != null && board.getBoardArr()[i][j].getColor() == color) {
switch (board.getBoardArr()[i][j].getType()) { score += board.getBoardArr()[i][j].getValue();
case QUEEN: if (positionScores.containsKey(board.getBoardArr()[i][j].getClass()))
score += 90; score += positionScores.get(board.getBoardArr()[i][j].getClass())[i][color == Color.WHITE ? j : 7 - j];
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];
} }
return score; return score;
} }

View File

@ -37,7 +37,7 @@ public class TextureUtil {
* @return The fitting texture * @return The fitting texture
*/ */
public static Image getPieceTexture(Piece piece) { 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); return scaledTextures.get(key);
} }

View File

@ -48,15 +48,15 @@ public class OverlayComponent extends JComponent {
// Draw an arrow representing the last move and mark its position and // Draw an arrow representing the last move and mark its position and
// destination // destination
if (arrow != null) { if (arrow != null) {
Point pos = new Point(arrow.pos.x * tileSize + tileSize / 2, arrow.pos.y * tileSize + tileSize / 2); Point pos = new Point(arrow.getPos().x * tileSize + tileSize / 2, arrow.getPos().y * tileSize + tileSize / 2);
Point dest = new Point(arrow.dest.x * tileSize + tileSize / 2, arrow.dest.y * tileSize + tileSize / 2); Point dest = new Point(arrow.getDest().x * tileSize + tileSize / 2, arrow.getDest().y * tileSize + tileSize / 2);
Graphics2D g2d = (Graphics2D) g; Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(3)); g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.yellow); g2d.setColor(Color.yellow);
g2d.drawRect(arrow.pos.x * tileSize, arrow.pos.y * tileSize, tileSize, tileSize); g2d.drawRect(arrow.getPos().x * tileSize, arrow.getPos().y * tileSize, tileSize, tileSize);
g2d.drawRect(arrow.dest.x * tileSize, arrow.dest.y * tileSize, tileSize, tileSize); g2d.drawRect(arrow.getDest().x * tileSize, arrow.getDest().y * tileSize, tileSize, tileSize);
Shape arrowShape = createArrowShape(pos, dest); Shape arrowShape = createArrowShape(pos, dest);
g.setColor(new Color(255, 0, 0, 127)); g.setColor(new Color(255, 0, 0, 127));