在 JavaScript 中生成对象的随机矩阵时出现问题
Problem generating random matrix of objects in JavaScript
我正在尝试在 JavaScript 中的 4 x 4 网格上制作数独生成器。
因此,我声明了一个对象矩阵,例如 {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。
但是现在,随着上面声明的对象矩阵,它不是 "shuffling"。结果始终是这样填充的网格:
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.
这可能是什么原因?
当你这样做时:
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" 到 4 个存储桶中的 3 个的对象 ID。
要解决此问题,请使用 .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
)。
顺便说一句,尽量避免嵌套很深的块。考虑编写辅助函数来处理其中的一些逻辑并使代码更易于理解。
此外,如果您正在寻找 JS 中的良好改组,我建议查看 Fisher-Yates shuffle。
我正在尝试在 JavaScript 中的 4 x 4 网格上制作数独生成器。 因此,我声明了一个对象矩阵,例如 {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。
但是现在,随着上面声明的对象矩阵,它不是 "shuffling"。结果始终是这样填充的网格:
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.
这可能是什么原因?
当你这样做时:
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" 到 4 个存储桶中的 3 个的对象 ID。
要解决此问题,请使用 .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
)。
顺便说一句,尽量避免嵌套很深的块。考虑编写辅助函数来处理其中的一些逻辑并使代码更易于理解。
此外,如果您正在寻找 JS 中的良好改组,我建议查看 Fisher-Yates shuffle。