//// Javascript für die Erstellung eines Sudokus (inkl. Hilfsfunktionen) siehe //// http://heuscher.ch/Sudoku // Einstellungen delay = 10;//200; // in Milisekunden working = false; // ist true, wenn gerade etwas läuft sudokuRegisterUrl = "http://heuscher.ch/~twiki/Main/Heuscher/Steve/Public/WebHome/SudokuRegister/"; randomSudokuUrl = "http://heuscher.ch/~twiki/Main/Heuscher/Steve/Public/WebHome/SudokuRegister/ajaxRandomSudoku.php"; // lösungsstack, die SudokuDaten und Geschichte initialisieren solveHistory = new Array(); SudokuHistory = new Array(); emptySudoku = new Array(); singleNumber = "singleNumber"; uniqueInRow = "uniqueInRow"; uniqueInBox = "uniqueInBox"; uniqueInCol = "uniqueInCol"; // hält fest, ob eine Taste gedrückt ist keyDown = false; // keyboard events registieren function onKeyDown(event) { setKeyStatus(event, false) } document.onkeydown = onKeyDown; function onKeyUp(event) { setKeyStatus(event, true) } document.onkeyup = onKeyUp; function setKeyStatus(event, keyUp) { keyDown = !keyUp; } // sudoku daten füllen for (var Zeile = 0; Zeile < 9; Zeile++) { emptySudoku[Zeile] = new Array(); for (var Zelle = 0; Zelle < 9; Zelle++) { emptySudoku[Zeile][Zelle] = new Array(); for (var Zahl = 0; Zahl < 9; Zahl++) { emptySudoku[Zeile][Zelle][Zahl] = Zahl + 1; } } } SudokuDaten = deepCopyArray(emptySudoku); // vergleicht arrays aufgrund ihres inhalts Array.prototype.compareArrays = function(arr) { if (this.length != arr.length) return false; for (var i = 0; i < arr.length; i++) { if (this[i] != null && this[i].compareArrays) { //likely nested array if (!this[i].compareArrays(arr[i])) return false; else continue; } if (this[i] != arr[i]) return false; } return true; } // kopiert rekursiv arrays function deepCopyArray(arrayToCopy) { if ( arrayToCopy == null ) { //alert ("deepCopyArray mit null aufgerufen"); return null; } var copyArray= new Array(); for(var i = 0; i < arrayToCopy.length; i++) { copyArray[i] = arrayToCopy[i]; //if (i==0) alert( typeof copyArray[i]); if (typeof arrayToCopy[i] == typeof arrayToCopy) { copyArray[i] = deepCopyArray(copyArray[i]); } } return copyArray; } // führt das model nach und updatet die view function setNumber(x,y,number, sudokuStatus, showHints, updateViewAfterCalculation) { //alert('Setting node ' + y +', '+ x + ' to value:' + number ); if (typeof number != 'number' && number.match(/[1-9]/) == null) { //alert("bitte eine Zahl eingeben; number:" + number +", typeof number:"+typeof number); return; } SudokuHistory[SudokuHistory.length] = deepCopyArray(SudokuDaten); setNumberInData(x,y,number, SudokuDaten); if (updateViewAfterCalculation != null && updateViewAfterCalculation) { updateView(sudokuStatus, showHints); } } function setNumberInData(x,y,number, data) { for(var i = 0; i < 9; i++) { data[i][x][number-1] = null; data[y][i][number-1] = null; data[Math.floor(y /3) * 3 + i % 3][Math.floor(x /3) * 3 + Math.floor(i / 3)][number-1] = null; } // resultat setzen data[y][x] = new Array(); data[y][x][number-1] = number; data[y][x][9] = number; } // führt das model nach und updatet die view function clearNumber(x,y,number) { //alert('Setting node ' + y +', '+ x + ' to value:' + number ); if (typeof number != 'number' && number.match(/[1-9]/) == null) { //alert("bitte eine Zahl eingeben; number:" + number +", typeof number:"+typeof number); return; } SudokuHistory[SudokuHistory.length] = deepCopyArray(SudokuDaten); SudokuDaten[y][x][number-1] = null; updateView(); } // updatet die view nach dem jetztigen Model function updateView(uniqueNumbersFound, showHints) { for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var table1to9 = document.getElementById("t" + i + '' + j); var parent = table1to9.parentNode; var filledNumber = parent.getElementsByTagName("span")[0]; var filledNumberText = filledNumber.firstChild; // alert('i:' + i + '; j:' + j + '; table:' + table1to9); var tdNodes = table1to9.getElementsByTagName("td"); var numberOfNumbers = 0; filledNumberText.data = " "; table1to9.style.zIndex = 1; filledNumber.style.zIndex = -1; parent.style.background = "#FFF"; for(var k = 0; k < tdNodes.length; k++) { tdNodes[k].style.background = "transparent"; numberLinkText = tdNodes[k].firstChild.firstChild; if (SudokuDaten[i][j][9] == null) { if (SudokuDaten[i][j][k] != null) { numberOfNumbers++; numberLinkText.data = SudokuDaten[i][j][k]; } else { numberLinkText.data = " "; } } else { numberOfNumbers = 1; numberLinkText.data = " "; } } if (numberOfNumbers == 0) { parent.style.background = "#F88"; return; } if (!(SudokuDaten[i][j][9] == null)) { filledNumberText.data = SudokuDaten[i][j][9]; parent.style.background = "#FFF"; table1to9.style.background = "#FFF"; table1to9.style.zIndex = -1; //filledNumber.style.background = "#FFF"; filledNumber.style.zIndex = 1; } } } if (uniqueNumbersFound != null) { if (uniqueNumbersFound != null) { for (var i = 0; i < uniqueNumbersFound.length; i++) { var numberFound = uniqueNumbersFound[i]; var table1to9 = document.getElementById("t" + numberFound[1] + '' + numberFound[0]); var parent = table1to9.parentNode; var tdNodes = table1to9.getElementsByTagName("td"); if (showHints != null) { tdNodes[numberFound[2] - 1].style.background = "#2F2"; parent.style.background = "#9F9"; } } } } updateDisplayedStatus(); } function updateDisplayedStatus() { var webroot = location.href; var search = location.search; var sudokuNumber = getSudokuNumber(SudokuDaten); if(search != null) { webroot = webroot.substr(0, webroot.indexOf("?")); } var permalink = document.getElementById("permalinkSudoku"); if (permalink != null) { var permalinkHref = webroot + '?source=permalink&sudoku=' + escape(sudokuNumber) + "#sudoku"; permalink.setAttribute("href", permalinkHref); } var statusField = document.getElementById('status'); if (statusField != null) { statusField.value = sudokuNumber; } var difficultyField = document.getElementById('remainingDifficulty'); if (difficultyField != null && document.getElementById('getDifficulty') != null) { var justNumbers = sudokuNumber.replace(/[^0-9]/g, "0"); setTimeout("if (working == false) document.getElementById('remainingDifficulty').firstChild.data = (new Board().solve(15,'"+justNumbers+"')) + '';", delay); } } // macht in der history einen schritt zurück und zeigt den stand an. function goBack () { if (SudokuHistory.length == 0) { return; } SudokuDaten = SudokuHistory[SudokuHistory.length -1]; updateView(); SudokuHistory.length = SudokuHistory.length -1 ; } // setzt das sudoku auf den ausgangsstand zurück function clearSudoku () { if (SudokuHistory.length == 0) { return; } SudokuHistory.length = 1 ; goBack (); } // gibt zurück, ob das sudoku legal ist (array mit eindeutigen Zahlen) // sonst null (-> in einem Feld kann keine Zahl mehr vorkommen) function getSudokuStatus (data) { if (data == null) { data = SudokuDaten; } var uniqueNumbersFound = new Array(); var numbersInRows = new Array(); var numbersInColumns = new Array(); var numbersInBlocks = new Array(); // leere arrays für löser generieren // zugriff: numbersInBlocks[0][1] = Array von Arraxys(Numberfound[x][y][nummer]), welche 1 enthalten) for(var i = 0; i < 9; i++) { numbersInRows[i] = new Array(); numbersInColumns[i] = new Array(); numbersInBlocks[i] = new Array(); for(var j = 1; j < 10; j++) { numbersInRows[i][j] = new Array(); numbersInColumns[i][j] = new Array(); numbersInBlocks[i][j] = new Array(); } } for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var numbersPresent = 0; var onlyNumber = null; for(var k = 0; k < 9; k++) { if ( data[i][j][k] != null) { numbersPresent++; onlyNumber = data[i][j][k]; if (data[i][j][9] == null) { numbersInRows[i][onlyNumber].push(new Array(j,i,onlyNumber, uniqueInRow)); numbersInColumns[j][onlyNumber].push(new Array(j,i,onlyNumber, uniqueInCol)); numbersInBlocks[Math.floor(j / 3) + 3 * Math.floor(i / 3)][onlyNumber].push(new Array(j,i,onlyNumber, uniqueInBox)); } } } // check ob der status legal ist if (numbersPresent == 0) { /*var table1to9 = document.getElementById("t" + i + '' + j); var parent = table1to9.parentNode; parent.style.background = "#F88"; //alert ("keine nummer in " + i +", "+j+" gefunden: " + data[i][j]); */ return null; } if (numbersPresent == 1 && data[i][j][9] != onlyNumber) { // alert('Nummer gefunden: '+ onlyNumber); var numberFound = new Array(j,i,onlyNumber,singleNumber); uniqueNumbersFound[uniqueNumbersFound.length] = numberFound; } } } for(var i = 0; i < 9; i++) { for(var j = 1; j < 10; j++) { if (numbersInColumns[i][j].length == 1) { //alert('Nummer '+j+' in Spalte '+i+' gefunden: '+ numbersInColumns[i][j][0]); addUniqueNumberIfNotPresent(uniqueNumbersFound, numbersInColumns[i][j][0]); } if (numbersInBlocks[i][j].length == 1) { //alert('Nummer '+j+' in Block '+i+' gefunden: '+ numbersInBlocks[i][j][0]); addUniqueNumberIfNotPresent(uniqueNumbersFound, numbersInBlocks[i][j][0]); } if (numbersInRows[i][j].length == 1) { //alert('Nummer '+j+' in Zeile '+i+' gefunden: '+ numbersInRows[i][j][0]); addUniqueNumberIfNotPresent(uniqueNumbersFound, numbersInRows[i][j][0]); } } } return uniqueNumbersFound; } function addUniqueNumberIfNotPresent(uniqueNumbersFound, newUniqueNumber) { var isDuplicate = false; for(var i = 0; !isDuplicate && i < uniqueNumbersFound.length; i++) { isDuplicate = (uniqueNumbersFound[i][0] == newUniqueNumber[0] && uniqueNumbersFound[i][1] == newUniqueNumber[1] && uniqueNumbersFound[i][2] == newUniqueNumber[2]); } if (isDuplicate) { return; } else { uniqueNumbersFound.push(newUniqueNumber); } } function backtrackPopupText() { return "Der Startpunkt führt nicht zu einer Lösung.\nIhre letzte Eingabe wird zurückgenommen."; } // löst rekursiv das sudoku // der status der rekursion wird in der variable solveHistory gehalten // wieder-aufruf durch timer function solveSudoku() { working = true; var uniqueNumbersFound = getSudokuStatus(); updateView(uniqueNumbersFound, true); if (uniqueNumbersFound == null) { goBack(); if (solveHistory.length > 0) { var lastSet = solveHistory[solveHistory.length-1]; SudokuDaten[lastSet[1]][lastSet[0]][lastSet[2]-1] = null; solveHistory.length = solveHistory.length - 1; //alert("Solution not found, backtracking. solveHistory.length: "+solveHistory.length +"; last set:" + lastSet); } else { alert(backtrackPopupText()); } setTimeout("solveSudoku()", delay); return; } var hasUniqueNumbers = false; var oldSudokuHistory = deepCopyArray(SudokuHistory); //alert("solveHistory.length: "+solveHistory.length +"; uniqueNumbersFound.length: " + uniqueNumbersFound.length); while (uniqueNumbersFound.length > 0) { hasUniqueNumbers = true; var nextNumber = uniqueNumbersFound[uniqueNumbersFound.length -1]; uniqueNumbersFound.length = uniqueNumbersFound.length -1; setNumber(nextNumber[0],nextNumber[1],nextNumber[2]); } if (hasUniqueNumbers) { // die automatisch gefundenen Zahlen gelten nicht als Eintrag in der History, sie sind // mehr die logische Fortsetzung der gesetzten Zahl, weshalb die history zurückgesetzt wird SudokuHistory = oldSudokuHistory; setTimeout("solveSudoku()", delay); return; } for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { for(var k = 0; SudokuDaten[i][j][9] == null && k < 9; k++) { if ( SudokuDaten[i][j][k] != null) { nextRecursion(new Array(j,i,k+1)); return; } } } } updateView(); working = false; } // setzt die nächste rekursion auf function nextRecursion(nextSetNumber, uniqueNumbersFound) { //alert("nextRecursion, nextSetNumber[0]: "+nextSetNumber[0]+", nextSetNumber[1]: "+nextSetNumber[1]+", nextSetNumber[2]: "+nextSetNumber[2]+", "); solveHistory[solveHistory.length] = nextSetNumber; setNumber(nextSetNumber[0],nextSetNumber[1],nextSetNumber[2], uniqueNumbersFound, true, true); setTimeout("solveSudoku()", delay); } // füllt "rekursiv" die eindeutigen Felder // wieder-aufruf durch timer function fillUniqueFields(callFromTimer) { working = true; var uniqueNumbersFound = getSudokuStatus(); if (callFromTimer == false && uniqueNumbersFound != null && uniqueNumbersFound.length > 0) { SudokuHistory[SudokuHistory.length] = deepCopyArray(SudokuDaten); oldSudokuHistory = deepCopyArray(SudokuHistory) } if (uniqueNumbersFound != null && uniqueNumbersFound.length > 0) { updateView(uniqueNumbersFound, true); while (uniqueNumbersFound.length > 0) { var nextNumber = uniqueNumbersFound[uniqueNumbersFound.length -1]; uniqueNumbersFound.length = uniqueNumbersFound.length - 1; setNumber(nextNumber[0], nextNumber[1], nextNumber[2]); } setTimeout("fillUniqueFields(true)", delay); return; } updateView(); SudokuHistory = oldSudokuHistory; working = false; } // füllt die in location.search vor-definierten oder übergebenen felder aus function fillPredefinedNumbers(definitionString) { working = true; clearSudoku(); SudokuHistory[SudokuHistory.length] = deepCopyArray(SudokuDaten); oldSudokuHistory = deepCopyArray(SudokuHistory) if (definitionString == null) { //alert("location.search : " + location.search); definitionString = unescape(location.search); definitionString = definitionString.replace(/^[^- 0-9]*(sudoku=)?/gi,""); //alert("definitionString : " + definitionString); } if (definitionString.indexOf("=") < 0) { var deletedNumbersStringArray = (definitionString).split(" "); var deletedNumbersArray = new Array(); if(deletedNumbersStringArray.length == 2) { deletedNumbersArray = deletedNumbersStringArray[1].split("-").reverse(); //alert(deletedNumbersArray); // kill first empty string ("-3-2".split("-") -> ["", "3", "2"]) deletedNumbersArray.pop(); } // set the selected numbers and gather the deleted ones (still encoded) for(var i = 0; i < 81; i++) { var x = i % 9; var y = Math.floor(i / 9); var valueCellEncoded = definitionString.substr(i, 1); if(valueCellEncoded.match(/[1-9]/) != null) { setNumberInData(x,y, valueCellEncoded, SudokuDaten); } else if(valueCellEncoded == "-") { var deletedNumbers = deletedNumbersArray.pop().split(""); //alert(deletedNumbers); for(var j = 0; j < deletedNumbers.length; j++) { removeNumberInData(x,y,deletedNumbers[j],SudokuDaten); } } } } else { if (definitionString != null && definitionString.length > 0) { for(var lastI = 0; lastI < 9; lastI++) { for(var lastJ = 0; lastJ < 9; lastJ++) { var coord = (lastJ+1)+''+(lastI+1); var coordIndex = definitionString.indexOf(coord) ; if ( coordIndex> 0) { setNumber(lastI,lastJ, definitionString.substr(coordIndex + 3, 1)); } } } } } updateView(); SudokuHistory = oldSudokuHistory; working = false; } function removeNumberInData(x,y,number,data) { if (typeof number != 'number' && number.match(/[1-9]/) == null) { return; } data[y][x][number-1] = null; } function setBackground(sudokuNumberElement) { var filledNumber = sudokuNumberElement.firstChild.nodeValue; if (filledNumber != null && filledNumber.match(/[1-9]/) != null) { if (keyDown) { sudokuNumberElement.style.background = "#F99"; } else { sudokuNumberElement.style.background = "#9F9"; } } } function clearBackground(sudokuNumberElement) { sudokuNumberElement.style.background = "transparent"; } // Background-Farben um komplexe Abhängikeiten zu markieren var colorForNumber = new Array(); colorForNumber[0] = ""; colorForNumber[1] = "#665CCC"; colorForNumber[2] = "#837CCC"; colorForNumber[3] = "#D4C91E"; colorForNumber[4] = "#A39D38"; colorForNumber[5] = "#8F870B"; colorForNumber[6] = "#EBE156"; colorForNumber[7] = "#D48D1E"; colorForNumber[8] = "#A37938"; colorForNumber[9] = "#8F5B0B"; // hier werden die tabellen erstellt // die internen tabellen stellen die möglichen Zahlen dar und sie sind über // die id tXY identifiziert document.writeln(''); for(i = 0; i < 9; i++) { document.writeln(''); for(j = 0; j < 9; j++) { document.write(''); } document.writeln(''); } document.write('
 '); document.write(''); for (var k=0; k<3; k++) { document.writeln(''); for (var l=0; l<3; l++) { // TODO font family überprüfen var number = k * 3 + l + 1; document.write(''); } document.writeln(''); } document.writeln('
'); document.write(''+ number + '
'); // Variabeln für den Background Sudoku Generator computeSudokusInBackground = true; NewSudokuDaten = SudokuDaten; NewSudokuHistory = new Array(); newSolveHistory = new Array(); lastNewSudokuFound = null; backgroundDelay = 10; maxBacktracks = 100; numberOfBacktracks = 0; lastNumberUndone = null; NewSudokuHistory[0] = deepCopyArray(SudokuDaten); // diese variabel zeigt ob die suche neu gestartet werden soll function backgroundCalculateNewSudoku(start) { if (start != null) { numberOfBacktracks = 0; lastNewSudokuFound = null; newSolveHistory.length = 0; NewSudokuHistory.length = 1; NewSudokuDaten = deepCopyArray(NewSudokuHistory[0]); //alert("Starte background sudoku kalkulation"); // minimale anzahl Zahlen in einem eindeutigen Sudoku sind 17 for (var i = 0; i < 17; i++) { setRandomNumberInNewSudoku(); } } // todo: nächste zwei Zeilen auskommentieren //SudokuDaten = NewSudokuDaten; //updateView(); setTimeout("tryForUniqueSudokuSolution()", backgroundDelay ); } function illegalNewSudokuFound() { var illegalSudokusCount = document.getElementById("illegalSudokusCount"); setTimeout("backgroundCalculateNewSudoku(true)", backgroundDelay); if (illegalSudokusCount != null) { illegalSudokusCount.firstChild.data++; } } function backtrackNewSudoku() { numberOfBacktracks++; NewSudokuDaten = deepCopyArray(NewSudokuHistory[NewSudokuHistory.length - 1]); NewSudokuHistory.length = NewSudokuHistory.length -1; lastNumberUndone = newSolveHistory[newSolveHistory.length-1]; NewSudokuDaten[lastNumberUndone[1]][lastNumberUndone[0]][lastNumberUndone[2]-1] = null; NewSudokuDaten[lastNumberUndone[1]][lastNumberUndone[0]][9] = null; newSolveHistory.length = newSolveHistory.length - 1; //alert("Solution not found, backtracking. newSolveHistory.length: "+newSolveHistory.length +"; last set:" + lastSet); var backtrackCount = document.getElementById("backtrackCount"); if (backtrackCount != null) { backtrackCount.firstChild.data = numberOfBacktracks; } } function sendSudokuSolution(callFrom) { // es gibt eine lösung, und es wurde keine zweite gefunden -> eindeutige Lösung //alert(callFrom + ": sudoku hat nur eine Lösung, sollte gespeichert werden"); var startSudoku = getSudokuNumber(NewSudokuHistory[1]); var endSudoku = getSudokuNumber(lastNewSudokuFound); var difficulty = ""; if (document.getElementById('getDifficulty') != null) { difficulty = "&difficulty=" + (new Board().solve(15,getSudokuNumber(NewSudokuHistory[1]))); } var legalSudokusCount = document.getElementById("legalSudokusCount"); if (legalSudokusCount != null) { legalSudokusCount.firstChild.data++; var generatedSudokus = document.getElementById("generatedSudokus"); if (generatedSudokus != null) { var newSudokuLink = document.createElement("a"); newSudokuLink.setAttribute("href", "#sudoku"); newSudokuLink.setAttribute("onclick", "fillPredefinedNumbers('" + startSudoku + "'); return true;"); newSudokuLink.appendChild(document.createTextNode("" + legalSudokusCount.firstChild.data)); generatedSudokus.appendChild(newSudokuLink); generatedSudokus.appendChild(document.createTextNode(" ")); } } executeRemoteJavascript( sudokuRegisterUrl +"?sudoku_start="+startSudoku+"&sudoku_solution=" + endSudoku + difficulty + "&source=xmlhttp&SudokuPageLastModified=" + document.lastModified); } function setNextFunctionAccordingToBacktrackCount() { if (numberOfBacktracks >= maxBacktracks) { setTimeout("backgroundCalculateNewSudoku(true)", backgroundDelay); } else { backtrackNewSudoku(); setTimeout("tryForUniqueSudokuSolution()", backgroundDelay); } } function tryForUniqueSudokuSolution() { if (working == true || computeSudokusInBackground == false) { setTimeout("tryForUniqueSudokuSolution()", backgroundDelay ); return; } var uniqueNumbersFound = getSudokuStatus(NewSudokuDaten); // todo: nächste zwei Zeilen auskommentieren //SudokuDaten = NewSudokuDaten; //updateView(uniqueNumbersFound, true); if (uniqueNumbersFound == null) { if (newSolveHistory.length > 0) { setNextFunctionAccordingToBacktrackCount(); return; } if (lastNewSudokuFound != null) { setTimeout("backgroundCalculateNewSudoku(true)", backgroundDelay); sendSudokuSolution("top"); return; } else { //alert("illegales sudoku"); illegalNewSudokuFound(); return; } } //alert("nächste runde"); var uniqueNumbers = false; while (uniqueNumbersFound != null && uniqueNumbersFound.length > 0) { uniqueNumbers = true; var nextNumber = uniqueNumbersFound[uniqueNumbersFound.length -1]; uniqueNumbersFound.length = uniqueNumbersFound.length -1; setNumberInData(nextNumber[0],nextNumber[1],nextNumber[2], NewSudokuDaten); } if (uniqueNumbers == true) { setTimeout("tryForUniqueSudokuSolution()", backgroundDelay); return; } for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { for(var k = 0; NewSudokuDaten[i][j][9] == null && k < 9; k++) { if ( NewSudokuDaten[i][j][k] != null) { // vor dem setzen die history speichern NewSudokuHistory.push(deepCopyArray(NewSudokuDaten)); nextSetNumber = new Array(j,i,k+1); newSolveHistory.push(nextSetNumber); // alert("setze " + nextSetNumber); setNumberInData(j,i,k+1, NewSudokuDaten); setTimeout("tryForUniqueSudokuSolution()", backgroundDelay); return; } } } } // wenn es bis hier durchläuft, ist alles gesetzt if (lastNewSudokuFound == null) { lastNumberUndone = null; lastNewSudokuFound = deepCopyArray(NewSudokuDaten); if (newSolveHistory.length == 0) { setTimeout("backgroundCalculateNewSudoku(true)", backgroundDelay); sendSudokuSolution("bottom"); return; } else { //alert("eine lösung gefunden"); setNextFunctionAccordingToBacktrackCount(); return; } } else { //alert("zwei lösungen gefunden, füge eine zahl hinzu"); // setze die letzte legale zahl um ein eindeutiges sudoku hinzukriegen var setNumber = lastNumberUndone; //alert("setze nummer für eindeutigkeit: " + setNumber); newSolveHistory.length = 0; NewSudokuDaten = deepCopyArray(NewSudokuHistory[1]); NewSudokuHistory.length = 1; lastNewSudokuFound = null; setNumberInData(setNumber[0],setNumber[1],setNumber[2], NewSudokuDaten); NewSudokuHistory.push(deepCopyArray(NewSudokuDaten)); setTimeout("tryForUniqueSudokuSolution()", backgroundDelay); return; } } function getSudokuNumber(data) { var defaultFilledSudoku = deepCopyArray(emptySudoku); for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var uniqueNumber = data[i][j][9]; if (uniqueNumber != null) { setNumberInData(j,i,uniqueNumber, defaultFilledSudoku); } } } var numbers = ""; var deletedNumbers = ""; for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var uniqueNumber = data[i][j][9]; if (uniqueNumber != null) { numbers += uniqueNumber; } else { var accumulatedDeletions = ""; for(var k = 0; k < 9; k++) { if (defaultFilledSudoku[i][j][k] != null && data[i][j][k] == null) { // wenn gelöscht, dann momentane "Lösch-Zahl" als gelöscht hinzufügen accumulatedDeletions += (k+1); } } if(accumulatedDeletions.length != 0) { numbers += "-"; deletedNumbers += "-" + accumulatedDeletions; } else { numbers += 0; } } } } if (deletedNumbers.length != 0) { numbers += " " + deletedNumbers; } return numbers; } function setRandomNumberInNewSudoku() { var number = null; var randX; var randY; var randNumber; while (number == null) { randX = Math.floor(Math.random()*9); randY = Math.floor(Math.random()*9); randNumber = Math.floor(Math.random()*9); if (NewSudokuDaten[randY][randX][randNumber] != null && NewSudokuDaten[randY][randX][9] == null) { number = NewSudokuDaten[randY][randX][randNumber]; //alert ("nummer gefunden: "+number+" in "+randY+","+randX+": "+ NewSudokuDaten[randY][randX]); } } setNumberInData(randX, randY, number, NewSudokuDaten); return new Array(randX, randY, number); } function isSudokuSolved(data) { for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { if( data[i][j][9] == null) { return false; } } } //alert ("sudoku gelöst"); return true; } // Füllen von der Nummern welche im Link übergeben wurden setTimeout("fillPredefinedNumbers()",20); // update den permalink und den status setTimeout("updateDisplayedStatus()", 1000); ///////////////////////////////////////// // Starte background sudoku kalkulation setTimeout("backgroundCalculateNewSudoku(true)", 1000); //////////////////////////////////////////////////////////////////////////// // AJAX Part //////////////////////////////////////////////////////////////////////////// function emptyHandler(){} function randomSudokuHandler() { // Make sure the request is loaded (readyState = 4) if (req && req.readyState == 4) { // Make sure the status is "OK" if (req.status == 200) { var data = req.responseXML.getElementById('sudoku').getAttribute('data'); fillPredefinedNumbers(data); } } } /** * Open a connection to the specified URL, which is * intended to respond with an XML message. * * @param string method The connection method; either "GET" or "POST". * @param string url The URL to connect to. * @param string toSend The data to send to the server; must be URL encoded. * @param function responseHandler The Javascript function handling server response. */ function xmlOpen(method, url, toSend, responseHandler) { if (window.XMLHttpRequest) { // browser has native support for XMLHttpRequest object req = new XMLHttpRequest(); } else if (window.ActiveXObject) { // try XMLHTTP ActiveX (Internet Explorer) version req = new ActiveXObject("Microsoft.XMLHTTP"); } if(req) { try { req.onreadystatechange = responseHandler; req.open(method, url, true); req.setRequestHeader("content-type","application/x-www-form-urlencoded"); req.send(toSend); } catch (e) { // fehler beim senden oder empfangen } } } // Verschiedene Utility-Funktionen, welche von Buttons und ähnlichem aufgerufen werden können function loadRandomSudoku(randomDiffuculty) { executeRemoteJavascript(randomSudokuUrl + '?' + (new Date()).getTime() + randomDiffuculty + "&javascript=true"); } // loads and executes javascript from given url function executeRemoteJavascript(url) { var script = document.createElement("script"); script.src = url; document.body.appendChild(script); } function getSudokuNumberEncoded(data) { var defaultFilledSudoku = deepCopyArray(SudokuHistory[0] != null ? SudokuHistory[0] : SudokuDaten); for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var uniqueNumber = data[i][j][9]; if (uniqueNumber != null) { setNumberInData(j,i,uniqueNumber, defaultFilledSudoku); } } } var numbers = ""; for(var i = 0; i < 9; i++) { for(var j = 0; j < 9; j++) { var uniqueNumber = data[i][j][9]; if (uniqueNumber != null) { numbers += uniqueNumber; } else { var currentDeletedNumber = 1; var accumulatedDeletions = 0; for(var k = 0; k < 9; k++) { if (defaultFilledSudoku[i][j][k] != null) { // check ob in data zusätzliche ziffern gelöscht wurden //alert("defaultFilledSudoku["+i+"]["+j+"] = " + defaultFilledSudoku[i][j]); if(data[i][j][k] == null) { // wenn ja, dann momentane "Lösch-Zahl" als gelösch hinzufügen accumulatedDeletions += currentDeletedNumber; } currentDeletedNumber *= 2; } } // wenn keine zusätzlichen Zahlen gelöscht wurden -> "0" hinzufügen if (accumulatedDeletions == 0) { numbers += "0"; } else { alert("accumulatedDeletions : "+ accumulatedDeletions + "\ndata["+i+"]["+j+"] : " + data[i][j] + "\ndefaultFilledSudoku["+i+"]["+j+"] : " + defaultFilledSudoku[i][j]); numbers += String.fromCharCode(160 + accumulatedDeletions); } } } } return numbers; }