window.onerror = function(){return true};
/** /// Constants /// */
var SUDOKU_SCRIPT = "/script/getsudoku.php"; // where to get sudokus??
var SUDOKU_PREFIX = "_sudoku"; // div id prefix
var DEFAULT_RATING = "easy"; // default rating
var WAIT_INTERVAL = 100; // time to wait for mutex in microseconds
/** COLORS */
var FIELD_SIZE = 24; // number fields will be FIELD_SIZE x FIELD_SIZE pixels
var FIELD_COLOR = "#f0f0f0"; // background color of fields without hints
var FIELD_COLOR_FOCUS = "#cccccc";
var FIELD_COLOR_HINTS = "#9bd5e6"; // background color of fields with hints
var FIELD_COLOR_HINTS_FOCUS = "#adc0f0";
var FIELD_COLOR_ERROR = "#ff9999"; // background color of fields in errorzone
var FIELD_COLOR_ERROR_FOCUS = "#e87474";
var FIELD_COLOR_ERROR_LOCKED = "#ff0000"; // background color of locked fields in errorzone
var FIELD_COLOR_ERROR_LOCKED_FOCUS = "#ea0000";
var FONT_SIZE = 17; // font size in fields
var SECTION_SIZE = 4; // space between sections (3x3)
var LOADING_TIMEOUT = 10000; // how long to wait before asuming timeout
var LOADING_CODE = // code to display when loading sudoku
'
loading..
';
var ERROR_CODE = // code to display when an error occures
'
Your browser is too old for this sudoku game :( Please upgrade your browser and come back.
';
var ERROR_DB =
'
we are currently updating the sudoku database.. please check back later :)
';
var RATING_EASY = 'Easy';
var RATING_MEDIUM = 'Medium';
var RATING_HARD = 'Hard';
var RATING_EVIL = 'Evil';
var ERROR_X = 0;
var ERROR_Y = 1;
var ERROR_B = 2;
// MOVEMENT
var KEY_UP = 38;
var KEY_DOWN = 40;
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
/** /// Globals /// */
var hasBoard = false;
var boardHTML = "";
var isDownloading = false;
var sudokuId = "";
var sudokuString = "";
var sudokuSolved = "";
var sudokuRating = "";
var sudokuPerm = "";
var sudokuBoard = new Array(9);
var sudokuLocked = new Array(9);
var sudokuBlock = new Array(9);
var sudokuError = new Array(3); // does the row, column or block contain an error?
var ajaxLoading = false;
var CURRENT_X = -1;
var CURRENT_Y = -1;
/** /// Convenient Functions /// */
function CurrencyFormatted(amount)
{
var i = parseInt(amount);
t = ''+amount;
output = (t.substr(t.length-3));
i = Math.floor(i/1000);
while(i > 1000) {
t = ''+i;
output = (t.substr(t.length-3)) + '.' + output;
i = Math.floor(i/1000);
}
if (i > 0) {
output = i + '.' + output;
}
return output;
}
function getElement(id)
{
return document.getElementById(id);
}
function setElement(id, str)
{
getElement(id).innerHTML = str;
}
function setValue(id, val)
{
getElement(id).value = val;
}
function checkLock(elem)
{
var v = elem.id;
var x = v.charAt(7);
var y = v.charAt(8);
if (sudokuLocked[x][y])
{
elem.blur();
}
}
/** extern */
function openwindow()
{
window.open("http://sudokus2go.com/showsudoku.php?id=" + sudokuId, "_sudoku");
}
function printsudoku()
{
window.open("http://sudokus2go.com/printsudoku.php?id=" + sudokuId, "_printsudoku");
}
/** check for sudoku logic */
function checkLogic(checkx, checky)
{
/** check x */
var solved = true;
var error = false;
var numbers = new Array(9);
for (var x = 0; x < 10; x++)
{
numbers[x] = false;
}
for (var x = 0; x < 9; x++)
{
var n = sudokuBoard[x][checky];
if (n > 0)
{
if (numbers[n])
{
error = true;
break;
}
numbers[n] = true;
if (!(sudokuError[ERROR_B][ sudokuBlock[x][checky] ] ||
sudokuError[ERROR_Y][ x ]))
{
if (sudokuLocked[x][checky])
{
getElement(SUDOKU_PREFIX + x + checky).style.background = FIELD_COLOR_HINTS;
}
else
{
getElement(SUDOKU_PREFIX + x + checky).style.background = FIELD_COLOR;
}
}
}
else
{
solved = false;
if (!sudokuError[ERROR_B][ sudokuBlock[x][checky] ] &&
!sudokuError[ERROR_Y][ x ])
{
getElement(SUDOKU_PREFIX + x + checky).style.background = FIELD_COLOR;
}
}
}
sudokuError[ERROR_X][checky] = error;
if (error)
{
solved = false;
for (var x = 0; x < 9; x++)
{
if (sudokuLocked[x][checky])
{
getElement(SUDOKU_PREFIX + x + checky).style.background = FIELD_COLOR_ERROR_LOCKED;
}
else
{
getElement(SUDOKU_PREFIX + x + checky).style.background = FIELD_COLOR_ERROR;
}
}
}
/** check y */
error = false;
for (var y = 0; y < 10; y++)
{
numbers[y] = false;
}
for (var y = 0; y < 9; y++)
{
var n = sudokuBoard[checkx][y];
if (n > 0)
{
if (numbers[n])
{
error = true;
break;
}
numbers[n] = true;
if (!(sudokuError[ERROR_B][ sudokuBlock[checkx][y] ] ||
sudokuError[ERROR_X][ y ]))
{
if (sudokuLocked[checkx][y])
{
getElement(SUDOKU_PREFIX + checkx + y).style.background = FIELD_COLOR_HINTS;
}
else
{
getElement(SUDOKU_PREFIX + checkx + y).style.background = FIELD_COLOR;
}
}
}
else
{
solved = false;
if (!(sudokuError[ERROR_B][ sudokuBlock[checkx][y] ] ||
sudokuError[ERROR_X][ y ]))
{
getElement(SUDOKU_PREFIX + checkx + y).style.background = FIELD_COLOR;
}
}
}
sudokuError[ERROR_Y][checkx] = error;
if (error)
{
solved = false;
for (var y = 0; y < 9; y++)
{
if (sudokuLocked[checkx][y])
{
getElement(SUDOKU_PREFIX + checkx + y).style.background = FIELD_COLOR_ERROR_LOCKED;
}
else
{
getElement(SUDOKU_PREFIX + checkx + y).style.background = FIELD_COLOR_ERROR;
}
}
}
/** check block */
error = false;
var blockx = Math.floor(checkx / 3) * 3;
var blocky = Math.floor(checky / 3) * 3;
var breaking = false;
for (var y = 0; y < 10; y++)
{
numbers[y] = false;
}
for (var y = 0; y < 3; y++)
{
var thisy = blocky + y;
for (var x = 0; x < 3; x++)
{
var thisx = blockx + x;
var n = sudokuBoard[thisx][thisy];
if (n > 0)
{
if (numbers[n])
{
error = true;
breaking = true;
break;
}
numbers[n] = true;
if (!(sudokuError[ERROR_X][ thisy ] ||
sudokuError[ERROR_Y][ thisx ]))
{
if (sudokuLocked[thisx][thisy])
{
getElement(SUDOKU_PREFIX + thisx + thisy).style.background = FIELD_COLOR_HINTS;
}
else
{
getElement(SUDOKU_PREFIX + thisx + thisy).style.background = FIELD_COLOR;
}
}
}
else
{
solved = false;
if (!(sudokuError[ERROR_X][ thisy ] ||
sudokuError[ERROR_Y][ thisx ]))
{
getElement(SUDOKU_PREFIX + thisx + thisy).style.background = FIELD_COLOR;
}
}
}
if (breaking)
{
break;
}
}
var blockn = sudokuBlock[blockx][blocky];
sudokuError[ERROR_B][blockn] = error;
if (error)
{
solved = false;
for (var y = 0; y < 3; y++)
{
var thisy = blocky + y;
for (var x = 0; x < 3; x++)
{
var thisx = blockx + x;
if (sudokuLocked[thisx][thisy])
{
getElement(SUDOKU_PREFIX + thisx + thisy).style.background = FIELD_COLOR_ERROR_LOCKED;
}
else
{
getElement(SUDOKU_PREFIX + thisx + thisy).style.background = FIELD_COLOR_ERROR;
}
}
}
}
if (solved) {
var really_solved = true;
for(var x = 0; x < 9; x++) {
for(var y = 0; y < 9; y++) {
if(sudokuBoard[x][y] == 0) {
really_solved = false;
break;
}
}
}
if(really_solved) {
alert('Congratulations! You solved the Sudoku! :)');
}
}
}
/** /// Sudoku Functions /// */
/** get sudoku */
function loadSudokuRandomExt(rating, symmetric)
{
if (rating == null)
{
rating = DEFAULT_RATING;
}
if (symmetric == null)
{
symmetric = (Math.random() * 2 < 1) ? "true" : "false";
}
sudokuRating = rating;
setElement("sudokuBoard", LOADING_CODE);
sudokuId = "";
sudokuString = "";
sudokuSolved = "";
ajaxLoading = true;
downloadSudoku(null, rating, symmetric, loadSudokuRandomExtCallback);
}
function loadSudokuById(sid)
{
if (sid == null)
{
sid = 0;
}
setElement("sudokuBoard", LOADING_CODE);
sudokuId = "";
sudokuString = "";
sudokuSolved = "";
ajaxLoading = true;
downloadSudoku(sid, null, null, loadSudokuRandomExtCallback);
}
function loadSudokuRandom()
{
loadSudokuRandomExt(null, null);
}
function loadSudokuRandomExtCallback(responseText)
{
if (responseText)
{
ajaxLoading = false;
sudokuString = responseText.substring(0,81);
sudokuSolved = responseText.substring(81);
sudokuPerm = responseText.substring(162,171);
sudokuId = responseText.substring(171);
setElement("sudokuLink", "open sudoku #"+CurrencyFormatted(sudokuId)+" in a new window");
if (!parseSudoku())
{
getElement("sudokuBoard").innerHTML = ERROR_DB;
return false;
}
showSudoku(false);
if (getElement("rating"))
{
switch(sudokuRating)
{
case "easy":
getElement("rating").innerHTML = RATING_EASY;
break;
case "medium":
getElement("rating").innerHTML = RATING_MEDIUM;
break;
case "hard":
getElement("rating").innerHTML = RATING_HARD;
break;
case "evil":
getElement("rating").innerHTML = RATING_EVIL;
break;
}
}
}
else
{
ajaxLoading = false;
setElement("sudokuBoard", ERROR_CODE);
}
}
/** download sudoku */
function downloadSudoku(sid, rating, symmetric, callback)
{
isDownloading = true;
if (sid == null)
{
sudokuString = xml_request(SUDOKU_SCRIPT + "?rating=" + rating + "&symmetric=" + symmetric, callback);
}
else
{
sudokuString = xml_request(SUDOKU_SCRIPT + "?id=" + sid, callback);
}
isDownloading = false;
}
/** convert sudoku string to array */
function parseSudoku(isResetting)
{
var sudokuSolvedPerm = "";
var i = 0;
var zero = "0".charCodeAt(0);
for (var y = 0; y < 9; y++)
{
for (var x = 0; x < 9; x++)
{
var c = sudokuString.charCodeAt(i) - zero;
if (c < 10 && c > 0)
{
sudokuBoard[x][y] = sudokuPerm.charAt(c-1);
sudokuSolvedPerm += sudokuPerm.charAt(c-1);
}
else if(c == 0)
{
sudokuBoard[x][y] = 0;
var sc = sudokuSolved.charCodeAt(i) - zero;
sudokuSolvedPerm += sudokuPerm[sc-1];
}
else
{
return false;
}
++i;
}
}
sudokuSolved = isResetting ? sudokuSolved : sudokuSolvedPerm;
return true;
}
/** generate HTML code for sudoku */
function showSudoku(isResetting)
{
/** check if html code for sudokuBoard has already been generated */
if (hasBoard)
{
setElement("sudokuBoard", boardHTML);
for (var y = 0; y < 9; y++)
{
for (var x = 0; x < 9; x++)
{
if(sudokuBoard[x][y] > 0)
{
var elem = getElement(SUDOKU_PREFIX + x + y);
elem.value = sudokuBoard[x][y];
elem.style.background = FIELD_COLOR_HINTS;
sudokuLocked[x][y] = true;
}
else
{
var elem = getElement(SUDOKU_PREFIX + x + y);
elem.value = "";
elem.style.background = FIELD_COLOR;
sudokuLocked[x][y] = false;
}
}
}
boardHTML = getElement("sudokuBoard").innerHTML;
getElement(SUDOKU_PREFIX + "44").focus();
}
else
{
var FORMAT = "border: 1px solid #000000; text-align: center; font-size: " + FONT_SIZE + "px; width: " + FIELD_SIZE + "px; height: " + FIELD_SIZE + "px;";
var PREFIX = '
';
var TDSPACE = '
';
var html = '
';
for (var y = 0; y < 9; y++)
{
/** space */
if (y % 3 == 0 && y != 0)
{
html = html + TRSPACE;
}
html = html + '
';
for (var x = 0; x < 9; x++)
{
if (x % 3 == 0 && x != 0)
{
html = html + TDSPACE;
}
if (sudokuBoard[x][y] > 0)
{
html = html + PREFIX + x + y
+ MIDDLE + sudokuBoard[x][y]
+ STYLE0
+ SUFFIX;
sudokuLocked[x][y] = true;
}
else
{
html = html + PREFIX + x + y
+ MIDDLE
+ STYLE1
+ SUFFIX;
sudokuLocked[x][y] = false;
}
}
html = html + '
';
}
html = html + '
';
boardHTML = html;
setElement("sudokuBoard", html);
hasBoard = true;
}
}
/** hint */
/** hint */
function getHint()
{
var sx = 0;
var sy = 0;
if (CURRENT_X != -1 && CURRENT_Y != -1 && sudokuBoard[CURRENT_X][CURRENT_Y] == 0) {
sx = CURRENT_X;
sy = CURRENT_Y;
} else {
sx = Math.floor(Math.random()*9);
sy = Math.floor(Math.random()*9);
}
var x;
var y;
if (sudokuBoard[sx][sy] > 0)
{
x = (sx == 8) ? 0 : sx + 1;
y = (sy == 8) ? 0 : sy + 1;
while (x != sx || y != sy)
{
if (sudokuBoard[x][y] == 0) {
break;
}
x++;
if (x == 9) {
x = 0;
y = (y == 8) ? 0 : y + 1;
}
}
}
else
{
x = sx;
y = sy;
}
if (sudokuBoard[x][y] == 0)
{
var n = sudokuSolved.charAt(x*1 + y*9);
sudokuBoard[x][y] = n;
getElement(SUDOKU_PREFIX + x + y).value = n;
checkLogic(x, y);
}
}
/** reset */
function reset()
{
var agree = confirm("Reset Sudoku??");
if (agree)
{
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 9; j++)
{
sudokuError[i][j] = false;
}
}
parseSudoku();
showSudoku(true);
}
}
/** /// EVENTS /// */
function _focus(elem)
{
var v = elem.id;
var checkx = v.charAt(7);
var checky = v.charAt(8);
CURRENT_X = parseInt(checkx);
CURRENT_Y = parseInt(checky);
var error = sudokuError[ERROR_X][ checky ] ||
sudokuError[ERROR_Y][ checkx ] ||
sudokuError[ERROR_B][ sudokuBlock[checkx][checky] ];
if (sudokuLocked[checkx][checky])
{
getElement(v).style.background =
(error) ? FIELD_COLOR_ERROR_LOCKED_FOCUS : FIELD_COLOR_HINTS_FOCUS;
}
else
{
getElement(v).style.background =
(error) ? FIELD_COLOR_ERROR_FOCUS : FIELD_COLOR_FOCUS;
}
return true;
}
function _blur(elem)
{
var v = elem.id;
var checkx = v.charAt(7);
var checky = v.charAt(8);
var error = sudokuError[ERROR_X][ checky ] ||
sudokuError[ERROR_Y][ checkx ] ||
sudokuError[ERROR_B][ sudokuBlock[checkx][checky] ];
if (sudokuLocked[checkx][checky])
{
getElement(v).style.background =
(error) ? FIELD_COLOR_ERROR_LOCKED : FIELD_COLOR_HINTS;
}
else
{
getElement(v).style.background =
(error) ? FIELD_COLOR_ERROR : FIELD_COLOR;
}
return true;
}
function _keydown(event, elem)
{
var v = elem.id;
var checkx = v.charAt(7);
var checky = v.charAt(8);
var n = event.keyCode ? event.keyCode : event.charCode; //sudokuBoard[checkx][checky];
if (n >= 49 && n <= 57)
{
if (!sudokuLocked[checkx][checky])
{
var v = n - 48;
sudokuBoard[checkx][checky] = v;
checkLogic(checkx, checky);
elem.value = v;
}
getElement(SUDOKU_PREFIX + checkx + checky).blur();
getElement(SUDOKU_PREFIX + checkx + checky).focus();
return false;
}
else if (n >= 97 && n <= 105)
{
if (!sudokuLocked[checkx][checky])
{
var v = n - 96;
sudokuBoard[checkx][checky] = v;
checkLogic(checkx, checky);
elem.value = v;
}
getElement(SUDOKU_PREFIX + checkx + checky).blur();
getElement(SUDOKU_PREFIX + checkx + checky).focus();
return false;
}
else if (n >= KEY_LEFT && n <= KEY_DOWN)
{
switch (n)
{
case KEY_UP:
checky = (checky > 0) ? checky - 1 : 8;
break;
case KEY_DOWN:
checky = (checky < 8) ? checky - 0 + 1 : 0;
break;
case KEY_LEFT:
checkx = (checkx > 0) ? checkx - 1 : 8;
break;
case KEY_RIGHT:
checkx = (checkx < 8) ? checkx - 0 + 1 : 0;
break;
}
getElement(SUDOKU_PREFIX + checkx + checky).blur();
getElement(SUDOKU_PREFIX + checkx + checky).focus();
return false;
}
else if (n == 48 || n == 96 || n == 32 || n == 13 || n == 8 || n == 46 || n == 12)
{
if (!sudokuLocked[checkx][checky])
{
sudokuBoard[checkx][checky] = 0;
checkLogic(checkx, checky);
elem.value = "";
elem.focus();
}
getElement(SUDOKU_PREFIX + checkx + checky).blur();
getElement(SUDOKU_PREFIX + checkx + checky).focus();
return false;
}
else
{
getElement(SUDOKU_PREFIX + checkx + checky).blur();
elem.focus();
return false;
}
}
/** /// INIT /// */
for (var i = 0; i < 9; i++)
{
sudokuBoard[i] = new Array(9);
sudokuLocked[i] = new Array(9);
sudokuBlock[i] = new Array(9);
for (var j = 0; j < 9; j++)
{
sudokuBlock[i][j] = Math.floor(i / 3) + Math.floor(j / 3) * 3;
}
}
for (var i = 0; i < 3; i++)
{
sudokuError[i] = new Array(9);
for (var j = 0; j < 9; j++)
{
sudokuError[i][j] = false;
}
}