Обнаружить диагональ в матрице на Java (победа в игре Connect Four)

Я делаю игру Connect 4. Цель состоит в том, чтобы выровнять четыре элемента одинаково.

У меня есть двойной массив: Player[6][7], который заполняется игроком, игравшим в этом слоте.

Я работаю над условиями победы, есть:

  • линии (рабочие)
  • колонки (рабочие)
  • диагонали сверху слева направо вниз -> не работает
  • диагонали снизу слева вверху справа -> не работает

И диагонали не работают.

Вот мой код, который проверяет победы:

private final Player[][] board = new Player[6][7]; // the board filled

public Player hasWinner() {
    // Lines (rows)
    for(int y = 0; y < board.length; y++) { // simple lines
        Player last = null;
        int nb = 0;
        Player[] line = board[y];
        for(int x = 0; x < line.length; x++) {
            Player played = line[x];
            if ((last == null || played == last) && played != null) { // new player or same as before
                nb++;
                if (nb == 4) // it's this !
                    return played;
            } else { // else reset
                nb = (played == null ? 0 : 1);
            }
            last = played;
        }
    }

    // Columns
    for(int x = 0; x < board[0].length; x++) { // simple columns
        Player last = null;
        int nb = 0;
        for(int y = 0; y < board.length; y++) { // for each columns
            Player played = board[y][x];
            if ((last == null || played == last) && played != null) { // new player or same as before
                nb++;
                if (nb == 4) // it's this !
                    return played;
            } else { // else reset
                nb = (played == null ? 0 : 1);
            }
            last = played;
        }
    }
   
    // ➡️ HERE IS THE INTERESTING PART
    // Diagonals
    for(int i = -board.length; i < board[0].length; i++) { // diagonals
        Player last = null;
        int nb = 0;
        for(int j = 0; j < 9; j++) {
            if (board.length <= j || board[j].length <= j)
                continue;
            Player played = board[j][j];
            if ((last == null || played == last) && played != null) { // new player or same as before
                nb++;
                if (nb == 4) // it's this !
                    return played;
            } else { // else reset
                nb = (played == null ? 0 : 1);
            }
            last = played;
        }
        for(int j = 9; j < 0; j--) {
            if (board.length <= j || board[j].length <= j)
                continue;
            Player played = board[j][board[j].length - j];
            if ((last == null || played == last) && played != null) { // new player or same as before
                nb++;
                if (nb == 4) // it's this !
                    return played;
            } else { // else reset
                nb = (played == null ? 0 : 1);
            }
            last = played;
        }
    }
    return null;
}

Как сделать так, чтобы победа с диагоналями работала?

board[j][j] и board[j][board[j].length - j] — это только (своего рода) главные диагонали; но поскольку нам нужно только 4 из 6х7, диагоналей гораздо больше (например, [j][j+1], [j+1][j]) - я бы проверял после каждого хода, завершает ли новая фигура четыре подряд
user85421 15.08.2024 20:51

Я бы это сделал так: hasWinner(Player[] slots) тогда вы могли бы создавать новые массивы со своей доски для проверки и передавать их в has Winner. Логика hasWinner будет очень простой — пройтись по массиву и найти четыре подряд.

ControlAltDel 15.08.2024 20:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Избегайте магических чисел, таких как 9. Используйте длину строк и столбцов матрицы в качестве верхних границ. Укажите константу для размера совпадения, например 4.

Что касается диагоналей, сравните текущего игрока с направлением [row + dy, col + dx].

public class Connect4 {
    private static final int ROWS = 6;
    private static final int COLS = 7;
    private static final int MATCH_SIZE = 4; // Number of pieces needed to win

    private final Player[][] board = new Player[ROWS][COLS]; // the board

    public Player hasWinner() {
        // Check horizontal lines
        for (int y = 0; y < board.length; y++) {
            Player last = null;
            int count = 0;
            for (int x = 0; x < board[y].length; x++) {
                Player current = board[y][x];
                if (current != null && current == last) {
                    count++;
                    if (count == MATCH_SIZE) {
                        return current;
                    }
                } else {
                    count = 1;
                    last = current;
                }
            }
        }

        // Check vertical lines
        for (int x = 0; x < board[0].length; x++) {
            Player last = null;
            int count = 0;
            for (int y = 0; y < board.length; y++) {
                Player current = board[y][x];
                if (current != null && current == last) {
                    count++;
                    if (count == MATCH_SIZE) {
                        return current;
                    }
                } else {
                    count = 1;
                    last = current;
                }
            }
        }

        // Check diagonal lines (top-left to bottom-right)
        for (int y = 0; y <= board.length - MATCH_SIZE; y++) {
            for (int x = 0; x <= board[y].length - MATCH_SIZE; x++) {
                Player current = board[y][x];
                if (current != null &&
                    current == board[y + 1][x + 1] &&
                    current == board[y + 2][x + 2] &&
                    current == board[y + 3][x + 3]) {
                    return current;
                }
            }
        }

        // Check diagonal lines (bottom-left to top-right)
        for (int y = MATCH_SIZE - 1; y < board.length; y++) {
            for (int x = 0; x <= board[y].length - MATCH_SIZE; x++) {
                Player current = board[y][x];
                if (current != null &&
                    current == board[y - 1][x + 1] &&
                    current == board[y - 2][x + 2] &&
                    current == board[y - 3][x + 3]) {
                    return current;
                }
            }
        }

        return null; // No winner found
    }
}

Рефакторинг логики

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

public class Connect4 {
    private static final int ROWS = 6;
    private static final int COLS = 7;
    private static final int MATCH_SIZE = 4; // Number of pieces needed to win

    private final Player[][] board = new Player[ROWS][COLS]; // the board

    public Player hasWinner() {
        for (int y = 0; y < ROWS; y++) {
            for (int x = 0; x < COLS; x++) {
                Player current = board[y][x];
                if (current == null) {
                    continue;
                }

                // Check right (horizontal)
                if (x <= COLS - MATCH_SIZE && checkDirection(y, x, 0, 1)) {
                    return current;
                }

                // Check down (vertical)
                if (y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, 0)) {
                    return current;
                }

                // Check down-right (diagonal)
                if (x <= COLS - MATCH_SIZE && y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, 1)) {
                    return current;
                }

                // Check down-left (anti-diagonal)
                if (x >= MATCH_SIZE - 1 && y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, -1)) {
                    return current;
                }
            }
        }

        return null; // No winner found
    }

    private boolean checkDirection(int y, int x, int dy, int dx) {
        Player player = board[y][x];
        for (int i = 1; i < MATCH_SIZE; i++) {
            if (board[y + i * dy][x + i * dx] != player) {
                return false;
            }
        }
        return true;
    }
}

Другие вопросы по теме