змейка в двухмерном массиве java

Заполните массив числами увеличивающимися от 1 до n*n таким образом, чтобы последовательность чисел составляла змейку. Отобразить значения заполненного массива в консоль в виде таблицы. Программа должна корректно работать для любых значений n >= 2. Пример вывода результата для массива n = 3:

1 2 3
6 5 4
7 8 9

у меня вышло только:

1 2 3
7 8 9
6 5 4

    final int n = 3;
    final int range = n * n;
    int[][] masiv = new int[n][n];
    int x = 0;
    int y = n - 1;
    int ctr = 1;

    while (ctr <= range) {
        for (int i = 0; i < masiv.length; i++) {
            if (masiv[x][i] == 0) {
                masiv[x][i] = ctr++;
            }
        }

        for (int i = 0; i < masiv.length; i++) {
            if (masiv[i][y] == 1) {
                masiv[i][y] = ctr++;
            }
        }

        for (int i = masiv.length - 1; i >= 0; i--) {
            if (masiv[y][i] == 0) {
                masiv[y][i] = ctr++;
            }
        }

        for (int i = masiv.length - 1; i >= 0; i--) {
            if (masiv[i][x] == 0) {
                masiv[i][x] = ctr++;
            }
        }
        x++;
        y--;
    }

    for (int i = 0; i < masiv.length; i++) {
        for (int j = 0; j < masiv.length; j++) {
            System.out.printf("%-2d ", masiv[i][j]);
        }
        System.out.println("");
    }

Если можете оставьте комментарии чтоб можно было понять как это работает


Ответы (3 шт):

Автор решения: had0uken

Мой вариант решения: идея в том, что при заполнении цикла мы, переходя к каждой строчке, определяем с помощью переменной start и значения а порядок заполнения. Если старт = 0, и а=1, то заполнение с лева на право. Если старт = n-1, и а=-1, то заполнение с права на лево. (где n - размерность массива). Слева на право мы заполняем четные строки, справа на лево, нечетные строки Остальное вроде должно быть понятным.

Сам код:

public class Snake {
    public static void main(String[] args) {
        int n = 7;
        makeSnake(n);
    }

    public static void makeSnake(int n) {
        int[][] array = new int[n][n];

        int a = -1;
        int count = 1;
        for (int i = 0; i < n; i++) {
            a *= -1;
            int start = 0;
            if (i % 2 != 0) start = n - 1;
            else start = 0;
            for (int j = start; (j < n) & (j >= 0); j += a) {

                array[i][j] = count++;
            }
        }
        printMatrix(array);
    }

    public static void printMatrix(int[][] array) {

        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++)
                System.out.print(array[i][j] + " ");
            System.out.println();
        }
    }
}

Выход:

1 2 3 4 5 6 7 
14 13 12 11 10 9 8 
15 16 17 18 19 20 21 
28 27 26 25 24 23 22 
29 30 31 32 33 34 35 
42 41 40 39 38 37 36 
43 44 45 46 47 48 49 

Process finished with exit code 0
→ Ссылка
Автор решения: DronDron

Ну у меня такая идея (на примере n = 3):
генерируем табличку с числами так (слева номер строки):
0 | 1 2 3
1 | 4 5 6
2 | 7 8 9
а зачем строки с нечётным номером (выделен жирным) переворачиваем:
0 | 1 2 3
1 | 6 5 4 <-- перевернули
2 | 7 8 9
Вуаля! Ну только можно сразу перевёрнутыми генерировать, ну и в итоге получаем что-то такое:

public int[][] snake(int n) {
    int[][] res = new int[n][0];
    for (int i = 1, o = 0; i <= n * n; i += n, o++)
        res[o] = (o % 2 == 0 ? IntStream.range(i, i + n) : IntStream.iterate(i + n - 1, j -> --j).limit(n)).toArray();
    return res;
}

Если что-то непонятно (как часто бывает с тернарными операторами и потоками), то вот версия с объяснениями:

public int[][] snake_(int n) {
    int[][] res = new int[n][0];
    /*
      переменные:
      o - номер текущей строки;
      i - стартовый индекс строки (начинается с 1, шаг - n);
     */
    for (int i = 1, o = 0; i <= n * n; i += n, o++)
        res[o] = (
                // ЕСЛИ номер строки чётный
                o % 2 == 0 ?
                // ТО генерируем прямую строку в виде потока
                IntStream.range(i, i + n) :
                // ИНАЧЕ в обратном порядке (так же в виде потока, чтобы не писать лишний код)
                IntStream.iterate(i + n - 1, j -> --j).limit(n))
                // ну и в массив надо преобразовать
                .toArray();
    return res;
}

Ну вроде работает, протестировал на n от 1 до 7.

→ Ссылка
Автор решения: Nowhere Man

В квадратном массиве размером n x n будет содержаться n2 элементов. Поскольку индексация элементов массива начинается с 0, индексы и строк и столбцов будут находиться в диапазоне [0, n - 1].

Таким образом, для использования одного цикла при итерации по массиву следует взять последовательность чисел в диапазоне [0, n * n) или [0, n * n - 1], и такой индекс нужно будет перевести в индексы строк / столбцов при помощи операций целочисленного деления и остатка по модулю n соответственно:

int r = i / n;
int c = i % n;
arr[r][c] = i + 1; // сдвинуть значение на 1 в диапазон [1, n * n]

Оставшийся нюанс в том, что для реализации змейки в каждой строке с чётным индексом 0, 2,... индексы колонок идут в прямом порядке, а в строках с нечётным индексом - в обратном порядке:

r = 0; // для значений i = [0.. n - 1], c = i % n;
arr[r][0] = 1; arr[r][1] = 2; ... arr[r][n - 1] = n;

r = 1; // для значений i = [n.. 2 * n - 1], c = n - 1 - i % n;
arr[r][0] = 2 * n; arr[r][1] = 2 * n - 1; ... arr[r][n - 1] = n + 1;

Предоставленной информации должно быть достаточно для самостоятельного решения.

Полное решение:

public static int[][] snake(int n) {
    int[][] arr = new int[n][n];

    for (int i = 0, n2 = n * n; i < n2; ) {
        int r = i / n;
        int c = r % 2 == 0 ? i % n : n - 1 - i % n;
        arr[r][c] = ++i;
    }

    return arr;
}
→ Ссылка