123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- * Copyright (c) 2011 Nokia Corporation.
- */
- var BLOCK_DIM = 3;
- var BLOCKS_PER_SIDE = 3;
- var DIM = BLOCKS_PER_SIDE * BLOCK_DIM;
- var numbers; // The main array for the numbers on the Sudoku game board
- var numbersCopy; // A working copy of the main array
- var randOrder; // An array for helping in the randomization
- var solutionFound = 0; // A helper variable for checking of the unique solution
- /* Tries to set the given number to the given index of the main array.
- * Returns 1 if it was possible, 0 otherwise. If it wasn't possible
- * this function will start the collision animations.
- */
- function setNumberByUser(index, value)
- {
- var row = Math.floor(index/DIM);
- var column = index%DIM;
- var rowCollision = testRow(index, row, value);
- var columnCollision = testColumn(index, column, value);
- var blockCollision = testBlock(index, row, column, value);
- if (numbers[index] || value)
- moves++;
- if (!rowCollision && !columnCollision && !blockCollision) {
- if (!numbers[index] && value)
- empties--;
- if (numbers[index] && !value)
- empties++;
- numbers[index] = value;
- return 1;
- }
- else {
- var indices = new Array();
- if (rowCollision)
- indices.push(rowCollision-1);
- if (columnCollision)
- indices.push(columnCollision-1);
- if (blockCollision)
- indices.push(blockCollision-1);
- startCollisionAnimations(indices);
- return 0;
- }
- }
- /* Tries to set the given number to the given index.
- * Returns 1 if it was possible, 0 otherwise.
- *
- * @param useCopy, tells whether we use the main array or a copy of it
- */
- function setNumber(index, value, useCopy)
- {
- var row = Math.floor(index/DIM);
- var column = index%DIM;
- if (!testRow(index, row, value, useCopy) &&
- !testColumn(index, column, value, useCopy) &&
- !testBlock(index, row, column, value, useCopy)) {
- if (useCopy)
- numbersCopy[index] = value;
- else
- numbers[index] = value;
- return 1;
- }
- return 0;
- }
- /*
- * Tests if there already is this number in the same row.
- * If there is, this returns the numbers index plus one and
- * 0 otherwise.
- *
- * @param useCopy, tells whether we use the main array or a copy of it
- */
- function testRow(index, row, value, useCopy)
- {
- var min = row*DIM;
- var max = row*DIM + DIM;
- for (var i = min; i < max; i++)
- if (useCopy) {
- if (numbersCopy[i])
- if (i != index && numbersCopy[i] == value)
- return i+1;
- }
- else {
- if (numbers[i])
- if (i != index && numbers[i] == value)
- return i+1;
- }
- return 0;
- }
- /*
- * Tests if there already is this number in the same column.
- * If there is, this returns the numbers index plus one and
- * 0 otherwise.
- *
- * @param useCopy, tells whether we use the main array or a copy of it
- */
- function testColumn(index, column, value, useCopy)
- {
- var max = DIM*DIM;
- for (var i = column; i <= max; i += DIM)
- if (useCopy) {
- if (numbersCopy[i])
- if (i != index && numbersCopy[i] == value)
- return i+1;
- }
- else {
- if (numbers[i])
- if (i != index && numbers[i] == value)
- return i+1;
- }
- return 0;
- }
- /*
- * Tests if there already is this number in the same block.
- * If there is, this returns the numbers index plus one and
- * 0 otherwise.
- *
- * @param useCopy, tells whether we use the main array or a copy of it
- */
- function testBlock(index, row, column, value, useCopy)
- {
- var blockRow = Math.floor(row/BLOCK_DIM);
- var blockColumn = Math.floor(column/BLOCK_DIM);
- var min = blockRow*BLOCK_DIM*DIM + blockColumn*BLOCK_DIM;
- var max = min+BLOCK_DIM;
- var idx;
- for (var x = min; x < max; x++)
- for (var y = 0; y < 3; y++) {
- idx = x + y*DIM;
- if (useCopy) {
- if (numbersCopy[idx])
- if (idx != index && numbersCopy[idx] == value)
- return idx+1;
- }
- else {
- if (numbers[idx])
- if (idx != index && numbers[idx] == value)
- return idx+1;
- }
- }
- return 0;
- }
- /*
- * Creates an array with numbers 1-9 in it, ordered randomly.
- */
- function fillRandOrder()
- {
- randOrder = new Array();
- var isSet = 0;
- var rand;
- for (var i = 0; i < DIM; i++) {
- while (!isSet) {
- rand = Math.floor(Math.random()*DIM)+1;
- for (var j = 0; j < DIM; j++)
- if (randOrder[j] && (rand == randOrder[j]))
- break;
- if (j == DIM) {
- randOrder[i] = rand;
- isSet = 1;
- }
- }
- isSet = 0;
- }
- }
- /* Generates a random full sudoku board by using recursive
- * backtracking method.
- */
- function fillCell(index)
- {
- if (index == DIM*DIM)
- return 1;
- for (var i = 0; i < 9; i++) {
- if (setNumber(index, randOrder[i], 0) && fillCell(index+1))
- return 1;
- numbers[index] = 0;
- }
- return 0;
- }
- /* Checks whether the puzzle has an unique solution.
- * Returns 0 if it does, 1 otherwise. The algorithm is mainly
- * the same as is fillCell().
- */
- function checkUniqueness(index)
- {
- if (index == DIM*DIM) {
- if (solutionFound) {
- solutionFound = 0;
- return 1;
- }
- solutionFound = 1;
- return 0;
- }
- if (numbersCopy[index]) {
- if (checkUniqueness(index+1))
- return 1;
- }
- else
- for (var i = 1; i <= 9; i++)
- if (setNumber(index, i, 1)) {
- if (checkUniqueness(index+1))
- return 1;
- numbersCopy[index] = 0;
- }
- return 0;
- }
- /* Removes numbers from the board until a desired puzzle is obtained.
- * Checks after every deletion that the puzzle still has an unique solution.
- */
- function removeCells()
- {
- var temp;
- var rand;
- while (empties < 45) {
- rand = Math.floor(Math.random()*DIM*DIM);
- temp = numbers[rand];
- if (temp) {
- numbers[rand] = 0;
- numbersCopy = numbers.slice(0);
- if (checkUniqueness(0))
- numbers[rand] = temp;
- else
- empties++;
- }
- }
- }
- /*
- * Generates a new Sudoku puzzle.
- */
- function generatePuzzle()
- {
- numbers = new Array();
- fillRandOrder();
- fillCell(0);
- empties = 0;
- removeCells();
- }
- /*
- * This enables the puzzle generating in another thread.
- */
- WorkerScript.onMessage = function(message) {
- generatePuzzle(message.rands);
- WorkerScript.sendMessage( {board: numbers, boardEmpties: empties} );
- }
|