2019-07-01 19:08:37 +02:00
|
|
|
package dev.kske.chess;
|
|
|
|
|
2019-07-03 11:05:20 +02:00
|
|
|
import java.util.ArrayList;
|
2019-07-02 20:07:47 +02:00
|
|
|
import java.util.HashMap;
|
2019-07-03 11:05:20 +02:00
|
|
|
import java.util.List;
|
2019-07-02 20:07:47 +02:00
|
|
|
import java.util.Map;
|
|
|
|
|
2019-07-03 11:05:20 +02:00
|
|
|
import dev.kske.chess.event.GameEvent;
|
|
|
|
import dev.kske.chess.event.GameEvent.GameEventType;
|
|
|
|
import dev.kske.chess.event.GameEventListener;
|
2019-07-01 19:50:42 +02:00
|
|
|
import dev.kske.chess.piece.Bishop;
|
|
|
|
import dev.kske.chess.piece.King;
|
|
|
|
import dev.kske.chess.piece.Knight;
|
|
|
|
import dev.kske.chess.piece.Pawn;
|
|
|
|
import dev.kske.chess.piece.Piece;
|
|
|
|
import dev.kske.chess.piece.Piece.Color;
|
2019-07-02 20:07:47 +02:00
|
|
|
import dev.kske.chess.piece.Piece.Type;
|
2019-07-01 19:50:42 +02:00
|
|
|
import dev.kske.chess.piece.Queen;
|
|
|
|
import dev.kske.chess.piece.Rook;
|
2019-07-01 19:37:15 +02:00
|
|
|
|
2019-07-01 19:08:37 +02:00
|
|
|
/**
|
|
|
|
* Project: <strong>Chess</strong><br>
|
|
|
|
* File: <strong>Board.java</strong><br>
|
|
|
|
* Created: <strong>01.07.2019</strong><br>
|
|
|
|
* Author: <strong>Kai S. K. Engelbart</strong>
|
|
|
|
*/
|
|
|
|
public class Board {
|
|
|
|
|
2019-07-02 20:07:47 +02:00
|
|
|
private Piece[][] boardArr;
|
|
|
|
private Map<Color, Position> kingPos;
|
2019-07-01 19:08:37 +02:00
|
|
|
|
2019-07-03 11:05:20 +02:00
|
|
|
private List<GameEventListener> gameEventListeners;
|
|
|
|
|
2019-07-01 19:08:37 +02:00
|
|
|
public Board() {
|
2019-07-05 14:14:48 +02:00
|
|
|
boardArr = new Piece[8][8];
|
|
|
|
kingPos = new HashMap<>();
|
2019-07-03 11:05:20 +02:00
|
|
|
gameEventListeners = new ArrayList<>();
|
2019-07-01 19:08:37 +02:00
|
|
|
initializeDefaultPositions();
|
|
|
|
}
|
|
|
|
|
2019-07-05 14:14:48 +02:00
|
|
|
/**
|
|
|
|
* Moves a piece across the board if the move is legal.
|
|
|
|
*
|
|
|
|
* @param move The move to execute
|
|
|
|
* @return {@code true}, if the attempted move was legal and thus executed
|
|
|
|
*/
|
|
|
|
public boolean attemptMove(Move move) {
|
2019-07-02 13:49:36 +02:00
|
|
|
Piece piece = getPos(move);
|
|
|
|
if (piece == null || !piece.isValidMove(move)) return false;
|
2019-07-01 21:46:30 +02:00
|
|
|
else {
|
2019-07-05 14:14:48 +02:00
|
|
|
/*
|
|
|
|
* Move piece
|
|
|
|
* Save destination piece for possible canceling of the move
|
|
|
|
*/
|
|
|
|
Piece capturePiece = move(move);
|
2019-07-02 20:40:28 +02:00
|
|
|
|
2019-07-02 20:07:47 +02:00
|
|
|
// Revert move if it caused a check for its team
|
|
|
|
if (checkCheck(piece.getColor())) {
|
2019-07-02 20:40:28 +02:00
|
|
|
revert(move, capturePiece);
|
2019-07-02 20:07:47 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-07-03 11:05:20 +02:00
|
|
|
|
|
|
|
// TODO: detecting checkmate
|
|
|
|
// Check for check on the opposite team
|
|
|
|
Color oppositeColor = piece.getColor() == Color.WHITE ? Color.BLACK : Color.WHITE;
|
2019-07-05 14:14:48 +02:00
|
|
|
if (checkCheck(oppositeColor)) notifyListeners(new GameEvent(this, GameEventType.CHECK, oppositeColor));
|
2019-07-03 11:05:20 +02:00
|
|
|
|
2019-07-01 21:46:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 14:14:48 +02:00
|
|
|
/**
|
|
|
|
* Moves a piece across the board without checking if the move is legal.
|
|
|
|
*
|
|
|
|
* @param move The move to execute
|
|
|
|
* @return The captures piece, or null if the move's destination was empty
|
|
|
|
*/
|
|
|
|
public Piece move(Move move) {
|
|
|
|
Piece piece = getPos(move);
|
|
|
|
Piece capturePiece = getDest(move);
|
|
|
|
setDest(move, piece);
|
|
|
|
setPos(move, null);
|
|
|
|
|
|
|
|
// Update the king's position if the moved piece is the king
|
|
|
|
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest);
|
|
|
|
|
|
|
|
return capturePiece;
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:40:28 +02:00
|
|
|
/**
|
|
|
|
* Reverts a move.
|
|
|
|
*
|
|
|
|
* @param move The move to revert
|
|
|
|
* @param capturedPiece The piece that has been captured when the move has been
|
|
|
|
* applied
|
|
|
|
*/
|
|
|
|
public void revert(Move move, Piece capturedPiece) {
|
|
|
|
setPos(move, getDest(move));
|
|
|
|
setDest(move, 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.pos);
|
|
|
|
}
|
|
|
|
|
2019-07-05 14:14:48 +02:00
|
|
|
/**
|
|
|
|
* Generated every legal move for one color
|
|
|
|
*
|
|
|
|
* @param color The color to generate the moves for
|
|
|
|
* @return A list of all legal moves
|
|
|
|
*/
|
|
|
|
public List<Move> getMoves(Color color) {
|
|
|
|
List<Move> moves = new ArrayList<>();
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
for (int j = 0; j < 8; j++)
|
|
|
|
if (boardArr[i][j] != null && boardArr[i][j].getColor() == color)
|
|
|
|
moves.addAll(boardArr[i][j].getMoves(new Position(i, j)));
|
|
|
|
return moves;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Move> getMoves(Position pos) {
|
|
|
|
return get(pos).getMoves(pos);
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:07:47 +02:00
|
|
|
public boolean checkCheck(Color color) {
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
for (int j = 0; j < 8; j++)
|
|
|
|
if (boardArr[i][j] != null && boardArr[i][j].getColor() != color
|
|
|
|
&& boardArr[i][j].isValidMove(new Move(new Position(i, j), kingPos.get(color))))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-07-03 11:05:20 +02:00
|
|
|
public void registerGameEventListener(GameEventListener listener) {
|
|
|
|
gameEventListeners.add(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void notifyListeners(GameEvent evt) {
|
|
|
|
gameEventListeners.forEach(listener -> listener.onGameEvent(evt));
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:07:47 +02:00
|
|
|
public Piece get(Position pos) {
|
|
|
|
return boardArr[pos.x][pos.y];
|
|
|
|
}
|
|
|
|
|
|
|
|
public void set(Position pos, Piece piece) {
|
|
|
|
boardArr[pos.x][pos.y] = piece;
|
|
|
|
}
|
|
|
|
|
2019-07-02 13:49:36 +02:00
|
|
|
public Piece getPos(Move move) {
|
2019-07-02 20:07:47 +02:00
|
|
|
return get(move.pos);
|
2019-07-02 13:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public Piece getDest(Move move) {
|
2019-07-02 20:07:47 +02:00
|
|
|
return get(move.dest);
|
2019-07-02 13:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setPos(Move move, Piece piece) {
|
2019-07-02 20:07:47 +02:00
|
|
|
set(move.pos, piece);
|
2019-07-02 13:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setDest(Move move, Piece piece) {
|
2019-07-02 20:07:47 +02:00
|
|
|
set(move.dest, piece);
|
2019-07-02 13:49:36 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 19:50:42 +02:00
|
|
|
/**
|
|
|
|
* Initialized the board array with the default chess pieces and positions.
|
|
|
|
*/
|
2019-07-03 11:05:20 +02:00
|
|
|
public void initializeDefaultPositions() {
|
2019-07-01 19:37:15 +02:00
|
|
|
// Initialize pawns
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[i][1] = new Pawn(Color.BLACK, this);
|
|
|
|
boardArr[i][6] = new Pawn(Color.WHITE, this);
|
2019-07-01 19:37:15 +02:00
|
|
|
}
|
2019-07-01 19:50:42 +02:00
|
|
|
|
|
|
|
// Initialize kings
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[4][0] = new King(Color.BLACK, this);
|
|
|
|
boardArr[4][7] = new King(Color.WHITE, this);
|
2019-07-01 19:50:42 +02:00
|
|
|
|
2019-07-02 20:07:47 +02:00
|
|
|
// Initialize king position objects
|
|
|
|
kingPos.put(Color.BLACK, new Position(4, 0));
|
|
|
|
kingPos.put(Color.WHITE, new Position(4, 7));
|
|
|
|
|
2019-07-01 19:50:42 +02:00
|
|
|
// Initialize queens
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[3][0] = new Queen(Color.BLACK, this);
|
|
|
|
boardArr[3][7] = new Queen(Color.WHITE, this);
|
2019-07-01 19:50:42 +02:00
|
|
|
|
|
|
|
// Initialize rooks
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[0][0] = new Rook(Color.BLACK, this);
|
|
|
|
boardArr[0][7] = new Rook(Color.WHITE, this);
|
|
|
|
boardArr[7][0] = new Rook(Color.BLACK, this);
|
|
|
|
boardArr[7][7] = new Rook(Color.WHITE, this);
|
2019-07-01 19:50:42 +02:00
|
|
|
|
|
|
|
// Initialize knights
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[1][0] = new Knight(Color.BLACK, this);
|
|
|
|
boardArr[1][7] = new Knight(Color.WHITE, this);
|
|
|
|
boardArr[6][0] = new Knight(Color.BLACK, this);
|
|
|
|
boardArr[6][7] = new Knight(Color.WHITE, this);
|
2019-07-01 19:50:42 +02:00
|
|
|
|
|
|
|
// Initialize bishops
|
2019-07-02 13:49:36 +02:00
|
|
|
boardArr[2][0] = new Bishop(Color.BLACK, this);
|
|
|
|
boardArr[2][7] = new Bishop(Color.WHITE, this);
|
|
|
|
boardArr[5][0] = new Bishop(Color.BLACK, this);
|
|
|
|
boardArr[5][7] = new Bishop(Color.WHITE, this);
|
2019-07-03 11:05:20 +02:00
|
|
|
|
|
|
|
// Clear all other tiles
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
for (int j = 2; j < 6; j++)
|
|
|
|
boardArr[i][j] = null;
|
2019-07-01 19:08:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-07-01 21:46:30 +02:00
|
|
|
* @return The board array
|
2019-07-01 19:08:37 +02:00
|
|
|
*/
|
|
|
|
public Piece[][] getBoardArr() { return boardArr; }
|
|
|
|
}
|