package rules;
import game.Move;
import components.Field;
import components.Figure;
import util.*;
/**
* Klasse zur überprüfung der Regeln.
* @author Florian Hallensleben
*
*/
public class Rules {
private boolean whiteRightRookMoved = false;
private boolean whiteLeftRookMoved = false;
private boolean blackRightRookMoved = false;
private boolean blackLeftRookMoved = false;
private boolean blackKingMoved = false;
private boolean whiteKingMoved = false;
private byte currentX;
private byte currentY;
private byte x;
private byte y;
/**
* Diese Methode überprüft, ob ein Schachzug gültig ist oder nicht.
* @param currentField Das aktuelle Spielfeld.
* @param move Der Schachzug, der überprüft werden soll.
* @return True: Gültiger Schachzug
* False: Ungültiger Schachzug
*/
public boolean checkMove(Field currentField, Move move)
{
/**
* Hilfsvariablen
*/
boolean legalMove;
// false zurückgeben, wenn Start- oder Zielfeld nicht existiert
if(!Field.isValidFieldnumber(move.getFieldFrom())
|| !Field.isValidFieldnumber(move.getFieldTo())){
return false;
}
// false zurückgeben, wenn zu schlagende Figur eine eigene Figur ist oder dort keine steht
if(move.isCaptured()){
if(!currentField.isFigureOnField(move.getFieldTo())){
return false;
}
// false zurückgeben, wenn eine Figur geschlagen werden würde
}
else{
if(currentField.isFigureOnField(move.getFieldTo())){
return false;
}
}
// false zurückgeben, wenn zu bewegende Figur nicht existiert oder nicht die eigene Figur ist
if(!currentField.isFigureOnField(move.getFieldFrom())){
return false;
}
/**
* Positionen speichern
*/
currentX = Field.getXPositionFromFieldnumber(move.getFieldFrom());
currentY = Field.getYPositionFromFieldnumber(move.getFieldFrom());
x = Field.getXPositionFromFieldnumber(move.getFieldTo());
y = Field.getYPositionFromFieldnumber(move.getFieldTo());
switch(currentField.getFigureAt(move.getFieldFrom()).getFigureType() ) {
case ChessfigureConstants.PAWN:
legalMove = checkPawnMove(currentField, move);
break;
case ChessfigureConstants.ROOK:
legalMove = checkRookMove(currentField, move);
break;
case ChessfigureConstants.KNIGHT:
legalMove = checkKnightMove(currentField, move);
break;
case ChessfigureConstants.BISHOP:
legalMove = checkBishopMove(currentField, move);
break;
case ChessfigureConstants.QUEEN:
legalMove = checkQueenMove(currentField, move);
break;
case ChessfigureConstants.KING:
legalMove = checkKingMove(currentField, move);
if(legalMove){
if(currentField.getFigureAt(move.getFieldFrom()).getColor() == ChessfigureConstants.WHITE){
whiteKingMoved = true;
if(currentY == y && currentX - x == 2){
whiteLeftRookMoved = true;
}
else if(currentY == y && currentX - x == - 2){
whiteRightRookMoved = true;
}
}
else if(currentField.getFigureAt(move.getFieldFrom()).getColor() == ChessfigureConstants.BLACK){
blackKingMoved = true;
if(currentY == y && currentX - x == 2){
blackLeftRookMoved = true;
}
else if(currentY == y && currentX - x == - 2){
blackRightRookMoved = true;
}
}
}
return legalMove;
default:
legalMove = false;
break;
}
if(legalMove){
return !isCheck(currentField, move, false,
currentField.getKingPosition(currentField.getFigureAt(move.getFieldFrom()).getColor()));
}
else{
return false;
}
}
/**
* überprüft, ob ein Bauernzug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: Bauer darf dem Move-Objekt entsprechend bewegt werden
* False: Irgendwas stimmt hier nicht!
*/
private boolean checkPawnMove(Field currentField, Move move)
{
int i;
if(currentField.getFigureAt(move.getFieldFrom()).getColor() == ChessfigureConstants.BLACK){
i = 1;
}
else if(currentField.getFigureAt(move.getFieldFrom()).getColor()== ChessfigureConstants.WHITE){
i = -1;
}
else{
return false;
}
// Bauer schlügt nicht
if(currentX == x
&& !move.isCaptured()
&& !currentField.isFigureOnField(move.getFieldTo())){
// Bauer ein Feld vor
if(currentY - y == i){
return true;
}
//Bauer zwei Felder vor (vom Startfeld), auf dem Feld dazwischen steht keine Figur
else if(currentY - y == 2*i
&& currentY == 4.5 + 2.5*i
&& !currentField.isFigureOnField(Field.getFieldNumber(currentX, currentY - i))){
return true;
}
}
// Bauer schlügt
else if(Math.abs(currentX - x) == 1
&& move.isCaptured()
&& currentField.isFigureOnField(move.getFieldTo())
&& currentY - y == i){
return true;
}
return false;
}
/**
* überprüft, ob ein Turmzug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: Turm darf dem Move-Objekt entsprechend bewegt werden
* False: Irgendwas stimmt hier nicht!
*/
private boolean checkRookMove(Field currentField, Move move)
{
//Turm bewegt sich in y-Richtung
if(currentX == x
&& currentY != y){
if(currentY - 1 > y){
//überprüfung, dass keine Figur zwischen Start- und Zielfeld steht
for(int i = 1; currentY - i > y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX, currentY - i))){
return false;
}
}
}
else if(currentY + 1 < y){
//überprüfung, dass keine Figur zwischen Start- und Zielfeld steht
for(int i = 1; currentY + i < y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX, currentY + i))){
return false;
}
}
}
return true;
}
//Turm bewegt sich in x-Richtung
else if(currentY == y
&& currentX != x){
if(currentX - 1 > x){
//überprüfung, dass keine Figur zwischen Start- und Zielfeld steht
for(int i = 1; currentX - i > x; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX - i, currentY))){
return false;
}
}
}
else if(currentX + 1 < x){
//überprüfung, dass keine Figur zwischen Start- und Zielfeld steht
for(int i = 1; currentX + i < x; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX + i, currentY))){
return false;
}
}
}
//bewegt sich ein Turm, darf er nicht mehr Teil der Rochade sein
//da Damenbewegung auch über diese Methode überprüft wird, darf die Dame hier nicht "reinpfuschen" :)
if(/*move.getFigure().getFigureType()*/ currentField.getFigureAt(move.getFieldFrom()).getFigureType() != ChessfigureConstants.QUEEN){
if(/*move.getFigure().getColor()*/ currentField.getFigureAt(move.getFieldFrom()).getColor() == ChessfigureConstants.BLACK){
if(move.getFieldFrom() == 57){
this.blackLeftRookMoved = true;
}
else if(move.getFieldFrom() == 64){
this.blackRightRookMoved = true;
}
}
else if(/*move.getFigure().getColor()*/ currentField.getFigureAt(move.getFieldFrom()).getColor() == ChessfigureConstants.WHITE){
if(move.getFieldFrom() == 1){
this.whiteLeftRookMoved = true;
}
else if(move.getFieldFrom() == 8){
this.whiteRightRookMoved = true;
}
}
}
//Keine Figur im Weg oder Turm hat sich nur ein Feld weit bewegt
return true;
}
return false;
}
/**
* überprüft, ob ein Springerzug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: Springer darf dem Move-Objekt entsprechend bewegt werden
False: Irgendwas stimmt hier nicht!
*/
private boolean checkKnightMove(Field currentField, Move move)
{
if((Math.abs(currentX - x) == 1
&& Math.abs(currentY - y) == 2)
|| (Math.abs(currentX - x) == 2
&& Math.abs(currentY - y) == 1)){
return true;
}
return false;
}
/**
* überprüft, ob ein Lüufernzug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: Lüufer darf dem Move-Objekt entsprechend bewegt werden
* False: Irgendwas stimmt hier nicht!
*/
private boolean checkBishopMove(Field currentField, Move move)
{
int xDif = currentX - x;
int yDif = currentY - y;
//Lüufer bewegt sich schräg
if(Math.abs(xDif) == Math.abs(yDif)
&& xDif != 0){
//nach unten
if(xDif > 1){
//links
if(yDif > 1){
for(int i = 1; currentY - i > y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX - i, currentY - i))){
return false;
}
}
}
//rechts
else if (yDif < 1){
for(int i = 1; currentY + i < y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX - i, currentY + i))){
return false;
}
}
}
}
//nach oben
else if(xDif < 1){
//links
if(yDif > 1){
for(int i = 1; currentY - i > y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX + i, currentY - i))){
return false;
}
}
}
//rechts
else if (yDif < 1){
for(int i = 1; currentY + i < y; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(currentX + i, currentY + i))){
return false;
}
}
}
}
//keine Figur im Weg oder Lüufer hat sich nur ein Feld bewegt
return true;
}
return false;
}
/**
* überprüft, ob ein Damenzug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: Dame darf dem Move-Objekt entsprechend bewegt werden
* False: Irgendwas stimmt hier nicht!
*/
private boolean checkQueenMove(Field currentField, Move move)
{
return (checkRookMove(currentField, move)||(checkBishopMove(currentField, move)));
}
/**
* überprüft, ob ein Königszug gültig ist.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @return True: König darf dem Move-Objekt entsprechend bewegt werden
False: Irgendwas stimmt hier nicht!
*/
private boolean checkKingMove(Field currentField, Move move)
{
if(currentX == x
&& Math.abs(currentY - y) == 1){
}
else if(currentX == x + 1
&& Math.abs(currentY - y) <= 1){
}
else if(currentX == x - 1
&& Math.abs(currentY - y) <= 1){
}
//Rochade
else if(currentY == y && Math.abs(currentX - x) == 2){
//sind die Felder zwischen Turm und König frei
if(currentX > x && currentField.getFigureAt(Field.getFieldNumber(1, currentY)).getFigureType() == ChessfigureConstants.ROOK){
for(int i = currentX - 1; i > 1; i--){
if(currentField.isFigureOnField(Field.getFieldNumber(i, y))){
return false;
}
}
}
else if(currentX < x && currentField.getFigureAt(Field.getFieldNumber(8, currentY)).getFigureType() == ChessfigureConstants.ROOK){
for(int i = currentX + 1; i < 8; i++){
if(currentField.isFigureOnField(Field.getFieldNumber(i, y))){
return false;
}
}
//Falls kein Turm zur Rochade vorhanden ist
}
else{
return false;
}
return !isCheck(currentField, move, true, move.getFieldTo());
}else{
return false;
}
return !isCheck(currentField, move, false, move.getFieldTo());
}
/**
* Stellt das Ausgangschachfeld wieder her.
* @param currentField aktuelles wiederherzustellendes Spielfeld
* @param move Spielzug, der zu diesem Feld geführt hat
* @param castling true, falls der Zug eine Rochade war, false sonst
* @param capturedFigure Figur, die geschlagen wurde; falls keine Figur geschlagen wurde null
*/
private void retractChanges(Field currentField, Move move, boolean castling, Figure capturedFigure){
currentField.moveFigure(move.getFieldTo(), move.getFieldFrom());
if(move.isCaptured()){
currentField.putFigureAt(move.getFieldTo(), capturedFigure);
}
//Falls Rochade, Turm zurücksetzen
if(castling){
if(currentX > x){
currentField.moveFigure(Field.getFieldNumber(4, y), Field.getFieldNumber(1, y));
}
else if(currentX < x){
currentField.moveFigure(Field.getFieldNumber(6, y), Field.getFieldNumber(8, y));
}
}
}
/**
* überprüft, ob sich der König im Schach befindet.
* @param currentField aktuelles Spielfeld
* @param move auszuführender Schachzug
* @param castling soll eine Rochade überprüft werden?
* @return False: der eigene König steht nicht im Schach
True: Der eigene König ist durch den Zug geführdet.
*/
private boolean isCheck(Field currentField, Move move, boolean castling, int position)
{
//Zwischenspeichern der Figur, die geschlagen wird, um sie später wieder auf das Spielfeld zu stellen
Figure capturedF = null;
if(move.isCaptured()){
capturedF = currentField.getFigureAt(move.getFieldTo());
currentField.removeFigureAt(move.getFieldTo());
}
//Figur versetzen
currentField.moveFigure(move.getFieldFrom(), move.getFieldTo());
//wenn der König versetzt wird, muss natürlich die Königsposition verändert werden, aber nicht bei der Rochade
if(currentField.getFigureAt(move.getFieldTo()).getFigureType() == ChessfigureConstants.KING && !castling){
position = move.getFieldTo();
}
//Turm bei Rochade versetzen
if(castling){
if(currentX > x){
currentField.moveFigure(Field.getFieldNumber(1, y), Field.getFieldNumber(4, y));
}
else if(currentX < x){
currentField.moveFigure(Field.getFieldNumber(8, y), Field.getFieldNumber(6, y));
}
}
byte colour = currentField.getFigureAt(move.getFieldTo()).getColor();
Figure fig;
byte figType;
byte xAxis = Field.getXPositionFromFieldnumber(position);
byte yAxis = Field.getYPositionFromFieldnumber(position);
//x-Achse prüfen
//Bewegung nach rechts
//ein Feld neben dem König anfangen, solange das Feld in der gleichen Zeile ist
for(int i = position + 1; (i - 1)/8 == (position - 1)/8; i++){
fig = currentField.getFigureAt(i);
if(fig == null){
continue;
}
if((fig.getColor() == colour && i != move.getFieldTo()) || i == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.ROOK
|| (figType == ChessfigureConstants.KING && position + 1 == i)
|| figType == ChessfigureConstants.QUEEN)){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//Bewegung nach links
for(int i = position - 1; (i - 1)/8 == (position - 1)/8; i--){
fig = currentField.getFigureAt(i);
if(fig == null){
continue;
}
if((fig.getColor() == colour && i != move.getFieldTo()) || i == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.ROOK
|| (figType == ChessfigureConstants.KING
&& position - 1 == i)
|| figType == ChessfigureConstants.QUEEN)){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//y-Achse prüfen
//nach oben
for(int i = position + 8; i > 0 && i <= 64; i += 8){
fig = currentField.getFigureAt(i);
if(fig == null){
continue;
}
if((fig.getColor() == colour && i != move.getFieldTo()) || i == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.ROOK
|| (figType == ChessfigureConstants.KING
&& position + 8 == i)
|| figType == ChessfigureConstants.QUEEN)){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//nach unten
for(int i = position - 8; i > 0 && i <= 64; i -= 8){
fig = currentField.getFigureAt(i);
if(fig == null){
continue;
}
if((fig.getColor() == colour && i != move.getFieldTo()) || i == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.ROOK
|| (figType == ChessfigureConstants.KING
&& position - 8 == i)
|| figType == ChessfigureConstants.QUEEN)){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//schräg prüfen
//nach rechts oben
int fieldNo;
for(int i = 1; xAxis + i < 9 && yAxis < 9; i++){
fieldNo = Field.getFieldNumber(xAxis + i, yAxis + i);
fig = currentField.getFigureAt(fieldNo);
if(fig == null){
continue;
}
if((fig.getColor() == colour && fieldNo != move.getFieldTo())
|| fieldNo == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.BISHOP
|| figType == ChessfigureConstants.QUEEN
|| (figType == ChessfigureConstants.KING && i == 1)
|| (figType == ChessfigureConstants.PAWN && i == 1
&& fig.getColor() == ChessfigureConstants.BLACK))){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//nach rechts unten
for(int i = 1; xAxis + i < 9 && yAxis - i > 0; i++){
fieldNo = Field.getFieldNumber(xAxis + i, yAxis - i);
fig = currentField.getFigureAt(fieldNo);
if(fig == null){
continue;
}
if((fig.getColor() == colour && fieldNo != move.getFieldTo()) || fieldNo == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.BISHOP
|| figType == ChessfigureConstants.QUEEN
|| (figType == ChessfigureConstants.KING && i == 1)
|| (figType == ChessfigureConstants.PAWN && i == 1
&& fig.getColor() == ChessfigureConstants.WHITE))){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//nach links oben
for(int i = 1; xAxis - i > 0 && yAxis + i < 9; i++){
fieldNo = Field.getFieldNumber(xAxis - i, yAxis + i);
fig = currentField.getFigureAt(fieldNo);
if(fig == null){
continue;
}
if((fig.getColor() == colour && fieldNo != move.getFieldTo()) || fieldNo == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.BISHOP
|| figType == ChessfigureConstants.QUEEN
|| (figType == ChessfigureConstants.KING && i == 1)
|| (figType == ChessfigureConstants.PAWN && i == 1
&& fig.getColor() == ChessfigureConstants.BLACK))){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//nach links unten (eigentlich links oben?!)
for(int i = 1; xAxis - i > 0 && yAxis - i > 0; i++){
fieldNo = Field.getFieldNumber(xAxis - i, yAxis - i);
fig = currentField.getFigureAt(fieldNo);
if(fig == null){
continue;
}
if((fig.getColor() == colour && fieldNo != move.getFieldTo()) || fieldNo == move.getFieldTo()){
break;
}
figType = fig.getFigureType();
if(fig.getColor() != colour
&& (figType == ChessfigureConstants.BISHOP
|| figType == ChessfigureConstants.QUEEN
|| (figType == ChessfigureConstants.KING && i == 1)
|| (figType == ChessfigureConstants.PAWN && i == 1
&& fig.getColor() == ChessfigureConstants.WHITE))){
retractChanges(currentField, move, castling, capturedF);
return true;
}
else{
break;
}
}
//Springer prüfen
//TODO: übersichtlicher gestallten???????????
if(xAxis + 2 < 9 && yAxis + 1 < 9){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis + 2, yAxis + 1));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis + 1 < 9 && yAxis + 2 < 9){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis + 1, yAxis + 2));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis - 2 > 0 && yAxis + 1 < 9){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis - 2, yAxis + 1));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis + 1 < 9 && yAxis - 2 > 0){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis + 1, yAxis - 2));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis - 2 > 0 && yAxis - 1 > 0){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis - 2, yAxis - 1));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis - 1 > 0 && yAxis - 2 > 0){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis - 1, yAxis - 2));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis - 1 > 0 && yAxis + 2 < 9){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis - 1, yAxis + 2));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
if(xAxis + 2 < 9 && yAxis - 1 > 0){
fig = currentField.getFigureAt(Field.getFieldNumber(xAxis + 2, yAxis - 1));
if(fig != null && fig.getColor() != colour && fig.getFigureType() == ChessfigureConstants.KNIGHT){
retractChanges(currentField, move, castling, capturedF);
return true;
}
}
//Feld wieder in Ausgangsstellung bringen.
retractChanges(currentField, move, castling, capturedF);
//TODO: blackkingmoved etc. evtl. in die checkkingmove methode verlagern
// Position von isCheck entsprechend anpassen
if(castling && x > currentX){
if((colour == ChessfigureConstants.WHITE && !whiteKingMoved && !whiteRightRookMoved)
|| (colour == ChessfigureConstants.BLACK && !blackKingMoved && !blackRightRookMoved)){
return isCheck(currentField, move, false, position + 1)
&& isCheck(currentField, move, false, position + 2);
}
}
else if(castling && x < currentX){
if((colour == ChessfigureConstants.WHITE && !whiteKingMoved && !whiteLeftRookMoved)
|| (colour == ChessfigureConstants.BLACK && !blackKingMoved && !blackLeftRookMoved)){
return isCheck(currentField, move, false, position - 1)
&& isCheck(currentField, move, false, position - 2);
}
}
return false;
}
}//class