【问题标题】:Page doesn't respond while creating a sudoku创建数独时页面没有响应
【发布时间】:2019-10-28 08:37:41
【问题描述】:

我正在尝试创建一个正确的数独。

我创建了 3 种方法来检查数字和一种方法来生成数独。

createSudoku() 尝试创建数独。

colContainsNumber():检查col是否包含我生成的随机数

rowContainsNumber(): 与 colContainsNumber 相同,仅针对行

squareContainsNumber():检查一个块是否包含随机数。

createSudoku() 中,我生成随机数,并通过 while 循环继续生成一个新数字,直到没有“包含方法”返回 true(如果“是的,数字已经在行中,则为 true”等。 )

使用所有方法自己创建数独作品。 (例如,如果我只使用 rowContainsNumber,我会得到一个数独,其中没有行包含相同的数字等)

但如果我同时使用所有三种方法,页面将不会响应。

我尝试更改我在 while 循环中调用的方法的顺序,但实际上并没有改变太多,因为如果我只调用其中一个方法,这些方法就可以正常工作。

function createSudoku() {
    var sudoku = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0]
    ];
    for (var i = 0; i < 9; i++) {
        for (var j = 0; j < 9; j++) {
            //generate a random number between 1 and 9
            var randomNumber = Math.floor((Math.random() * 9) + 1);

            /*Keep generate a random number, until the square doesn't contain 
            the number. This is the loop where I'm supposed to use all three 
            Methods (colContains-, rowContains- and squareContainsNumber) but 
            the page doesn't respond if I use all three of them. If I only use 
            one like you can see now, the generation works fine*/

            while (squareContainsNumber(sudoku, i, j, randomNumber)) {
                randomNumber = Math.floor((Math.random() * 9) + 1);

            }
            sudoku[i][j] = randomNumber;
            solvedSudoku[i][j] = randomNumber;
        }
    }
    return sudoku;
}

function rowContainsNumber(sudoku, col, number) {
    for (var i = 0; i < 9; i++) {
        if (sudoku[col][i] == number) {
            return true;
        }
    }
    return false;
}

function colContainsNumber(sudoku, row, number) {
    for (var i = 0; i < 9; i++) {
        if (sudoku[i][row] == number) {
            return true;
        }
    }
    return false;
}

function squareContainsNumber(sudoku, col, row, number)
{
    var minRow, maxRow, minCol, maxCol = 0;
    //Check which column the loop is in, then set the min and max column so I 
    //can get the range of the block
    switch (col) {
        case 0:
        case 1:
        case 2:
            minCol = 0;
            maxCol = 2;
            break;
        case 3:
        case 4:
        case 5:
            minCol = 3;
            maxCol = 5;
            break;
        case 6:
        case 7:
        case 8:
            minCol = 6;
            maxCol = 8;
            break;
        default:
            break;
    }
    //Check which row the loop is in, then set the min and max row so I 
    //can get the range of the block
    switch (row) {
        case 0:
        case 1:
        case 2:
            minRow = 0;
            maxRow = 2;
            break;
        case 3:
        case 4:
        case 5:
            minRow = 3;
            maxRow = 5;
            break;
        case 6:
        case 7:
        case 8:
            minRow = 6;
            maxRow = 8;
            break;
        default:
            break;
    }

   //loop through the square and check If the square contains the random number
    for (var i = minRow; i <= maxRow; i++) {
        for (var j = minCol; j <= maxCol; j++) {
            if (sudoku[i][j] == number)
                return true;
        }
    }

    return false;
}

预期结果将是一个正确的数独,其中没有行、没有列和没有正方形包含相同的数字。

但就像我已经说过的,页面只是没有响应,可能是因为 while 循环太长了。

【问题讨论】:

  • 我怀疑可能需要回溯以避免生成无效的数独,由于单元格已经分配了值,因此无法通过更改下一个空方格的值来修复。您是否研究过现有算法来生成(已解决的)数独板?
  • @traktor53 我试图找到一些回溯算法,但其中很多都在使用已经有值的“数独板”,而我的却没有。

标签: javascript sudoku


【解决方案1】:

基于满足不重复行、列或框中现有数字的约束来随机选择数独单元格值的算法是不完整的。人们可能会遵循这些限制条件,但仍会发现一个空单元格先前已将所有数字 1-9 分配为一行、单元格或框中的邻居。

当发布的代码达到此条件时,它会尝试为拼图生成一个新的随机数字,而不检查是否可能。由于页面不可能挂起,因为它会继续尝试另一个不起作用的随机数字。

此代码 sn-p 检查空单元格的房屋(行、列或框)是否确实有未使用的数字,如果没有则重试拼图:

var attempts = 0;

function puzzle( sudoku) {
    ++attempts;

    function House() {
        this.index = Object.create(null);
    }
    House.prototype.add = function( n) {
            if( this.index[n]) {
                return 0;
            }
            this.index[n] = true;
            return n;
        };
    
    let houses = [];
    for( var i = 0; i < 27; ++i) {
        houses [i] = new House();
    }
    let rowOf = index =>  Math.floor(index/9);
    let colOf = index =>  index%9;
    let boxOf = index =>  3 * Math.floor( rowOf( index)/3) + Math.floor( colOf( index)/3);
    
    function randomDigit( index) {
        let rowHouse = houses[ rowOf( index)];
        let colHouse = houses[ 9 + colOf(index)];
        let boxHouse = houses[ 18 + boxOf(index)];
        let domain = [1,2,3,4,5,6,7,8,9].reduce( function( array, digit) {
            if( !(rowHouse.index[ digit] || colHouse.index[digit] || boxHouse.index[ digit])) {
                array.push( digit);
            }
            return array;
        }, []);
        let digit = domain.length ? domain[ Math.floor( domain.length * Math.random())] : 0;
        if( digit) {
            rowHouse.add(digit);
            colHouse.add(digit);
            boxHouse.add(digit);
        }
        return digit;
    }

    var sudoku = [];
    for( var index = 0 ; index < 81; ++index) {
        let digit = randomDigit( index);
        if( digit == 0) {
            break;
        }
        sudoku[ index] = digit;
    }

    if( sudoku.length == 81) {
        return sudoku;
    }
    return puzzle();
}

const sudoku = puzzle();

console.log( "Attempts = " + attempts);
if( sudoku.length < 81) {
    sudoku.push('x');
    console.log("invalid sudoku");
}
for( let i = 0; i < 81; i += 9) {
    console.log( sudoku.slice( i, i+9).toString());
}

运行 sn-p 表明可能需要大量尝试才能获得结果。

快速浏览网络表明,这可能是生成完整谜题的一种不同寻常的方法,如果没有进一步的经验,我无法评论它的有用性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2021-11-10
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2023-01-11
    • 2018-04-04
    相关资源
    最近更新 更多