StackOverflowError в программе Magic Square для проверки магии квадрата

Думаю, я перейду к сути: мой учитель информатики дал нам задание, в котором он хотел, чтобы мы создали программу, которая генерирует магический квадрат 3 на 3 (это означает, что все строки, столбцы и диагонали квадрата должны равняться 15 ). Он хотел, чтобы мы использовали обычный массив (массив с одним измерением, а не с двумя) и имел по крайней мере две функции: одна рекурсивная и генерирует или перемешивает квадрат, а другая просто проверяет, является ли квадрат магическим. Программа должна вернуться и напечатать магический квадрат, и никаких действий со стороны пользователя не требуется.

Вот мой код (я помещаю его первым, так как проблему, с которой я столкнулся, легче объяснить, если он размещен первым; переходите к концу, чтобы узнать о фактических вопросах):

public class MagicSquare {
    public static void main(String[] args) {
        // main stub, get user input here
        int[] square = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        //int[] test = {2, 7, 6, 9, 5, 1, 4, 3, 8};

        //printMagicSquare(test);

        shuffleSquare(square, 0);       
        printMagicSquare(square);
    }

    public static int[] shuffleSquare(int[] square, int count) {
        // shuffles array
        Random randGen = new Random();

        if (count >= square.length-1) {
            return square;
        }
        else {
            int index = randGen.nextInt(square.length - 1) + 0;
            int temp = square[count];
            square[count] = square[index];
            square[index] = temp;

            shuffleSquare(square, count + 1);
        }
        return square;
    }

    public static boolean checkIfMagic(int[] square) {
        // returns true or false for whether or not inputted array is a magic square
        int MAGICNUM = 15;

        int row1 = square[0] + square[1] + square[2];
        //System.out.println(square[0] + " " + square[1] + " " + square[2]);
        int row2 = square[3] + square[4] + square[5];
        //System.out.println(square[3] + " " + square[4] + " " + square[5]);
        int row3 = square[6] + square[7] + square[8];
        //System.out.println(square[6] + " " + square[7] + " " + square[8] + "\n");

        int col1 = square[0] + square[3] + square[6];
        int col2 = square[1] + square[4] + square[7];
        int col3 = square[2] + square[5] + square[8];

        int diag1 = square[0] + square[4] + square[8];
        int diag2 = square[2] + square[4] + square[6];

        if (row1 == MAGICNUM && row2 == MAGICNUM && row3 == MAGICNUM && col1 == MAGICNUM && col2 == MAGICNUM && col3 == MAGICNUM && diag1 == MAGICNUM && diag2 == MAGICNUM) {
            return true;
        }
        else {
            return false;
        }
    }

    public static void printMagicSquare(int[] square) {
        // prints out magic square
        boolean isMagic = checkIfMagic(square);
        // check if square is magic (if it is, print it, if not then re-shuffle it and re-check it)
        if (isMagic == true) {
            System.out.println("Magic Square: ");
            for(int count = 0; count < square.length; count ++) {
                if (count == 3 || count == 6) {
                    System.out.println();
                    System.out.print(square[count] + " ");
                }
                else {
                    System.out.print(square[count] + " ");
                }
            }
            System.out.println("\n");
        }
        else {
            shuffleSquare(square, 0);
            printMagicSquare(square);
        }
    }
}

Итак, проблема, с которой я столкнулся, заключается в том, что программа перестает перемешивать квадрат через определенное количество раз. Обе функции shuffleSquare и checkIfMagic работают, они просто выдают stackOverflowError после перетасовки п раз. Я протестировал, будет ли это делать, если я сниму некоторые ограничения в функции checkIfMagic (например, я попробовал if (row1 == MAGICNUM && row2 == MAGICNUM && row3 == MAGICNUM)), но этого не произошло. Вместо этого он вывел то, что должно быть: квадрат, в котором суммы строк равны 15. Он начал показывать stackOverflowError, когда код был if (row1 == MAGICNUM && row2 == MAGICNUM && row3 == MAGICNUM && col1 == MAGICNUM && col2 == MAGICNUM && col3 == MAGICNUM). Однако, поскольку квадрат должен быть магическим (опять же, имея одинаковую сумму всех строк, столбцов и диагоналей), я не могу его использовать.

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

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

Hovercraft Full Of Eels 17.12.2018 05:26

@HovercraftFullOfEels спасибо за советы! Я запомню это в следующий раз, когда задам вопрос.

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

Ответы 1

попробуй это:

public class MagicSquare {
    public static void main(String[] args) {
        // main stub, get user input here
        int[] square = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        printMagicSquare(square);
    }
    static Random randGen = new Random();
    public static void shuffleSquare(int[] square, int i) {
        if (i > 0) {
            int index = randGen.nextInt(i);
            int temp = square[index];
            square[index] = square[i];
            square[i] = temp;
            shuffleSquare(square, i - 1);
        }
    }

    public static boolean checkIfMagic(int[] square) {
        // returns true or false for whether or not inputted array is a magic square
        int MAGICNUM = 15;

        int row1 = square[0] + square[1] + square[2];
        //System.out.println(square[0] + " " + square[1] + " " + square[2]);
        int row2 = square[3] + square[4] + square[5];
        //System.out.println(square[3] + " " + square[4] + " " + square[5]);
        int row3 = square[6] + square[7] + square[8];
        //System.out.println(square[6] + " " + square[7] + " " + square[8] + "\n");

        int col1 = square[0] + square[3] + square[6];
        int col2 = square[1] + square[4] + square[7];
        int col3 = square[2] + square[5] + square[8];

        int diag1 = square[0] + square[4] + square[8];
        int diag2 = square[2] + square[4] + square[6];

        if (row1 == MAGICNUM && row2 == MAGICNUM && row3 == MAGICNUM && col1 == MAGICNUM && col2 == MAGICNUM && col3 == MAGICNUM && diag1 == MAGICNUM && diag2 == MAGICNUM) {
            return true;
        }
        else {
            return false;
        }
    }

    public static void printMagicSquare(int[] square) {
        while (!checkIfMagic(square)){
            shuffleSquare(square, square.length - 1);
        }

        System.out.println("Magic Square: ");
        for(int count = 0; count < square.length; count ++) {
            if (count == 3 || count == 6) {
                System.out.println();
                System.out.print(square[count] + " ");
            }
            else {
                System.out.print(square[count] + " ");
            }
        }
        System.out.println("\n");
    }
}

Стековая память локальных переменных освобождается только после того, как переменные выходят за пределы области видимости. Когда вы вызываете printMagicSquare внутри printMagicSquare. Параметр вызывающего абонента все еще находится в области видимости, поэтому память не освобождается. Среда выполнения создает новые кадры стека над старыми для хранения локальных переменных и параметров вызываемого объекта. И это продолжается до тех пор, пока один из printMagicSquare не найдет ответ или пока у нас не закончится стековая память. Поскольку shuffleSquare не работает, есть только один выход.

    while (!checkIfMagic(square)){
        shuffleSquare(square, square.length - 1);
    }

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

Пожалуйста, объясните свой ответ, а не просто предоставьте дамп кода. Без объяснения проблемы OP и того, почему ваше решение помогает ее решить, ответ будет бесполезен для будущих посетителей.

Hovercraft Full Of Eels 17.12.2018 05:35

не стесняйтесь изменять ответ или размещать новый ответ, если считаете, что это невозможно исправить. Я ухожу на ужин.

W.H 17.12.2018 05:54

@JohnSmith благодарим вас за помощь! Сегодня я пошел к своему учителю, чтобы спросить, в порядке ли этот код; он сказал, что я неправильно понял, что он имел в виду, и помог мне понять, чего он хотел. Мне пришлось переделать часть кода, и мне удалось это решить. Приносим извинения за беспокойство и еще раз спасибо!

awkward-dingus 20.12.2018 02:29

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