Added block checking to move validation

+ Move class
+ Utility methods in Board
+ isFreePath method in Piece with implementations in every subclass

- Pawn movement is still not fully implemented, including promotion, en
passant and movement over two tiles
This commit is contained in:
Kai S. K. Engelbart 2019-07-02 13:49:36 +02:00
parent 21737d6845
commit 1f371ad006
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
9 changed files with 194 additions and 55 deletions

View File

@ -25,49 +25,71 @@ public class Board {
} }
public boolean move(int xPos, int yPos, int xDest, int yDest) { public boolean move(int xPos, int yPos, int xDest, int yDest) {
if (boardArr[xPos][yPos] == null || !boardArr[xPos][yPos].isValidMove(xPos, yPos, xDest, yDest)) return false; return move(new Move(xPos, yPos, xDest, yDest));
}
public boolean move(Move move) {
Piece piece = getPos(move);
if (piece == null || !piece.isValidMove(move)) return false;
else { else {
boardArr[xDest][yDest] = boardArr[xPos][yPos]; // Move piece
boardArr[xPos][yPos] = null; setDest(move, getPos(move));
setPos(move, null);
return true; return true;
} }
} }
public Piece getPos(Move move) {
return boardArr[move.xPos][move.yPos];
}
public Piece getDest(Move move) {
return boardArr[move.xDest][move.yDest];
}
public void setPos(Move move, Piece piece) {
boardArr[move.xPos][move.yPos] = piece;
}
public void setDest(Move move, Piece piece) {
boardArr[move.xDest][move.yDest] = piece;
}
/** /**
* Initialized the board array with the default chess pieces and positions. * Initialized the board array with the default chess pieces and positions.
*/ */
private void initializeDefaultPositions() { private void initializeDefaultPositions() {
// Initialize pawns // Initialize pawns
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
boardArr[i][1] = new Pawn(Color.BLACK); boardArr[i][1] = new Pawn(Color.BLACK, this);
boardArr[i][6] = new Pawn(Color.WHITE); boardArr[i][6] = new Pawn(Color.WHITE, this);
} }
// Initialize kings // Initialize kings
boardArr[4][0] = new King(Color.BLACK); boardArr[4][0] = new King(Color.BLACK, this);
boardArr[4][7] = new King(Color.WHITE); boardArr[4][7] = new King(Color.WHITE, this);
// Initialize queens // Initialize queens
boardArr[3][0] = new Queen(Color.BLACK); boardArr[3][0] = new Queen(Color.BLACK, this);
boardArr[3][7] = new Queen(Color.WHITE); boardArr[3][7] = new Queen(Color.WHITE, this);
// Initialize rooks // Initialize rooks
boardArr[0][0] = new Rook(Color.BLACK); boardArr[0][0] = new Rook(Color.BLACK, this);
boardArr[0][7] = new Rook(Color.WHITE); boardArr[0][7] = new Rook(Color.WHITE, this);
boardArr[7][0] = new Rook(Color.BLACK); boardArr[7][0] = new Rook(Color.BLACK, this);
boardArr[7][7] = new Rook(Color.WHITE); boardArr[7][7] = new Rook(Color.WHITE, this);
// Initialize knights // Initialize knights
boardArr[1][0] = new Knight(Color.BLACK); boardArr[1][0] = new Knight(Color.BLACK, this);
boardArr[1][7] = new Knight(Color.WHITE); boardArr[1][7] = new Knight(Color.WHITE, this);
boardArr[6][0] = new Knight(Color.BLACK); boardArr[6][0] = new Knight(Color.BLACK, this);
boardArr[6][7] = new Knight(Color.WHITE); boardArr[6][7] = new Knight(Color.WHITE, this);
// Initialize bishops // Initialize bishops
boardArr[2][0] = new Bishop(Color.BLACK); boardArr[2][0] = new Bishop(Color.BLACK, this);
boardArr[2][7] = new Bishop(Color.WHITE); boardArr[2][7] = new Bishop(Color.WHITE, this);
boardArr[5][0] = new Bishop(Color.BLACK); boardArr[5][0] = new Bishop(Color.BLACK, this);
boardArr[5][7] = new Bishop(Color.WHITE); boardArr[5][7] = new Bishop(Color.WHITE, this);
} }
/** /**

View File

@ -0,0 +1,29 @@
package dev.kske.chess;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>Move.java</strong><br>
* Created: <strong>02.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class Move {
public final int xPos, yPos, xDest, yDest, xDist, yDist, xSign, ySign;
public Move(int xPos, int yPos, int xDest, int yDest) {
this.xPos = xPos;
this.yPos = yPos;
this.xDest = xDest;
this.yDest = yDest;
xDist = Math.abs(xDest - xPos);
yDist = Math.abs(yDest - yPos);
xSign = (int) Math.signum(xDest - xPos);
ySign = (int) Math.signum(yDest - yPos);
}
public boolean isHorizontal() { return yDist == 0; }
public boolean isVertical() { return xDist == 0; }
public boolean isDiagonal() { return xDist == yDist; }
}

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Bishop.java</strong><br> * File: <strong>Bishop.java</strong><br>
@ -8,13 +11,21 @@ package dev.kske.chess.piece;
*/ */
public class Bishop extends Piece { public class Bishop extends Piece {
public Bishop(Color color) { public Bishop(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
return Math.abs(xDest - xPos) == Math.abs(yDest - yPos); return move.isDiagonal() && isFreePath(move);
}
@Override
protected boolean isFreePath(Move move) {
for (int i = move.xPos + move.xSign, j = move.yPos
+ move.ySign; i != move.xDest; i += move.xSign, j += move.ySign)
if (board.getBoardArr()[i][j] != null) return false;
return checkDestination(move);
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>King.java</strong><br> * File: <strong>King.java</strong><br>
@ -8,13 +11,13 @@ package dev.kske.chess.piece;
*/ */
public class King extends Piece { public class King extends Piece {
public King(Color color) { public King(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
return Math.abs(xDest - xPos) <= 1 && Math.abs(yDest - yPos) <= 1; return move.xDist <= 1 && move.yDist <= 1 && isFreePath(move);
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Knight.java</strong><br> * File: <strong>Knight.java</strong><br>
@ -8,15 +11,13 @@ package dev.kske.chess.piece;
*/ */
public class Knight extends Piece { public class Knight extends Piece {
public Knight(Color color) { public Knight(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
int xDist = Math.abs(xDest - xPos); return Math.abs(move.xDist - move.yDist) == 1 && move.xDist != 0 && move.yDist != 0 && isFreePath(move);
int yDist = Math.abs(yDest - yPos);
return Math.abs(xDist - yDist) == 1 && xDist != 0 && yDist != 0;
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Pawn.java</strong><br> * File: <strong>Pawn.java</strong><br>
@ -8,16 +11,31 @@ package dev.kske.chess.piece;
*/ */
public class Pawn extends Piece { public class Pawn extends Piece {
public Pawn(Color color) { public Pawn(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
int direction = color == Color.WHITE ? -1 : 1; // TODO: Positioning, en passant
int xDist = Math.abs(xDest - xPos); if (getColor() == Color.WHITE)
int yDist = (yDest - yPos) * direction; return ((move.xDist == 0 && move.yDist > 0 && move.yDist <= 2) || (move.xDist == 1 && move.yDist == 1))
return (xDist == 0 && yDist > 0 && yDist <= 2) || (xDist == 1 && yDist == 1); && move.ySign == -1 && isFreePath(move);
else return ((move.xDist == 0 && move.yDist > 0 && move.yDist <= 2) || (move.xDist == 1 && move.yDist == 1))
&& move.ySign == 1
&& isFreePath(move);
}
@Override
protected boolean isFreePath(Move move) {
// Two steps forward
if (move.yDist == 2)
return board.getBoardArr()[move.xPos][move.yDest - move.ySign] == null && checkDestination(move);
// One step forward
else if (move.xDist == 0) return board.getDest(move) == null;
// Capture move
else return board.getDest(move) != null && board.getDest(move).getColor() != getColor();
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Piece.java</strong><br> * File: <strong>Piece.java</strong><br>
@ -9,12 +12,30 @@ package dev.kske.chess.piece;
public abstract class Piece { public abstract class Piece {
protected Color color; protected Color color;
protected Board board;
public Piece(Color color) { public Piece(Color color, Board board) {
this.color = color; this.color = color;
this.board = board;
} }
public abstract boolean isValidMove(int xPos, int yPos, int xDest, int yDest); public abstract boolean isValidMove(Move move);
protected boolean isFreePath(Move move) {
// Only check destination by default
return checkDestination(move);
}
/**
* Checks if the destination of a move is empty or a piece from the opposing
* team
*
* @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();
}
public abstract Type getType(); public abstract Type getType();

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Queen.java</strong><br> * File: <strong>Queen.java</strong><br>
@ -8,13 +11,29 @@ package dev.kske.chess.piece;
*/ */
public class Queen extends Piece { public class Queen extends Piece {
public Queen(Color color) { public Queen(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
return (xPos == xDest || yPos == yDest) || (Math.abs(xDest - xPos) == Math.abs(yDest - yPos)); return ((move.isHorizontal() || move.isVertical()) || move.isDiagonal()) && isFreePath(move);
}
@Override
protected boolean isFreePath(Move move) {
if (move.isHorizontal()) {
for (int i = move.xPos + move.xSign; i != move.xDest; i += move.xSign)
if (board.getBoardArr()[i][move.yPos] != null) return false;
} else if (move.isVertical()) {
for (int i = move.yPos + move.ySign; i != move.yDest; i += move.ySign)
if (board.getBoardArr()[move.xPos][i] != null) return false;
} else {
for (int i = move.xPos + move.xSign, j = move.yPos
+ move.ySign; i != move.xDest; i += move.xSign, j += move.ySign)
if (board.getBoardArr()[i][j] != null) return false;
}
return checkDestination(move);
} }
@Override @Override

View File

@ -1,5 +1,8 @@
package dev.kske.chess.piece; package dev.kske.chess.piece;
import dev.kske.chess.Board;
import dev.kske.chess.Move;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
* File: <strong>Rook.java</strong><br> * File: <strong>Rook.java</strong><br>
@ -8,13 +11,25 @@ package dev.kske.chess.piece;
*/ */
public class Rook extends Piece { public class Rook extends Piece {
public Rook(Color color) { public Rook(Color color, Board board) {
super(color); super(color, board);
} }
@Override @Override
public boolean isValidMove(int xPos, int yPos, int xDest, int yDest) { public boolean isValidMove(Move move) {
return xPos == xDest || yPos == yDest; return (move.isHorizontal() || move.isVertical()) && isFreePath(move);
}
@Override
protected boolean isFreePath(Move move) {
if (move.isHorizontal()) {
for (int i = move.xPos + move.xSign; i != move.xDest; i += move.xSign)
if (board.getBoardArr()[i][move.yPos] != null) return false;
} else {
for (int i = move.yPos + move.ySign; i != move.yDest; i += move.ySign)
if (board.getBoardArr()[move.xPos][i] != null) return false;
}
return checkDestination(move);
} }
@Override @Override