Я пытаюсь создать правильную судоку.

Я создал 3 метода для проверки чисел и один для генерации судоку.

createSudoku() пытается создать судоку.

colContainsNumber(): проверьте, содержит ли col случайное число, которое я сгенерировал

rowContainsNumber(): то же самое, что colContainsNumber, только для строки

squareContainsNumber(): проверьте, содержит ли блок случайное число.

В createSudoku() я генерирую случайное число, и с помощью цикла while я продолжаю генерировать новое число, пока ни один из «contains-Methods» не вернет 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 занимает слишком много времени.

0
Lars

1 ответ

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

function House() {
    this.digits = [];
    this.index = Object.create(null);
}
House.prototype.add = function( n) {
        if( this.index[n]) {
            return 0;
        }
        this.index[n] = true;
        this.digits.push(n);
        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) {
        console.log( "Invalid suduko");
        break;
    }
    sudoku[ index] = digit;
}

while (sudoku.length < 81) {
    sudoku.push('.');
};
for( let i = 0; i < 81; i += 9) {
    console.log( sudoku.slice( i, i+9).toString());
}

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

Я предполагаю, что в генераторе требуется какое-то обратное отслеживание, но, к сожалению, не имея такого проекта, у него нет алгоритма для обмена.

58587772