Я давно занимаюсь шахматной программой. Я создал класс под названием Checkmate для обнаружения проверок, незаконных ходов, матов и пат. На данный момент я только что реализовал Проверки и Незаконные ходы. Но всякий раз, когда я запускаю программу, возникает ошибка StackOverflowError.
/**
* <code>String player</code> contains the constant of the currently playing player.
* This method will first find out the position of the opponent's King and store it in <code>Point opponentKing</code>.
* After that, it will find all the currently playing player's pieces. It will find the possible moves of each of the piece.
* If the <code>opponentKing</code> is found within the possible moves of any piece, it will return "true, else it will return "false".
* @return "true" if it is check. "false" if it is not a check.
*/
public boolean getIsCheck(String[][] board) {
boolean isCheck = false;
Point opponentKing = new Point(0,0);
outer: for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (!board[i][j].substring(1).equals(player) && board[i][j].substring(0,1).equals(Board.KING)) {
opponentKing = new Point(i, j);
break outer;
}
}
}
List<Point> friendlyPieces = new ArrayList<>();
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
if (board[i][j].substring(1).equals(player)
&& !board[i][j].equals(Board.EMPTY))
friendlyPieces.add(new Point(i, j));
outer: for(Point p : friendlyPieces) {
List<Point> availableMoves = new ArrayList<>();
switch (board[p.x][p.y].substring(0,1)){
case Board.PAWN: availableMoves = new Pawn(player).getCheckMoves(p); break;
case Board.ROOK: availableMoves = new Rook(player).getAvailableMoves(p); break;
case Board.KNIGHT: availableMoves = new Knight(player).getAvailableMoves(p); break;
case Board.BISHOP: availableMoves = new Bishop(player).getAvailableMoves(p); break;
case Board.KING: availableMoves = new King(player).getAvailableMoves(p); break;
case Board.QUEEN: availableMoves = new Queen(player).getAvailableMoves(p); break;
}
for (Point point: availableMoves) {
if (point.equals(opponentKing)) {
isCheck = true;
break outer;
}
}
}
return isCheck;
}
Это код для определения того, является ли текущая позиция фигур на доске шахом для короля.
public boolean getIsIllegal(Point start, Point end, Pieces piece){
String[][] board = Board.board;
board[start.x][start.y] = Board.EMPTY;
board[end.x][end.y] = piece.getPiece() + piece.getPlayer();
return getIsCheck(board);
}
Это getIsIllegal () из того же класса Checkmate.
Каждый раз, когда я выбираю пешку с доски. Это дает мне следующую ошибку: -
Exception in thread "main" java.lang.StackOverflowError
at Pieces.Pawn.getCheckMoves(Pawn.java:56)
at Win.Checkmate.getIsCheck(Checkmate.java:60)
at Win.Checkmate.getIsIllegal(Checkmate.java:81)
at Pieces.Knight.getAvailableMoves(Knight.java:30)
at Win.Checkmate.getIsCheck(Checkmate.java:62)
at Win.Checkmate.getIsIllegal(Checkmate.java:81)
at Pieces.Knight.getAvailableMoves(Knight.java:34)
at Win.Checkmate.getIsCheck(Checkmate.java:62)
at Win.Checkmate.getIsIllegal(Checkmate.java:81)
И так далее.
if (x<7 && y<6 && isEmpty(x + 1, y + 2) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x + 1, y + 2));
if (x>0 && y<6 && isEmpty(x - 1, y + 2) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x - 1, y + 2));
if (x<6 && y>0 && isEmpty(x + 2, y - 1) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x + 2, y - 1));
if (x<6 && y<7 && isEmpty(x + 2, y + 1) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x + 2, y + 1));
if (x<7 && y>1 && isEmpty(x + 1, y - 2) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x + 1, y - 2));
if (x>0 && y>1 && isEmpty(x - 1, y - 2) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x - 1, y - 2));
if (x>1 && y>0 && isEmpty(x - 2, y - 1) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x - 2, y - 1));
if (x>1 && y<7 && isEmpty(x - 2, y + 1) && !check.getIsIllegal(point, new Point(x, y), this)) availableMoves.add(new Point(x - 2, y + 1));
Приведенный выше код - это строки, которые я написал, чтобы получить доступные ходы для коня на текущей доске. Это постоянный цикл между getIsCheck () и getIsIllegal (). Пожалуйста, обратитесь к Исключению для дальнейших разъяснений.
Ваш метод isCheck очень дорогой. Я бы предложил вместо этого сохранить позицию королей в начале и изменять ее по мере движения.
Я написал часть кода в getAvailableMoves () в своем вопросе. Последний фрагмент кода (содержащий 8 if) - это код для Knight.getAvailableMoves (). Да, в этом методе я вызываю getIsIllegal (). Если предположить, что эта логика / подход неверны, как мне это сделать?




Фигура проверяет короля, хотя ход фигуры недопустим! Например: белые Kc2, Rb2 - черные Kh2, Ba3:
После хода Kc2-c1 Rb2 дает шах, хотя Rb2 не может двигаться.
Измените свое определение доступного и незаконного хода: доступный ход может быть незаконным. Таким образом, getAvailableMoves () не вызывает getIsIllegal (). Итак, Rb2-h2 - доступный ход, и метод isCheck () работает.
Теперь, чтобы получить законные ходы, вам нужно написать такой код:
...
Pieces piece;
switch (board[p.x][p.y].substring(0,1)){
case Board.PAWN: piece = new Pawn(player); break;
case Board.ROOK: piece = new Rook(player); break;
case Board.KNIGHT: piece = new Knight(player); break;
case Board.BISHOP: piece = new Bishop(player); break;
case Board.KING: piece = new King(player); break;
case Board.QUEEN: piece = new Queen(player); break;
}
List<Point> availableMoves = piece.getAvailableMoves(p);
List<Point> legalMoves = new ArrayList<>();
for (Point point : availableMoves ) {
if (!getIsIllegal(p, point, piece))
legalMoves.add(point);
}
...
Спасибо, но я должен сказать вам, что это также приведет к ошибке StackOverflowError. Всякий раз, когда я проверяю недопустимый ход с помощью getIsIllegal (), я делаю копию исходной доски и предполагаю, что игрок хочет сделать определенный ход, а затем проверяю, находится ли доска на проверке, предполагая, что игрок играет этот ход с помощью getIsCheck ( ). Следовательно, getIsIllegal () и getIsCheck () будут продолжать вызывать друг друга. Я хотел удалить этот вопрос, так как сам нашел ответ. В любом случае, спасибо, что поделились идеей, я воплощу ее в другом месте.
Какой код у
getAvailableMoves(); Вы вызываете там дополнительные методы? Если я правильно понимаю, ваш стек:getIsIllegal()->getIsCheck()->getCheckMoves()/getAvailableMoves()?