// Append ?raw to the URL of this page to view the raw source (for 
// comments, copyright & licence), or ?pretty for a colorized version.

if(registerDOMConverter){registerDOMConverter("Object.domNode",function(obj){return!!obj.domNode&&obj.domNode.nodeType>0;},function(obj){return obj.domNode;});}
var SBaseBoard=[[1,4,7,2,5,8,3,6,9],[2,5,8,3,6,9,4,7,1],[3,6,9,4,7,1,5,8,2],[4,7,1,5,8,2,6,9,3],[5,8,2,6,9,3,7,1,4],[6,9,3,7,1,4,8,2,5],[7,1,4,8,2,5,9,3,6],[8,2,5,9,3,6,1,4,7],[9,3,6,1,4,7,2,5,8]];var SSwaps=[[0,1],[1,2],[0,2],[3,4],[4,5],[3,5],[6,7],[7,8],[6,8]];var SSecs=[[[[0,0],[0,1],[0,2]],[[1,0],[1,1],[1,2]],[[2,0],[2,1],[2,2]]],[[[0,3],[0,4],[0,5]],[[1,3],[1,4],[1,5]],[[2,3],[2,4],[2,5]]],[[[0,6],[0,7],[0,8]],[[1,6],[1,7],[1,8]],[[2,6],[2,7],[2,8]]],[[[3,0],[3,1],[3,2]],[[4,0],[4,1],[4,2]],[[5,0],[5,1],[5,2]]],[[[3,3],[3,4],[3,5]],[[4,3],[4,4],[4,5]],[[5,3],[5,4],[5,5]]],[[[3,6],[3,7],[3,8]],[[4,6],[4,7],[4,8]],[[5,6],[5,7],[5,8]]],[[[6,0],[6,1],[6,2]],[[7,0],[7,1],[7,2]],[[8,0],[8,1],[8,2]]],[[[6,3],[6,4],[6,5]],[[7,3],[7,4],[7,5]],[[8,3],[8,4],[8,5]]],[[[6,6],[6,7],[6,8]],[[7,6],[7,7],[7,8]],[[8,6],[8,7],[8,8]]]];var Random={bool:function(){return!(Math.random()>.5);},integer:function(max,min){min=min||0;return min+Math.floor((Math.random()-.00001)*(max-min));},choice:function(lst){return lst[Math.floor((Math.random()-.00001)*lst.length)];},intArray:function(length,max,min){var lst=[];while(lst.length<length){lst.push(Random.integer(max,min));}
return lst;}};var SBoardUtils={copy:function(lst,copyTo){var newArray=copyTo||[];for(var i=0;i<9;i++){newArray[i]=lst[i].concat();}
return newArray;},shuffle:function(board,times){log("shuffle()",times,board);while(times>0){if(Random.bool()){SBoardUtils.swapColumns(board,Random.choice(SSwaps));}else{SBoardUtils.swapRows(board,Random.choice(SSwaps));}
times--;}},swapRows:function(board,indices){log("Swap rows:",indices);var v1=board[indices[0]],v2=board[indices[1]];board[indices[1]]=v1;board[indices[0]]=v2;},swapColumns:function(board,indices){log("Swap columns:",indices);var vs1=[],vs2=[];for(var y=0;y<9;y++){vs1[y]=board[y][indices[0]];vs2[y]=board[y][indices[1]];}
for(var y=0;y<9;y++){board[y][indices[0]]=vs2[y];board[y][indices[1]]=vs1[y];}},removeRandom:function(board,howMany){while(howMany>0){coords=Random.intArray(2,9,0);if(board[coords[0]][coords[1]]!==null){board[coords[0]][coords[1]]=null;howMany--;}}},stringRepr:function(board,blankChar){var div='+-------+-------+-------+';blankChar=blankChar||" ";if(/[\|\d]/.test(blankChar))throw"Invalid blankChar specified: "+blankChar;return div+"\n"+map(function(inner){return"|"+map(function(i){return i||blankChar;},inner).join(" ").replace(new RegExp("([\\d"+blankChar+"] [\\d"+blankChar+"] [\\d"+blankChar+"]) ?","g"),' $1 |')},board).join("\n").replace(new RegExp("(((\\|? [\\d"+blankChar+"] ?){9} \\|\\n){3})","g"),"$1"+div+"\n")+"\n"+div;},blank:function(){return[[],[],[],[],[],[],[],[],[]];}};function SudokuBoard(removePlaces,shuffleCount){var self=this;shuffleCount=shuffleCount||100;removePlaces=(removePlaces<10)?10:(removePlaces>=81)?60:removePlaces;this.board=SBoardUtils.copy(SBaseBoard);SBoardUtils.shuffle(this.board,shuffleCount);this.fillBoard=SBoardUtils.copy(this.board);SBoardUtils.removeRandom(this.fillBoard,removePlaces);};SudokuBoard.prototype.toString=function(hide){return SBoardUtils.stringRepr(hide&&this.fillBoard||this.board);};SudokuBoard.prototype.toDisplayDom=function(hide){var self=this;var board=hide?this.fillBoard:this.board;var secs=map(function(sec){return self._renderDisplayDomSection(board,sec);},SSecs);var rows=[[secs[0],secs[1],secs[2]],[secs[3],secs[4],secs[5]],[secs[6],secs[7],secs[8]]];function render_row(cells){return TR(null,map(partial(TD,null),cells));};return TABLE({'class':'SudokuBoard SudokuPrintBoard','cellspacing':'0'},TBODY(null,map(render_row,rows)));};SudokuBoard.prototype._renderDisplayDomSection=function(boardArray,section){function render_row(cells){return TR(null,map(render_cell,cells));};function render_cell(coords){return TD(null,boardArray[coords[0]][coords[1]]||"\xA0");};return TABLE({'class':'SudokuSection','cellspacing':'0'},TBODY(null,map(render_row,section)));};function SudokuFieldset(fieldsetName,emptyPlacesDefault){this.fieldsetName=fieldsetName;this.board=null;this._boardPrefs={};this._domCacheAnswers=null;this._domCacheBlanks=null;this.fields={emptyPlaces:INPUT({'type':'text','size':'3','value':emptyPlacesDefault||40}),shuffleCount:INPUT({'type':'text','size':'3','value':100}),forceRegeneration:INPUT({'type':'checkbox','class':'checkbox','disabled':true})};this.domNode=FIELDSET(null,LEGEND(null,fieldsetName||"Board"),P({'class':'ffitem'},LABEL(null,"Empty places"),this.fields.emptyPlaces,SPAN({'class':'desc'},"1\xA0<\xA0",createDOM("var",null,"x"),"\xA0<\xA080")),P({'class':'ffitem'},LABEL(null,"Times to shuffle"),this.fields.shuffleCount,SPAN({'class':'desc'},createDOM("var",null,"x"),"\xA0>\xA01")),P({'class':'ffitem full'},LABEL({'class':'checkbox'},this.fields.forceRegeneration," Force regeneration")));};SudokuFieldset.prototype.generate=function(showAnswers){var emptyPlaces=this.fields.emptyPlaces&&parseInt(this.fields.emptyPlaces.value,10);if(!emptyPlaces||emptyPlaces===NaN||emptyPlaces<=1||emptyPlaces>=80){addElementClass(this.fields.emptyPlaces,"invalid");this.fields.emptyPlaces.focus();return false;}else{removeElementClass(this.fields.emptyPlaces,"invalid");}
var shuffleCount=this.fields.shuffleCount&&parseInt(this.fields.shuffleCount.value,10);if(!shuffleCount||shuffleCount===NaN||shuffleCount<1){addElementClass(this.fields.shuffleCount,"invalid");this.fields.shuffleCount.focus();return false;}else{removeElementClass(this.fields.shuffleCount,"invalid");}
var forceRegen=this.fields.forceRegeneration.checked;this.fields.forceRegeneration.disabled=false;if(forceRegen||!this.board||this._boardPrefs.emptyPlaces!==emptyPlaces||this._boardPrefs.shuffleCount!==shuffleCount){this.board=this[cacheKey]||new SudokuBoard(emptyPlaces,shuffleCount);this._domCacheBlanks=this._domCacheAnswers=null;}
this._boardPrefs.emptyPlaces=emptyPlaces;this._boardPrefs.shuffleCount=shuffleCount;var cacheKey=showAnswers?"_domCacheBlanks":"_domCacheAnswers";if(!this[cacheKey]){this[cacheKey]=this.board.toDisplayDom(!showAnswers);}
return this[cacheKey];};
