/*
Sudoku Puzzle Javascript Frontend
(C) Copyright 2007
John Ryland <jryland@invertedlogic.com>
ALL RIGHTS RESERVED
*/
var pauseBackup = new Array;
var puzzle = new Array;
var solution = new Array;
var seed = null;
var checkCount = 0;
var startTime = 0;
var startPausedTime = 0;
var pausedTime = 0;
var updateTimerId = 0;
var lastItem = 0;
var lastVal = 0;
var facebookEnabled = false;
var paused = false;
var solved = false;
var menuShown = false;
function pageClick()
{
if (menuShown) {
document.getElementById("menuWrapper").style.display = "none";
setTimeout("menuShown = false;", 10);
}
}
function scaleToFit()
{
var dim = getViewportSize();
var ratio = dim.h / dim.w;
var s = dim.h / 1400;
if ( ratio > 1.4 )
s = dim.w / 970;
var scale = 'scale(' + s + ')';
if (ratio > 1.1) {
off = 0;//(50*s) / ratio;
} else {
off = 50;
}
scaleElement(document.getElementById("content"), scale, off);
forEach(document, '.dialogFrame', function(elem){ scaleElement(elem.children[0], scale, off); });
}
window.onorientationchange = function(event)
{
scaleToFit();
}
function totalTime()
{
return Math.round((currentMilliSecond() - startTime - pausedTime) / 1000);
}
function setIconButtonEnabled(buttonId, state)
{
var button = document.getElementById(buttonId);
if (button) {
button.className = "IconButton";
if (!state)
button.className += " disabledIconButton";
}
}
function setMenuItemEnabled(buttonId, state)
{
var button = document.getElementById(buttonId);
if (button) {
button.className = "MenuItem";
if (!state)
button.className += " disabledMenuItem";
}
}
function isButtonEnabled(buttonId)
{
var button = document.getElementById(buttonId);
if (button && hasClass(button, "disabledButton"))
return false;
return true;
}
function enableAllNumButtons()
{
for (var i = 1; i <= 9; i++) {
var button = document.getElementById('Button_' + i.toString());
button.className = "numButton";
/*
// Modify colors via JavaScript
var stopsList = button.querySelectorAll('#stop7394');
if (stopsList && stopsList.length > 0)
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#e1f1e1;stop-opacity:1;";
stopsList = button.querySelectorAll('#stop7396');
if (stopsList && stopsList.length > 0)
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#e1f1e1;stop-opacity:0;";
stopsList = button.querySelectorAll('#stop7402');
if (stopsList && stopsList.length > 0)
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#c0d0c0;stop-opacity:1;";
stopsList = button.querySelectorAll('#stop7404');
if (stopsList && stopsList.length > 0)
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#979797;stop-opacity:1;";
*/
}
}
function init()
{
if (facebookEnabled) {
FB.api("/me/achievements", "GET", {}, function (response) {
if (response && !response.error) {
alert('achievements response :' + response);
}
});
}
// newGame();
// loadGame(getUrlArgs()["type"], getUrlArgs()["difficulty"], getUrlArgs()["id"]);
}
// var json = JSON.stringify(eval("(" + data + ")"));
function loadGame(type, difficulty, id)
{
document.getElementById("newDialogWrapper").style.display = "none";
document.getElementById("inProgress").style.display = "block";
var url = "bin/sudoku.php?time=" + (new Date()).getTime() + "&";
if (type) url += "type=" + type + "&";
if (difficulty) url += "difficulty=" + difficulty + "&";
if (id) url += "id=" + id + "&";
// TODO: remove any trailing &
loadJsonAsync(url, function(okay, json) {
if (okay)
initBoard(json);
else
alert("There was a problem getting a new game. Try again later.")
});
}
function loadDailyChallenge()
{
//var d = new Date();
//d.setHours(0,0,0,0,0);
//d.getTime());
loadGame('daily');
}
function logEvent(str)
{
if (facebookEnabled)
FB.AppEvents.logEvent(str);
}
function newGame()
{
logEvent("newGame");
//loadGame('', 'hard', '');
//document.getElementById("newDialogWrapper").style.display = "block";
document.getElementById("newDialogWrapper").style.display = "block";
//setTimeout('document.getElementById("newDialogWrapper").style.display = "none"', 2000);
document.getElementById("newDialogCancel").style.display = "block";
}
function initBoard(json)
{
document.getElementById("inProgress").style.display = "none";
enableAllNumButtons();
// var lines = initRequest.responseText.split("\n");
seed = json.id;//lines[0];
var clue = json.clues;
var puz = json.solution;
for (var i = 1; i < 82; i++) {
document.getElementById(i.toString()).className = "EmptyNumber";
solution[i] = puz.charAt(i-1).toUpperCase();
puzzle[i] = clue.charAt(i-1).toUpperCase();
if ( puzzle[i] != '0' ) {
document.getElementById(i.toString()).innerHTML = puzzle[i];
// document.getElementById(i.toString()).readOnly = true;
document.getElementById(i.toString()).className = "ClueNumber";
}
}
resetGame();
lastItem = 41;
lastVal = 0;
highlightItems(41);
}
function trophies()
{
document.getElementById("leaderBoardWrapper").style.display = "block";
}
function menu()
{
if (!menuShown) {
document.getElementById("menuWrapper").style.display = "block";
setTimeout("menuShown = true;", 10);
}
}
document.addEventListener("visibilitychange", function() {
console.log(document.hidden, document.visibilityState);
doPause();
}, false);
function solveGame()
{
logEvent("solveGame");
if ( !confirm("Do you really want to see the answers?\n" +
"You will not be allowed to continue after this.\n" +
"Are you sure you want to proceed?") )
return;
for (var i = 1; i < 82; i++) {
document.getElementById(i.toString()).innerHTML = solution[i];
//
// puzzle[i] = solution[i];
//document.getElementById(i.toString()).readOnly = true;
}
setMenuItemEnabled("resetButton", false);
setIconButtonEnabled("pauseButton", false);
setIconButtonEnabled("resumeButton", false);
setMenuItemEnabled("printButton", false);
setMenuItemEnabled("checkButton", false);
setMenuItemEnabled("solveButton", false);
// document.getElementById("status").innerHTML = "TOO HARD?" +
// "<br>Answers checked " + checkCount + " time(s)." +
// "<br>Gave up after " + totalTime() + " seconds";
clearTimeout( updateTimerId );
updateTimerId = 0;
//document.getElementById("time").innerHTML = "";
highlightItems(0);
}
function doResume()
{
paused = false;
clearTimeout( updateTimerId );
updateTimerId = setTimeout( "updateTime()", 10 );
pausedTime += currentMilliSecond() - startPausedTime;
startPausedTime = 0;
//document.getElementById("pauseButton").value = "Pause";
document.getElementById("pauseButton").style.display = "block";
document.getElementById("resumeButton").style.display = "none";
for (var i = 1; i < 82; i++) {
document.getElementById(i.toString()).innerHTML = pauseBackup[i];
if ( puzzle[i] == '0' ) {
document.getElementById(i.toString()).className = "EnteredNumber";
} else {
document.getElementById(i.toString()).className = "ClueNumber";
}
}
setIconButtonEnabled("newButton", true);
setMenuItemEnabled("resetButton", true);
setMenuItemEnabled("printButton", true);
setMenuItemEnabled("checkButton", true);
setMenuItemEnabled("solveButton", true);
//document.getElementById("status").innerHTML = "";
}
function doPause()
{
if ( startPausedTime )
return;
clearTimeout( updateTimerId );
updateTimerId = 0;
paused = true;
startPausedTime = currentMilliSecond();
//document.getElementById("pauseButton").value = "Resume";
document.getElementById("pauseButton").style.display = "none";
document.getElementById("resumeButton").style.display = "block";
for (var i = 1; i < 82; i++) {
pauseBackup[i] = document.getElementById(i.toString()).innerHTML;
document.getElementById(i.toString()).innerHTML = "";
document.getElementById(i.toString()).className = "PausedNumber";
}
document.getElementById("39").innerHTML = "P";
document.getElementById("40").innerHTML = "A";
document.getElementById("41").innerHTML = "U";
document.getElementById("42").innerHTML = "S";
document.getElementById("43").innerHTML = "E";
setIconButtonEnabled("newButton", false);
setMenuItemEnabled("resetButton", false);
setMenuItemEnabled("printButton", false);
setMenuItemEnabled("checkButton", false);
setMenuItemEnabled("solveButton", false);
//document.getElementById("status").innerHTML = "PAUSED - Click resume to continue";
}
function pauseGame()
{
if ( solved )
return;
// alert("Pause not implemented");
if ( startPausedTime ) {
doResume();
} else {
doPause();
}
}
function resetGame()
{
logEvent("resetGame");
startTime = currentMilliSecond();
paused = false;
pausedTime = 0;
checkCount = 0;
lastItem = 0;
lastVal = 0;
clearTimeout( updateTimerId );
updateTimerId = setTimeout( "updateTime()", 10 );
solved = false;
for (var i = 1; i < 82; i++) {
if ( puzzle[i] == '0' ) {
document.getElementById(i.toString()).innerHTML = "";
// document.getElementById(i.toString()).readOnly = false;
document.getElementById(i.toString()).className = "EnteredNumber";
}
}
setMenuItemEnabled("resetButton", true);
setIconButtonEnabled("pauseButton", true);
setIconButtonEnabled("resumeButton", true);
setMenuItemEnabled("printButton", true);
setMenuItemEnabled("checkButton", true);
setMenuItemEnabled("solveButton", true);
//document.getElementById("status").innerHTML = "";
enableAllNumButtons();
/*
for (var i = 1; i < 82; i++)
setMenuItemEnabled(i.toString(), true);
*/
document.onkeydown = keyEventHandler;
}
function showWinScreen()
{
var min = Math.floor(totalTime() / 60);
var sec = Math.floor(totalTime() % 60);
var Sec1 = Math.floor(sec / 10);
var Sec2 = Math.floor(sec % 10);
//document.getElementById("status").innerHTML = "CONGRATULATIONS - PUZZLE SOLVED" +
// "<br>Answers checked " + checkCount + " time(s)." +
// "<br>Solved in " + totalTime() + " seconds";
//alert("\nCONGRATULATIONS - PUZZLE SOLVED" + "\n\nSolved in " + min + ":" + Sec1 + Sec2 + "\n");
document.getElementById("winScreenWrapper").style.display = "block";
document.getElementById("winScreenContents").innerHTML = "<br>Solved in " + min + ":" + Sec1 + Sec2 + "\n";
}
function updateTime()
{
clearTimeout( updateTimerId );
updateTimerId = setTimeout( "updateTime()", 1000 );
//document.getElementById("time").innerHTML = totalTime() + " seconds";
var min = Math.floor(totalTime() / 60);
var sec = Math.floor(totalTime() % 60);
var Sec1 = Math.floor(sec / 10);
var Sec2 = Math.floor(sec % 10);
document.getElementById("Timer").innerHTML = min + ":" + Sec1 + Sec2;
}
var fromClick = false;
function highlightItems(item)
{
if ( !isButtonEnabled("solveButton") || solved ) {
for (var i = 1; i < 82; i++)
if (puzzle[i] != '0')
document.getElementById(i.toString()).className = "ClueNumber";
else
document.getElementById(i.toString()).className = "EnteredNumber";
return;
}
var usedNumbers = new Array;
for (var i = 1; i <= 9; i++)
usedNumbers[i] = 0;
for (var i = 1; i < 82; i++) {
document.getElementById(i.toString()).className = "EmptyNumber";
var v = document.getElementById(i.toString()).innerHTML;
if ( v.toString() == solution[i].toString() )
usedNumbers[v]++;
if (puzzle[i] != '0')
document.getElementById(i.toString()).className = "ClueNumber";
else if (v != "" && v != " ")
document.getElementById(i.toString()).className = "EnteredNumber";
}
var val = document.getElementById(item.toString()).innerHTML;
if (!val || !fromClick)
{
for (var i = 1; i < 82; i++) {
var sameCol = (((i-1) % 9) == ((item - 1) % 9));
var sameRow = (Math.floor((i-1) / 9) == Math.floor((item - 1) / 9));
var sameSqr = (Math.floor((i-1) / 27) == Math.floor((item - 1) / 27))
&& (Math.floor(((i-1) % 9)/3) == Math.floor(((item - 1) % 9)/3));
if ( i == item )
document.getElementById(i.toString()).className = "ClueNumberFocused";
else if ( sameCol || sameRow )
document.getElementById(i.toString()).className = "ClueNumberFocusedLine";
else if ( sameSqr )
document.getElementById(i.toString()).className = "ClueNumberFocusedSquare";
}
} else {
for (var i = 1; i < 82; i++) {
if ( val && val == document.getElementById(i.toString()).innerHTML )
{
// .SameValueRowCol {
document.getElementById(i.toString()).className = "SameValue";
if ( i == item )
document.getElementById(i.toString()).className = "SameValueFocused";
}
}
}
fromClick = false;
for (var i = 1; i <= 9; i++) {
if ( usedNumbers[i] >= 9 ) {
var button = document.getElementById('Button_' + i.toString());
if (!hasClass(button, "disabledNumButton"))
button.className += " disabledNumButton";
/*
// Modify colors via JavaScript
var stopsList = button.querySelectorAll('#stop7394');
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#d1d1d1;stop-opacity:1;";
stopsList = button.querySelectorAll('#stop7396');
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#d1d1d1;stop-opacity:0;";
stopsList = button.querySelectorAll('#stop7402');
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#b0b0b0;stop-opacity:1;";
stopsList = button.querySelectorAll('#stop7404');
for (var i = 0; i < stopsList.length; i += 1)
stopsList[i].style = "stop-color:#878787;stop-opacity:1;";
*/
}
}
checkAnswers()
}
function checkAnswers()
{
if ( !isButtonEnabled("solveButton") || solved )
return;
//alert("Check not implemented");
var clues = 0;
var correct = 0;
var wrong = 0;
var empty = 0;
for (var i = 1; i < 82; i++) {
if ( puzzle[i] == '0' ) {
var val = document.getElementById(i.toString()).innerHTML;
if ( val == "" || val == " " ) {
//document.getElementById(i.toString()).className = "EnteredNumber";
empty++;
} else if ( val.toString() != solution[i].toString() ) {
document.getElementById(i.toString()).className = "WrongNumber";
var wrongVal = document.getElementById(i.toString()).innerHTML;
var wrongStr = "document.getElementById(" + i.toString() + ").innerHTML";
setTimeout("{ if (" + wrongStr + " == " + wrongVal + ") { lastVal = 0; " + wrongStr + " = ''; } }", 1250);
wrong++;
} else {
document.getElementById(i.toString()).className += " CorrectNumber";
correct++;
}
} else {
clues++;
}
}
checkCount++;
//document.getElementById("status").innerHTML = "Clues: " + clues + " Correct: " + correct +
// " Wrong: " + wrong + " Empty: " + empty +
// "<br>Answers checked " + checkCount + " time(s).";
if ( wrong == 0 && empty == 0 ) {
setIconButtonEnabled("pauseButton", false);
setIconButtonEnabled("resumeButton", false);
setMenuItemEnabled("printButton", false);
setMenuItemEnabled("checkButton", false);
setMenuItemEnabled("solveButton", false);
/* Replace {achievement-id} with the ID of your achievement. */
if (facebookEnabled) {
FB.api("/me/achievements", "POST",
{ "achievement": "956642174439599" // {solved-a-sudoku}"
}, function (response) {
if (response && !response.error) {
// Verify the achievement was published.
}
}
);
}
/*
for (var i = 1; i < 82; i++)
setMenuItemEnabled(i.toString(), false);
*/
clearTimeout( updateTimerId );
updateTimerId = 0;
//document.getElementById("time").innerHTML = "";
solved = true;
highlightItems(0);
setTimeout("showWinScreen();", 10);
}
}
function resetItem(item)
{
if ( paused == true ) {
doResume();
}
if ( !isButtonEnabled("solveButton") || solved )
return;
if ( lastItem != 0 && lastItem != "0" ) {
if ( puzzle[lastItem] == '0' && lastVal ) {
//if ( !document.getElementById(lastItem.toString()).readOnly && lastVal) {
document.getElementById(lastItem.toString()).innerHTML = lastVal;
}
}
lastItem = 0;
lastItem = item;
if ( puzzle[item] == '0' ) {
// if ( !document.getElementById(item.toString()).readOnly ) {
lastItem = item;
lastVal = document.getElementById(item).innerHTML.toString();
//document.getElementById(item).innerHTML = "";
}
//document.getElementById(item.toString()).focus();
document.getElementById(item.toString()).blur();
//document.getElementById("status").innerHTML = "";
for (var i = 1; i < 82; i++) {
if ( puzzle[i] == '0' ) {
document.getElementById(i.toString()).className = "EnteredNumber";
}
}
fromClick = true;
highlightItems(item);
}
function enterNumber(ch)
{
if ( lastItem != 0 && lastItem != "0" ) {
var oldCh = document.getElementById(lastItem.toString()).innerHTML;
var button = document.getElementById('Button_' + ch.toString());
// if ( !document.getElementById(lastItem.toString()).readOnly ) {
if ( puzzle[lastItem] == '0' // It's an editable value
&& ( ch > '0' && ch <= '9' ) // A valid number
&& (oldCh.toString() != solution[lastItem].toString()) // It's not already the correct value
&& !hasClass(button, "disabledNumButton") // The number button is enabled
) {
document.getElementById(lastItem.toString()).innerHTML = ch;
lastVal = ch;
}
if ( ( ch > '0' && ch <= '9' ) // A valid number
&& (oldCh.toString() == solution[lastItem].toString()) // It's the correct value
)
{
for (var i = 0; i < 81; i++) {
var j = i + lastItem; // find the position of the next occurance from the current
j = (j % 81) + 1;
if (document.getElementById(j.toString()).innerHTML == ch) {
lastItem = j;
lastVal = ch;
break;
}
}
//highlightItems(lastItem);
resetItem(lastItem);
} else {
highlightItems(lastItem);
setTimeout("resetItem(lastItem);", 500);
}
//document.getElementById(lastItem.toString()).focus();
}
}
function keyEventHandler(event)
{
var k;
if (window.event)
k = window.event.keyCode;
else if (event)
k = event.which;
if (!event)
event = window.event;
target = event.target ? event.target : event.srcElement;
if (lastItem) {
//if (target) {
// k = event.keyCode;
ch = String.fromCharCode(k);
// i = parseInt(target.id);
i = lastItem;
if ( i == NaN || i < 1 || i > 81)
return false;
if ( !document.getElementById(i.toString()) )
return false;
//if ( puzzle[i] == '0' ) {
// if ( !document.getElementById(i.toString()).readOnly ) {
if ( k == 8 || ch <= ' ' )
document.getElementById(i.toString()).innerHTML = "";
if ( ch > '0' && ch <= '9' ) {
//document.getElementById(i.toString()).innerHTML = "";
//document.getElementById(i.toString()).innerHTML= ch;
lastItem = i;
enterNumber(ch);
return;
//lastVal = ch;
//highlightItems(i);
}
//}
if ( k < 37 || k > 40 )
return false;
if ((k == 37 && (i % 9) == 1) || (k == 38 && (i - 9) <= 0))
return false;
if ((k == 39 && (i % 9) == 0) || (k == 40 && (i + 9) > 81))
return false;
if ( puzzle[i] == '0' )
document.getElementById(i.toString()).className = "EnteredNumber";
else
document.getElementById(i.toString()).className = "ClueNumber";
var prevI = i;
if ( k == 37 ) i--; // Left
if ( k == 38 ) i -= 9; // Up
if ( k == 39 ) i++; // Right
if ( k == 40 ) i += 9; // Down
//document.getElementById(i.toString()).focus();
if (i != prevI)
fromClick = true;
if ( lastItem != 0 && lastItem != "0" ) {
if ( puzzle[lastItem] == '0' && lastVal ) {
// if ( !document.getElementById(lastItem.toString()).readOnly && lastVal) {
document.getElementById(lastItem.toString()).innerHTML = lastVal;
}
}
//lastItem = 0;
lastItem = i;
lastVal = document.getElementById(i.toString()).innerHTML;
if ( puzzle[i] == '0' )
document.getElementById(i.toString()).className = "EnteredNumberFocused";
else
document.getElementById(i.toString()).className = "ClueNumberFocused";
highlightItems(i);
}
return false;
}