package eu.semberal.migmang.logic;
import eu.semberal.migmang.enums.GameColor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Contains static methods for move validation
* @author lukas.sembera
*/
public class Referee {
/**
* Checks if the move is valid having the specified board. Doesn't check captured indexes!
*/
public static boolean isValidMove(Board board, Move move, boolean isWhiteOnMove) {
if (move.isIncorrectMove() ||
!isSquareOnBoard(move.getFrom()) ||
!isSquareOnBoard(move.getTo()) ||
isWhiteOnMove && move.getColor() != GameColor.White ||
!isWhiteOnMove && move.getColor() != GameColor.Black) {
return false;
}
for (Move t : Referee.getAvailableMoves(board, move.getFrom())) {
if (move.getTo() == t.getTo()) {
return true;
}
}
return false;
}
/**
* Checks if the game is over
* @return GameColor if some player won or null if the game has not ended yet
*/
public static GameColor isGameEnded(Board board) {
if (board.getPiecesCount(GameColor.White) == 0) {
return GameColor.Black;
}
if (board.getPiecesCount(GameColor.Black) == 0) {
return GameColor.White;
}
return null;
}
/**
* Calculates all possible moves for a specific color
*/
public static Move[] getAllAvailableMovesForColor(Board board, GameColor color) {
List<Move> temp = new ArrayList<Move>();
for (int i = 0; i < 81; i++) {
if (board.getSquare(i) != color) {
continue;
}
temp.addAll(Arrays.asList(getAvailableMoves(board, i)));
}
return temp.toArray(new Move[temp.size()]);
}
/**
* Returns all moves without jumping over possibility
*/
private static Move[] getAvailableMovesWithoutJumpingOver(Board board, int position) {
List<Move> temp = new ArrayList<Move>();
int i = position + 9;
if (areNeighbours(i, position, 1) && isSquareOnBoard(i) && board.getSquare(i) == null) {
temp.add(new Move(position, i, board.getSquare(position)));
}
i = position - 9;
if (areNeighbours(i, position, 1) && isSquareOnBoard(i) && board.getSquare(i) == null) {
temp.add(new Move(position, i, board.getSquare(position)));
}
i = position + 1;
if (areNeighbours(i, position, 1) && isSquareOnBoard(i) && board.getSquare(i) == null) {
temp.add(new Move(position, i, board.getSquare(position)));
}
i = position - 1;
if (areNeighbours(i, position, 1) && isSquareOnBoard(i) && board.getSquare(i) == null) {
temp.add(new Move(position, i, board.getSquare(position)));
}
return temp.toArray(new Move[temp.size()]);
}
/**
* Returns all moves where the piece from current position can move (including jumping over)
*/
public static Move[] getAvailableMoves(Board board, int position) {
List<Move> tempList = new ArrayList<Move>();
tempList.addAll(Arrays.asList(getAvailableMovesWithoutJumpingOver(board, position)));
/* In a user have only one peice left, jumping over is allowed */
if (board.getPiecesCount(board.getSquare(position)) == 1) {
int i = position + 18;
if (areNeighbours(i, position, 2) && isSquareOnBoard(i) && board.getSquare(i) == null &&
board.getSquare(position + 9) ==
(board.getSquare(position) == GameColor.White ? GameColor.Black : GameColor.White)) {
tempList.add(new Move(position, i, board.getSquare(position)));
}
i = position - 18;
if (areNeighbours(i, position, 2) && isSquareOnBoard(i) && board.getSquare(i) == null &&
board.getSquare(position - 9) ==
(board.getSquare(position) == GameColor.White ? GameColor.Black : GameColor.White)) {
tempList.add(new Move(position, i, board.getSquare(position)));
}
i = position + 2;
if (areNeighbours(i, position, 2) && isSquareOnBoard(i) && board.getSquare(i) == null &&
board.getSquare(position + 1) ==
(board.getSquare(position) == GameColor.White ? GameColor.Black : GameColor.White)) {
tempList.add(new Move(position, i, board.getSquare(position)));
}
i = position - 2;
if (areNeighbours(i, position, 2) && isSquareOnBoard(i) && board.getSquare(i) == null &&
board.getSquare(position - 1) ==
(board.getSquare(position) == GameColor.White ? GameColor.Black : GameColor.White)) {
tempList.add(new Move(position, i, board.getSquare(position)));
}
}
return tempList.toArray(new Move[tempList.size()]);
}
/**
* Whether two squares are neighbors on the board.
* @param m First square
* @param n Second square
* @param distance Distance of the squares. If 1, it means they have to be direct neighbours, it 2, there can be one square in the middle, etc.
*/
private static boolean areNeighbours(int m, int n, int distance) {
if ((m % 9 == n % 9 || m / 9 == n / 9) && (Math.abs(m - n) == distance || Math.abs(m - n) == 9*distance)) {
return true;
}
return false;
}
private static boolean isSquareOnBoard(int i) {
return (i >= 0 && i <= 80);
}
/**
* Adds capturing information to a move
*/
public static void addCaptureInformationToMove(Board board, Move move) {
GameColor color = move.getColor();
GameColor colorForCaptures = (color == GameColor.White ? GameColor.Black : GameColor.White);
Board s = new Board(board).addMoveWithoutCaptures(move);
if (move.getTo() == move.getFrom() + 2) { //if distance is 2, jump over occured and is necessary to delete piece in the middle
move.addCapturedPieceIndex(move.getFrom() + 1);
} else if (move.getTo() == move.getFrom() - 2) {
move.addCapturedPieceIndex(move.getFrom() - 1);
} else if (move.getTo() == move.getFrom() + 18) {
move.addCapturedPieceIndex(move.getFrom() + 9);
} else if (move.getTo() == move.getFrom() - 18) {
move.addCapturedPieceIndex(move.getFrom() - 9);
}
for (int i = 0; i < 81; i++) {
if (s.getSquare(i) == colorForCaptures &&
Referee.getAvailableMovesWithoutJumpingOver(s, i).length == 0 &&
Referee.areNeighbours(move.getTo(), i, 1)) {
move.addCapturedPieceIndex(i);
}
}
}
}