Задача генерации случайной матрицы объектов в JavaScript - PullRequest
1 голос
/ 10 апреля 2020

Я пытаюсь создать генератор судоку на сетке 4 на 4 в JavaScript. Поэтому я объявляю матрицу объектов, таких как {number: 0, cbd: 1}, которые представляют число, которое будет в ячейке, и переменную состояния, которая контролирует, можно ли позже вырыть эту ячейку (cbd):

var matrix = new Array(4).fill({number: 0, cbd: 1}).map(() => new Array(4).fill({number: 0, cbd: 1}));

Затем я использовал эту функцию, чтобы заполнить сетку, соблюдая все 3 ограничения судоку: нет повторений в строке, столбцах и квадрате:

fillmatrix4(matrix,tam){
var numberList = [...Array(4+1).keys()].slice(1); //[1,2,3,4]
for(var k = 0; k < 4**2; k++){
    var row = Math.floor(k/4);
    var col = k%4;
    if (matrix[row][col].number == 0){
        numberList.sort(() => Math.random() - 0.5); //shuffles the array
        for(var q = 0; q < numberList.length; q++){
            var ids = matrix[row].map(a => a.number); //creates an array with the number property from all cells in that row
            if (!(ids.includes(numberList[q]))){ //check if number is in row
                if ((matrix[0][col].number != numberList[q]) && (matrix[1][col].number != numberList[q]) && (matrix[2][col].number != numberList[q]) && (matrix[3][col].number != numberList[q])){ //check if number is in column 
                    var square = [];
                    if (row<2){It is used to find out what subgrid we are in
                        if (col<2){
                            square = [matrix[0][0].number, matrix[0][1].number, matrix[1][0].number, matrix[1][1].number];
                        } else {  
                            square = [matrix[0][2].number, matrix[0][3].number, matrix[1][2].number, matrix[1][3].number];
                        }
                    } else {
                        if (col<2){
                            square = [matrix[2][0].number, matrix[2][1].number, matrix[3][0].number, matrix[3][1].number];
                        } else {  
                            square = [matrix[2][2].number, matrix[2][3].number, matrix[3][2].number, matrix[3][3].number];
                        }
                    }
                    if (!(square.includes(numberList[q]))){ //check if number is that subgrid
                        matrix[row][col].number = numberList[q]; //if number not in row, column and square, adds it to matrix
                        if (this.checkGrid(matrix,tam)){ //returns true all matrix is filled
                            return matrix;
                        } 
                    }
                }
            }
        }
    }
}

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

Но теперь, с объявленной матрицей объектов выше, это не «перемешивание». Результатом всегда является сетка, заполненная так:

a | a | a | a
b | b | b | b
c | c | c | c
d | d | d | d
where a,b,c,d are numbers from 1 to 4.

В чем может быть причина этого?

1 Ответ

0 голосов
/ 10 апреля 2020

Когда вы делаете:

Array(4).fill({number: 0, cbd: 1})

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

                   .-----------.
                   | number: 0 |
                   | cbd: 1    |
                   `-----------`
                    ^  ^  ^  ^
                    |  |  |  |
variable `matrix`: [0, 1, 2, 3]

Изменения, внесенные в любой из этих индексов массива, изменят один и тот же базовый объект.

Вот минимальный, полный, воспроизводимый пример:

const arr = Array(4).fill({foo: "bar"});
arr[0].foo = "baz";
console.log(JSON.stringify(arr, null, 2));
console.log(arr);

Вы видите, что все 4 записи отражают изменения, внесенные в первый объект. Обратите внимание, что фрагмент стека console.log массива показывает «ref» для идентификатора объекта для 3 из 4 сегментов.

Чтобы устранить проблему, используйте .map для генерации различных объектов:

const arr = Array(4).fill().map(() => ({foo: "bar"}));
arr[0].foo = "baz";
console.log(JSON.stringify(arr, null, 2));
console.log(arr);

Или, в вашем коде:

const matrix = Array(4).fill().map(() => ({number: 0, cbd: 1}))
  .map(() => Array(4).fill().map(() => ({number: 0, cbd: 1})));

console.log(matrix);

(new не требуется).

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

Кроме того, если вам нужна хорошая перетасовка в JS, я рекомендую заглянуть в Фишер-Йейтс шаффл .

...