我正在构建一个需要生成6x6的小网格,但它需要符合4个关键约束。目前它符合3.我无法弄清楚如何管理第四个。
001001
101101
010110
110010
001101
所以这里必须发生的是:
以下是当前代码:
// JavaScript Document
$(document).ready(function () {
var grid = new anyGrid(6, 6);
for (var i = 0; i < grid.length; i++) {
var printIt = "";
for (var j = 0; j < grid[0].length; j++) {
printIt += grid[i][j] + " ";
}
console.log(printIt);
}
});
function anyGrid(rows, cols) {
var grid = [];
for (var i = 0; i < rows; i++) {
grid.push(new Array(cols));
}
var row = 0;
for (var col = 0; col - row < cols; col++) {
for (var r = row; r >= 0 && col - r < cols;) {
setBit(grid, r, col - r--);
}
if (row < rows - 1) row++;
}
return grid;
}
function setBit(grid, row, col) {
var vInd = calcVerticalIndicator(grid, row, col);
var hInd = calcHorizontalIndicator(grid, row, col);
if (isPartiallyRestricted(vInd, hInd)) {
grid[row][col] = flip(vInd);
} else if (isFullyRestricted(vInd, hInd)) {
grid[row][col] = vInd;
grid[row - 1][col] = flip(vInd);
} else {
grid[row][col] = Math.abs(vInd) <= 1
? flip(vInd)
: Math.abs(hInd) <= 1 ? flip(hInd) : anyBit();
}
}
function isPartiallyRestricted(vInd, hInd) {
return vInd == hInd;
}
function isFullyRestricted(vInd, hInd) {
return vInd + hInd == 1;
}
function calcVerticalIndicator(grid, row, col) {
return calcIndicator(grid, row - 1, col, row - 2, col, 2);
}
function calcHorizontalIndicator(grid, row, col) {
return calcIndicator(grid, row, col - 1, row, col - 2, 4);
}
function calcIndicator(grid, row1, col1, row2, col2, unrestricted) {
try {
return grid[row1][col1] * grid[row2][col2] + (grid[row1][col1] - grid[row2][col2]) * unrestricted;
} catch (e) {
return unrestricted;
}
}
function anyBit() {
return getRandomInt(0,1);
}
function flip(bit) {
return bit == 0 ? 1 : 0;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
问题:
目前它满足4个条件中的3个条件,但所需要的是任何行或列中每个数字不超过3个。如何修改我的代码才能实现这一目标?
示例输出:
0 1 1 0 1 0
1 1 0 0 1 0
1 0 1 1 0 1 (violation of 4 1s)
0 0 1 0 0 1 (violation of 4 0s)
1 1 0 0 1 0
1 1 0 1 1 0 (violation of 4 1s)
^ ^ ^ ^ ^
Violations
0 0 1 0 1 1
0 1 1 0 1 1 (violation of 4 1s)
1 0 0 1 0 0 (violation of 4 0s)
0 0 1 0 0 1
1 1 0 0 1 1 (violation of 4 1s)
1 1 0 1 1 0 (violation of 4 1s)
^ ^ ^
Violations
答案 0 :(得分:2)
这似乎有效。因为我删除了水平和垂直指示器,但不确定它是否正是您正在寻找的,但似乎能够生成带有约束的随机网格。我通过usedNumbers对象跟踪字符/位在行/ col中出现的次数。
我试图保持一种简单的方法(即每个列出的约束的if语句)...我试图使其可以配置为网格中的行/列以及&#34;可用的字符&#34;对于网格值(如果要扩展)。当然,有些解决方案是不可能的,因为如果字母太小而网格太大(例如,7x7为0,1位),你可能会重复超过3个字符。这是jsfiddle。
(function () {
//Polyfill for Array.indexOf... Needed for older browsers.
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
if ( this === undefined || this === null ) {
throw new TypeError( '"this" is null or not defined' );
}
var length = this.length >>> 0; // Hack to convert object.length to a UInt32
fromIndex = +fromIndex || 0;
if (Math.abs(fromIndex) === Infinity) {
fromIndex = 0;
}
if (fromIndex < 0) {
fromIndex += length;
if (fromIndex < 0) {
fromIndex = 0;
}
}
for (;fromIndex < length; fromIndex++) {
if (this[fromIndex] === searchElement) {
return fromIndex;
}
}
return -1;
};
}
//availableBits to be used to determine the "alphabet" of characters to generate.
var availableBits = [0, 1];
var availLen = availableBits.length;
//usedNumbers to keep track of how many were used in rows/cols.
var usedNumbers;
//How many times to try to generate a grid before failing.
var numTries = 30;
var currentTries = 1;
var success = false;
//Grid config
var grid;
var rows = 6;
var cols = 6;
var vThresh = rows/2;
var hThresh = cols/2;
//Impossible to generate a solution due to constraint 4. Pigeon-hole principle.
if (rows / availLen > vThresh || cols / availLen > hTresh) {
throw new Error("Need to shrink the grid size or add availableBits. There will be more than 3 characters in a row or column.");
}
//Try to generate the grid.
while (!success && currentTries <= numTries) {
try {
grid = new anyGrid(rows, cols);
success = true;
}
catch(e) {
currentTries++;
if (currentTries > numTries) {
console.error(e.message);
console.log("Could not generate anygrid after " + numTries + " attempts.");
}
}
}
if (success) {
console.log("Generated anygrid after " + currentTries + " attempts.");
printGrid(grid);
}
function printGrid (grid) {
for (var i = 0; i < grid.length; i++) {
var printIt = "";
for (var j= 0; j < grid[0].length; j++) {
printIt += grid[i][j] + " ";
}
console.log(printIt);
}
}
function anyGrid (rows, cols) {
var grid = [];
//set used numbers
usedNumbers = {vNumbers: new Array(rows), hNumbers: new Array(cols)};
for (var i = 0; i < rows; i++) {
grid.push(new Array(cols));
}
var row = 0;
for (var col = 0; col - row < cols; col++) {
for (var r = row; r >= 0 && col - r < cols;) {
setBit(grid, r, col - r--);
}
if (row < rows - 1) row++;
}
return grid;
};
//Complies to the 4 constraints:
//No 2 numbers consecutively in a row
//No 2 numbers consecutively in a column
//Use random when able
//No more than 3 of a number in a column or row
function setBit (grid, row, col) {
var needRandom = true;
var bit;
//"Clone" the availableBits to be able to remove characters when calling flip.
var availClone = availableBits.slice();
//Constraint 1: First check previous 2 rows
if ((row - 2) >= 0 && grid[row - 2][col] === grid[row - 1][col]) {
//Needs to flip
bit = flip(grid[row - 1][col], availClone);
needRandom = false;
}
//-------------------------------
//Constraint 2: Check previous 2 cols
else if ((col - 2) >= 0 && grid[row][col - 2] === grid[row][col - 1]) {
//Needs to flip
bit = flip(grid[row][col - 1], availClone);
needRandom = false;
}
//---------------------------------
//Constraint 3: Attempt a random
if (needRandom) {
bit = anyBit(availClone);
}
//-------------------------------
//Constraint 4: Flip if constraint 4 is now violated.
var vNumber = usedNumbers.vNumbers[row] || {};
var hNumber = usedNumbers.hNumbers[col] || {};
while (availClone.length && (vNumber[bit] >= vThresh || hNumber[bit] >= hThresh)) {
bit = flip(bit, availClone);
}
//-------------------------------------
//Set grid value and update vNumber and hNumber to be used in further iterations.
grid[row][col] = bit;
vNumber[bit] = vNumber[bit] + 1 || 1;
hNumber[bit] = hNumber[bit] + 1 || 1;
usedNumbers.vNumbers[row] = vNumber;
usedNumbers.hNumbers[col] = hNumber;
//----------------------------------
};
//Removes a bit from availableBits array and looks to return another random bit.
function flip (bit, availableBits) {
var index = availableBits.indexOf(bit);
//Remove bit from the available bits.
availableBits.splice(index, 1);
var length = availableBits.length;
if (length > 0) {
//Try another random character
return anyBit(availableBits);
}
//We cannot construct the grid, no more availble characters/bits
else {
throw new Error("Could not generate any grid for current configurations. Try again or expand the available characters.");
}
};
//Returns a random bit from the availableBits array.
function anyBit (availableBits) {
var length = availableBits.length;
var randomIndex = getRandomInt(0, length - 1);
return availableBits[randomIndex];
};
//Returns a random integer between min and max.
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
}());
编辑:使用vThresh和hThresh并将它们分别设置为rows / 2和cols / 2。代码和小提琴更新。