Этот вопрос довольно большой, и его трудно решить, не просматривая мой код, и если это очень важно, то область, вероятно, слишком велика, и я удалю вопрос. В основном у меня есть рабочая игра в шахматы со всеми правилами шахмат, кроме проверки , следовательно, также не мат, пат и т. Д. .) реализовано.

Я приступил к реализации Check, присвоив Squares моей ChessBoard два логических значения: protectedByWhite и protectedByBlack. С проверкой есть два основных элемента логики:

  • Если белые делают ход, в результате которого их король оказывается на поле то есть protectedByBlack, и, наоборот, черными ход "отменено".
  • Если белые делают ход, в результате которого король черных оказывается на поле, равном protectedByWhite, и, наоборот, черным, то следующий ход черных должен поместить его короля на поле, отличное от protectedByWhite.

Таким образом, логика довольно проста. В моем классе ChessBoard у меня есть функции testCheckWhite и testCheckBlack, которые вызываются после каждого хода. Ходы вызываются в моем классе Square (простая функция щелчка мышью).

Основная проблема в том, что код глючит ... и я не знаю, почему и где. Основная ошибка в том, что:

  • Когда черные или белые в шахе, если они делают ход там, где они все еще находятся в шахе, этот ход не отменяется. Я знаю, что функция отмены работает нормально, так что в некоторой степени моя логика неверна.

Например, у меня есть ярлыки сбоку, которые предупреждают, когда черный / белый находится в поле зрения. Когда я сначала "чек" оппонента, лейбл уведомляет меня о чеке. Однако, когда я пытаюсь переместить короля на поле, где я все еще буду под шахом, на этикетке неправильно написано, что шаха нет. Я уже некоторое время работаю, пытаясь определить, где я ошибся, и я мог бы использовать какое-то направление.


Соответствующий код:

ChessBoard.Java

public static void setProtectedSquares() {
        // Reset
        for(Square s : BOARD_SQUARES) {
            s.protectedByWhite = false;
            s.protectedByBlack = false;
        }

        // Now set protections
        for(Square s : BOARD_SQUARES) {
            if(s.hasPiece() && s.getPiece().getTeamColor().equals(TeamColor.WHITE)) {
                Piece p = s.getPiece();
                for(int[] position : p.getLegalMoves(p.getPosition())) {
                    if(hasSquare(position)) {
                        getSquare(position).protectedByWhite = true;
                    }
                }
            }
        }
        for(Square s : BOARD_SQUARES) {
            if(s.hasPiece() && s.getPiece().getTeamColor().equals(TeamColor.BLACK)) {
                Piece p = s.getPiece();
                for(int[] position : p.getLegalMoves(p.getPosition())) {
                    if(hasSquare(position)) {
                        getSquare(position).protectedByBlack = true;
                    }
                }
            }
        }
}

public static boolean testCheckWhite() {

        // Get king position
        int[] whiteKingPosition = new int[]{};
        for(Square s : BOARD_SQUARES) {
            Piece p = s.getPiece();
            if(s.hasPiece() && (p.getPieceType()).equals(PieceType.KING)) {
                if((p.getTeamColor()).equals(TeamColor.WHITE)) {
                    whiteKingPosition = p.getPosition();
                }
            }
        }

        if(hasSquare(whiteKingPosition) && getSquare(whiteKingPosition).protectedByBlack) {
            GameInfoPanel.inCheckWhite.setText("White is in check");
            return true;
        } else {
            GameInfoPanel.inCheckWhite.setText("White is not in check");
            return false;
        }
    }

    public static boolean testCheckBlack() {

        // Get king position
        int[] blackKingPosition = new int[]{};
        for(Square s : BOARD_SQUARES) {
            Piece p = s.getPiece();
            if(s.hasPiece() && (p.getPieceType()).equals(PieceType.KING)) {
                if((p.getTeamColor()).equals(TeamColor.BLACK)) {
                    blackKingPosition = p.getPosition();
                }
            }
        }

        if(hasSquare(blackKingPosition) && getSquare(blackKingPosition).protectedByWhite) {
            GameInfoPanel.inCheckBlack.setText("Black is in check");
            return true;
        } else {
            GameInfoPanel.inCheckBlack.setText("Black is not in check");
            return false;
        }
    }

Square.java

.... // If a square is clicked that IS colored...
        } else {
            for(Square s : ChessBoard.BOARD_SQUARES) {
                if(s.hasPiece() && (s.getPiece()).getFocus()) {

                    // Check to make sure that the target square and current
                    // square are not the same
                    if(!this.equals(s)) {
                        movePiece(s);

                        ChessBoard.setProtectedSquares();

                        // Test for check
                        // 1) Find out what color the moved piece is
                        if((ChessBoard.getTurn()) == TeamColor.WHITE) {
                            if(ChessBoard.testCheckWhite()) {
                                // Undo move
                                s.movePiece(ChessBoard.getSquare(STORED_POSITION));
                                GameInfoPanel.gameStatus.setText("Illegal move, white in check");
                            } else if(ChessBoard.testCheckBlack()) {
                                // Move is okay, black is now in check
                                GameInfoPanel.gameStatus.setText("Okay move, black in check");
                                // Switch players' turn
                                ChessBoard.switchTurn();
                            } else {
                                // Move is okay, nothing happened
                                GameInfoPanel.gameStatus.setText("No one in check");
                                // Switch players' turn
                                ChessBoard.switchTurn();
                            }

                        } else {
                            if(ChessBoard.testCheckBlack()) {
                                // Undo move
                                s.movePiece(ChessBoard.getSquare(STORED_POSITION));
                                GameInfoPanel.gameStatus.setText("Illegal move, black in check");
                            } else if(ChessBoard.testCheckWhite()) {
                                // Move is okay, white is now in check
                                GameInfoPanel.gameStatus.setText("Okay move, white in check");
                                // Switch players' turn
                                ChessBoard.switchTurn();
                            } else {
                                // Move is okay, nothing happened
                                GameInfoPanel.gameStatus.setText("No one in check");
                                // Switch players' turn
                                ChessBoard.switchTurn();
                            }
                        }
                    }
                }
            }

            // Clear all color and focus
            ChessBoard.clearFocus();

            ChessBoard.setProtectedSquares();
        }
8
sir_thursday 30 Апр 2014 в 10:04

3 ответа

Лучший ответ

Я прекрасно понимаю алгоритм вашего кода. К сожалению, я не вижу ничего плохого в опубликованном вами фрагменте.

Вот почему вы всегда должны использовать модульные тесты при написании кода. :)

  1. Модульное тестирование setProtectedSquares ()
  2. Модульное тестирование testCheckWhite ()
  3. Модульное тестирование testcCheckBlack ()
  4. Единичный тест ЗАТЕМ РЕФАКТОР for(Square s : ChessBoard.BOARD_SQUARES) {...}

Это поможет вам в долгосрочной перспективе.

Однако, если вы хотите (надеюсь) решить проблему быстрее, используйте режим отладчика в вашей среде IDE.

3
renz 30 Апр 2014 в 06:44

Вот предлагаемое направление расследования. Предположим, что это сценарий: белые сделали чек, и черный король может перейти на другое поле, защищенное белыми.

Исходя из предоставленного кода и того факта, что черный цвет (под контролем) может перемещаться в квадрат, защищенный белым, метод ChessBoard.testCheckBlack() должен возвращать false. Теперь, основываясь на реализации метода ChessBoard.testCheckBlack(), мы можем сделать вывод, что текст

«Черные под шахом»

Должен выводиться на GameInfoPanel.

Если это верно, то необходимо проверить по очереди следующее:

hasSquare(blackKingPosition)
getSquare(blackKingPosition).protectedByWhite // just protectedByWhite 

Было бы здорово, если бы вы могли разместить GameInfoPanel сообщений для описанного выше сценария.

2
bytefire 30 Апр 2014 в 16:24

Проверка того, находится ли какое-либо поле под угрозой, является полезной функцией, которую вы можете использовать не только для прямых атак короля, но и для рокировки, поскольку королю не разрешается рокировать "сквозной" шах. Это означает, что вы должны убедиться, что до трех квадратов свободны от прямой линии атаки противника, чтобы законно рокировать короля.

Имея это в виду, вы можете создать такой метод:

public static final boolean isThreatenedSquare(
          Color threatenedColor, 
          Square threatenedSquare, 
          Chessboard board)

Алгоритм скользящих фигур может использовать параллельные массивы для определения 8 направлений (линий атаки или «лучей»), исходящих из исходной точки (квадрата, находящегося под угрозой). Например:

int[] rowDirections = {-1, -1, -1, 0, 0, 1, 1, 1};
int[] colDirections = {-1, 0, 1, -1, 1, -1, 0, 1};
  • первый набор индексов (-1, -1) представляет собой диагональный «луч», движущийся в направлении « северо-запад ».
  • второй набор индексов (-1, 0) представляет собой вертикальный «луч», движущийся в направлении « на север ».
  • третий набор индексов (-1, 1) представляет собой диагональный «луч», движущийся в направлении « на северо-восток ».
  • четвертый набор индексов (0, -1) представляет собой горизонтальный «луч», движущийся в направлении « на запад ».

... и так далее. Выделяя по одной клетке за раз, вы просто осматриваете квадрат (убедившись, что находитесь в пределах границ шахматной доски) и видите, занято ли оно. Если да, то определите, дружеская это фигура или фигура соперника. То, что мы ударили по фигуре соперника, не обязательно означает, что наше угрожаемое поле находится под атакой.

Епископ, например, может атаковать только по диагональным лучам, поэтому обнаружение одного по вертикальному лучу не дает нашему лучу распространяться дальше, однако епископ не угрожает квадрату. Мы можем точно описать атакующие возможности любой скользящей части относительно параллельных направленных массивов, которые мы определили ранее. Например:

boolean bishopThreats[] = {true, false, true, false, false, true, false, true};
boolean rookThreats[] = {false, true, false, true, true, false, true, false};
boolean queenThreats[] = {true, true, true, true, true, true, true, true};
boolean kingThreats[] = {true, true, true, true, true, true, true, true};

Массивы выше показывают, что слоны могут угрожать только по диагоналям, ладьи по вертикальным и горизонтальным линиям, ферзи и короли могут атаковать в любом направлении.

Пешки несколько сложны, потому что они атакуют по диагоналям, но только в направлениях северо-восток + северо-запад (для белых) и юго-восток + юго-запад (для черных).

boolean kill = threatenedColor.equals(Color.black) ? true : false;
boolean pawnThreats[] = {kill, false, kill, false, false, !kill, false, !kill};

Когда все готово, все, что требуется, - это использовать пару вложенных циклов for. Внешний - для повторения во всех направлениях, внутренний - для излучения по одному квадрату за раз, пока мы не коснемся края шахматной доски или не ударим по фигуре, в зависимости от того, что наступит раньше. Вот алгоритм раздвижных фигур. Рыцарь немного отличается от скользящих частей, но общие идеи, представленные здесь, также применимы.

boolean threatDetected = false;
int threatenedRow = threatenedSquare.getRow();
int threatenedCol = threatenedSquare.getCol();

for(int direction = 0; direction < 8 && !threatDetected; direction++) {
    // RESET OUR COORDINATES TO PROCESS CURRENT LINE OF ATTACK. 
    // INCREMENT VALUES ARE SAME AS DIRECTION ARRAY VALUES
    int row = threatenedRow;
    int col = threatenedCol;
    int rowIncrement = rowDirections[direction];
    int colIncrement = colDirections[direction];

    // RADIATE OUTWARDS STARTING FROM ORIGIN UNTIL WE HIT A PIECE OR ARE OUT OF BOUNDS
    for(int step = 0; step < 8; step++) {
        row = row + rowIncrement;
        col = col + colIncrement;

        // IF WE ARE OUT OF BOUNDS, WE STOP RADIATING OUTWARDS FOR 
        // THIS RAY AND TRY THE NEXT ONE
        if(row < 0 || row > 7 || col < 0 || col > 7) {
            break;
        }
        else {
            // LOOK AT CURRENT SQUARE AND SEE IF IT IS OCCUPIED BY A PIECE
            Square square = board.getSquare(row, col);
            IPiece piece = square.getPiece();
            if(piece != null) {
                // RADIATING OUTWARDS MUST STOP SINCE WE HIT A PIECE, ONLY
                // QUESTION IS WHAT DID WE HIT? FRIEND OR FOE?  
                if(!piece.getColor.equals(threatenedColor)) {
                    // WE ARE FACING AN OPPONENT, DOES IT HAVE THE CAPABILITY
                    // TO ATTACK US GIVEN THE DIRECTIONAL LINE OF ATTACK  
                    // WE ARE CURRENTLY ANALYZING     
                    if(piece instanceof Bishop && bishopThreats[direction]) 
                        threatDetected = true;
                    else if(piece instanceof Rook && rookThreats[direction]) 
                        threatDetected = true;
                    else if(piece instanceof Queen && queenThreats[direction]) 
                        threatDetected = true;
                     else {
                        if(step == 0) {  
                            // PAWNS AND KINGS DONT HAVE THE REACH OF OTHER SLIDING
                            // PIECES; THEY CAN ONLY ATTACK SQUARES THAT ARE CLOSEST
                            // TO ORIGIN  
                            if(piece instanceof Pawn && pawnThreats[direction]) 
                                threatDetected = true;
                            if(piece instanceof King && kingThreats[direction]) 
                                threatDetected = true;
                        }  
                    }
                }
                break;
            }
        }
    }
}
2
Constantin 5 Дек 2014 в 18:00