var w,h,g,my={};function sudokuMain(){my.version='0.562';w=360;h=454 my.bdSzs=[9] my.levels=[{name:'Beginner',type:"easy",blankN:19},{name:'Medium',type:"medium",blankN:28},{name:'Challenging',type:"hard",blankN:37},{name:'Hard',type:"very-hard",blankN:46},{name:'Tough',type:"insane",blankN:55},{name:'Brutal',type:"inhuman",blankN:64},] my.bdStyles=[{name:'simple',checkQ:false},{name:'fancy',checkQ:false}] my.bdStyle=my.bdStyles[1];my.activeQ=false var s='';s+=arrowBoxHTML() s+='' my.sndHome=(document.domain=='localhost')?'/mathsisfun/images/sounds/':'/images/sounds/' s+='';s+='';s+='';my.snds=[];s+='
';s+='
' s+='
' s+='' s+='' s+='' s+='' my.soundQ=true s+=' ' s+=soundBtnHTML() s+='
' s+='' s+='' s+='
' s+='
' s+='
?
' s+='';s+='
';s+='';s+=optPopHTML();s+='';s+='
© 2019 MathsIsFun.com v'+my.version+'
';s+='
';document.write(s);var el=document.getElementById('canvas1');var ratio=3;el.width=w*ratio;el.height=h*ratio;el.style.width=w+"px";el.style.height=h+"px";g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0);my.clrs=[["Blue",'#0000FF'],["Red",'#FF0000'],["Black",'#000000'],["Green",'#00cc00'],["Orange",'#FFA500'],["Slate Blue",'#6A5ACD'],["Lime",'#00FF00'],["Spring Green",'#00FF7F'],["Teal",'#008080'],["Gold",'#ffd700'],["Med Purple",'#aa00aa'],["Light Blue",'#ADD8E6'],["Navy",'#000080'],["Purple",'#800080'],["Dark SeaGreen",'#8FBC8F']];my.clrNum=0;my.game=new Sudoku() my.hintQ=false my.clrNumQ=false my.bd=[] optPop()} function gameNew(){my.bdSz=9 bdMake() document.getElementById('ansBox').style.visibility='hidden';my.hist=[] var levelStr=document.querySelector('input[name="level"]:checked').value my.level=my.levels[0] for(var i=0;i=1&&val<=9){tile.val=val tile.origQ=true}}} bdCandUpdate() bdDraw() my.activeQ=true msg('New game')} function bdCandUpdate(){for(var i=0;i<9;i++){for(var j=0;j<9;j++){var tile=my.bd[i][j] var cands=[1,2,3,4,5,6,7,8,9] if(tile.val==''){for(var k=0;k<9;k++){var index=cands.indexOf(parseInt(my.bd[i][k].val)) if(index>-1)cands.splice(index,1)} for(var k=0;k<9;k++){var index=cands.indexOf(parseInt(my.bd[k][j].val)) if(index>-1)cands.splice(index,1)} var iStt=parseInt(i/3)*3 var jStt=parseInt(j/3)*3 for(var k=iStt;k-1)cands.splice(index,1)}} var was=tile.cands.join() tile.cands=cands if(was!=cands.join()){tile.draw()}}}}} function gameSolve(){var bdStr='' for(var i=0;i<9;i++){for(var j=0;j<9;j++){var tile=my.bd[i][j] if(tile.origQ){bdStr+=tile.val}else{bdStr+='.'}}} var soln=my.game.solve(bdStr) console.log('gameSolve',bdStr) console.log('gameSolve',soln) console.log('gameSolve',gameSolvable()) var bdStr=soln var n=0 for(var i=0;i<9;i++){for(var j=0;j<9;j++){var val=bdStr.charAt(n++) var tile=my.bd[i][j] if(val>=1&&val<=9){tile.val=val tile.draw()}}} msg('Solution') my.activeQ=false} function gameSolvable(){var bdStr=bdString(my.bd,false) var soln=my.game.solve(bdStr) return(!!soln)} function gameWinCheck(){var bdStr=bdString(my.bd,false) var n=0 for(var i=0;i=1&&c<=9){}else{n++}} if(n<5){msg(n+' left to go')}else{msg('')} if(n==0){if(gameSolvable()){msg('You win!','gold') soundPlay('sndWin')}else{msg('(not solved)','red')}}} function gameSolveCheck(){msg(gameSolvable()?'Solvable':'Not Solvable')} function gameReset(){for(var i=0;i<9;i++){for(var j=0;j<9;j++){var tile=my.bd[i][j] if(!tile.origQ){tile.val='' tile.draw()}}} msg('Reset') my.activeQ=true} function gameUndo(){if(!my.activeQ)return var step=my.hist.pop() if(step){var tile=my.bd[step.xn][step.yn] tile.valSet(step.was,false)} gameWinCheck() bdCandUpdate()} function msg(s,clr){clr=typeof clr!=='undefined'?clr:'black' var div=document.getElementById('msg') div.innerHTML=s div.style.color=clr} function bdMake(){my.border=1 my.boxWd=Math.min(70,(Math.min(w-my.border*5,h-90))/my.bdSz) my.borderTp=75 my.borderLt=(w-my.bdSz*my.boxWd)/2+my.border var myNode=document.getElementById("board");while(myNode.firstChild){myNode.removeChild(myNode.firstChild);} my.bd=[] for(var xn=0;xn';for(var j=0;j<3;j++){var id=me.xn+'-'+me.yn+'-'+anss[n];s+='
';var ans=anss[n] if(ans=='-')ans=' ' s+=ans s+='
';n++;} s+='';} div.innerHTML=s;} function getChoices(xn,yn){var keys=[1,2,3,4,5,6,7,8,9];var choices=candFill(xn,yn) for(var i=0;i<9;i++){if(choices.indexOf(keys[i])==-1){keys[i]='-'}} return keys} function bdString(bd,origQ){var s='' for(var i=0;i<9;i++){for(var j=0;j<9;j++){var val=bd[i][j].val if(origQ&&!bd[i][j].origQ){val='.'}else{if(val>=1&&val<=9){}else{val='.'}} s+=val}} return s} function candFill(xn,yn){var starttime=performance.now() var alpha='ABCDEFGHI' var id=alpha.charAt(xn)+(yn+1) var bdStr=bdString(my.bd) my.cands=my.game._get_candidates_map(bdStr);console.log('my.cands',id,my.cands[id],my.cands) var elapsed=performance.now()-starttime;console.log('Cand elapsed time: '+elapsed+'ms');return my.cands[id]} function doAns(me){var ids=me.id.split('-');var xn=ids[0] var yn=ids[1] var tile=my.bd[xn][yn] var div=document.getElementById('ansBox') div.style.visibility='hidden';var val=ids[2] if(val>=1&&val<=9)tile.valSet(val) if(val=='')tile.valSet(val) gameWinCheck() bdCandUpdate()} function radioHTML(prompt,id,lbls,func){var s='';s+='
';s+=prompt;s+='
';s+='
';for(var i=0;i';s+='';} s+='
';return s;} function optPopHTML(){var s='';s+='
';s+='
';s+=radioHTML('Level:','level',my.levels,'');s+='
' s+='
';s+='' s+='' s+='
' s+='
';s+='New game? ' s+='';s+=' ' s+='';s+='
';s+='
';return s;} function optPop(){var pop=document.getElementById('optpop');pop.style.transitionDuration="0.3s";pop.style.opacity=1;pop.style.zIndex=12;pop.style.left=(w-340)/2+'px';} function optYes(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.zIndex=1;pop.style.left='-999px';gameNew()} function optNo(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.zIndex=1;pop.style.left='-999px';} function soundBtnHTML(){var onClr='blue' var offClr='#bbb' var s='' s+='' s+='
' return s} function hintToggle(){my.hintQ=!my.hintQ;toggleBtn("hintBtn",my.hintQ);bdDraw()} function clrNumToggle(){my.clrNumQ=!my.clrNumQ;toggleBtn("clrNumBtn",my.clrNumQ);bdDraw()} function toggleBtn(btn,onq){if(onq){document.getElementById(btn).classList.add("hi");document.getElementById(btn).classList.remove("lo");}else{document.getElementById(btn).classList.add("lo");document.getElementById(btn).classList.remove("hi");}} function soundPlay(name,simulQ){if(!my.soundQ)return simulQ=typeof simulQ!=='undefined'?simulQ:true if(simulQ){if(name.length>0){var div=document.getElementById(name) if(div.currentTime>0&&div.currentTime0)soundPlayQueue();};} function soundToggle(){var btn='sound' if(my.soundQ){my.soundQ=false document.getElementById(btn).classList.add("mute")}else{my.soundQ=true document.getElementById(btn).classList.remove("mute")}} function Timer(g,rad,secs,clr,funcEnd){this.g=g;this.rad=rad;this.secs=secs;this.clr=clr;this.funcEnd=funcEnd;this.x=rad;this.y=rad;this.stt=performance.now();this.stopQ=false;} Timer.prototype.update=function(){};Timer.prototype.restart=function(secs){this.secs=secs;this.stt=performance.now();this.stopQ=false;requestAnimationFrame(this.draw.bind(this));};Timer.prototype.more=function(secs){this.stt+=secs*1000;};Timer.prototype.stop=function(){this.stopQ=true;};Timer.prototype.draw=function(){if(this.stopQ)return;var now=performance.now();var elapsed=now-this.stt;var ratio=Math.min(1,elapsed/this.secs/1000);var g=this.g;g.beginPath();g.fillStyle="#def";g.arc(this.x,this.y,this.rad,0,2*Math.PI);g.fill();g.beginPath();g.moveTo(this.x,this.y);g.fillStyle=this.clr;g.arc(this.x,this.y,this.rad,-Math.PI/2,ratio*2*Math.PI-Math.PI/2);g.fill();if(ratio<1){requestAnimationFrame(this.draw.bind(this));}else{this.funcEnd();}};function Tile(wd,ht,xn,yn){this.wd=wd this.ht=ht this.xn=xn this.yn=yn this.bgClr='#fef' this.fgClr='black' this.val='' this.origQ=false this.cands=[] var div=document.createElement("div");div.style.width=wd+'px' div.style.height=ht+'px' div.style.position='absolute' div.style.left=boxLeft(xn)+'px' div.style.top=boxTop(yn)+'px' this.div=div var me=this div.addEventListener('mouseover',function(){if(!my.activeQ)return}) div.addEventListener('mouseleave',function(){if(!my.activeQ)return}) div.addEventListener('click',function(){if(!my.activeQ)return showOpts(me)}) var can=document.createElement('canvas');can.style.position="absolute";can.style.top='0px' can.style.left='0px' can.style.width='100%' can.style.height='100%' can.width=wd can.height=ht this.g=can.getContext("2d");div.appendChild(can) document.getElementById('board').appendChild(div);this.draw()} Tile.prototype.valSet=function(v,histQ){histQ=typeof histQ!=='undefined'?histQ:true var was=this.val if(v>=1&&v<=9){this.val=parseInt(v) soundPlay('sndPlace')}else{this.val='' soundPlay('sndClear')} this.origQ=false if(histQ)my.hist.push({xn:this.xn,yn:this.yn,was:was}) this.draw()} Tile.prototype.draw=function(){var fgClr=this.origQ?'black':'orange' if(this.val>=1&&this.val<=9){this.drawNum(this.val,fgClr)}else{this.drawHints('#444')}} Tile.prototype.drawHints=function(clr){var g=this.g g.clearRect(0,0,this.wd,this.ht) if(my.hintQ){for(var i=0;i=difficulty&&this._strip_dups(single_candidates).length>=8){var board="";var givens_idxs=[];for(var i in this.SQUARES){var square=this.SQUARES[i];if(candidates[square].length==1){board+=candidates[square];givens_idxs.push(i);}else{board+=this.BLANK_CHAR;}} var nr_givens=givens_idxs.length;if(nr_givens>difficulty){givens_idxs=this._shuffle(givens_idxs);for(var i=0;imax_nr_candidates){max_nr_candidates=nr_candidates;max_candidates_square=square;}} if(max_nr_candidates===1){return candidates;} var min_nr_candidates=10;var min_candidates_square=null;for(si in this.SQUARES){var square=this.SQUARES[si];var nr_candidates=candidates[square].length;if(nr_candidates1){min_nr_candidates=nr_candidates;min_candidates_square=square;}} var min_candidates=candidates[min_candidates_square];if(!reverse){for(var vi in min_candidates){var val=min_candidates[vi];var candidates_copy=JSON.parse(JSON.stringify(candidates));var candidates_next=this._search(this._assign(candidates_copy,min_candidates_square,val));if(candidates_next){return candidates_next;}}}else{for(var vi=min_candidates.length-1;vi>=0;--vi){var val=min_candidates[vi];var candidates_copy=JSON.parse(JSON.stringify(candidates));var candidates_next=this._search(this._assign(candidates_copy,min_candidates_square,val),reverse);if(candidates_next){return candidates_next;}}} return false;};Sudoku.prototype._assign=function(candidates,square,val){var other_vals=candidates[square].replace(val,"");for(var ovi in other_vals){var other_val=other_vals[ovi];var candidates_next=this._eliminate(candidates,square,other_val);if(!candidates_next){return false;}} return candidates;};Sudoku.prototype._eliminate=function(candidates,square,val){if(!this._in(val,candidates[square])){return candidates;} candidates[square]=candidates[square].replace(val,'');var nr_candidates=candidates[square].length;if(nr_candidates===1){var target_val=candidates[square];for(var pi in this.SQUARE_PEERS_MAP[square]){var peer=this.SQUARE_PEERS_MAP[square][pi];var candidates_new=this._eliminate(candidates,peer,target_val);if(!candidates_new){return false;}}} if(nr_candidates===0){return false;} for(var ui in this.SQUARE_UNITS_MAP[square]){var unit=this.SQUARE_UNITS_MAP[square][ui];var val_places=[];for(var si in unit){var unit_square=unit[si];if(this._in(val,candidates[unit_square])){val_places.push(unit_square);}} if(val_places.length===0){return false;}else if(val_places.length===1){var candidates_new=this._assign(candidates,val_places[0],val);if(!candidates_new){return false;}}} return candidates;};Sudoku.prototype._get_square_vals_map=function(board){var squares_vals_map={};if(board.length!=this.SQUARES.length){throw "Board/squares length mismatch.";}else{for(var i in this.SQUARES){squares_vals_map[this.SQUARES[i]]=board[i];}} return squares_vals_map;};Sudoku.prototype._get_square_units_map=function(squares,units){var square_unit_map={};for(var si in squares){var cur_square=squares[si];var cur_square_units=[];for(var ui in units){var cur_unit=units[ui];if(cur_unit.indexOf(cur_square)!==-1){cur_square_units.push(cur_unit);}} square_unit_map[cur_square]=cur_square_units;} return square_unit_map;};Sudoku.prototype._get_square_peers_map=function(squares,units_map){var square_peers_map={};for(var si in squares){var cur_square=squares[si];var cur_square_units=units_map[cur_square];var cur_square_peers=[];for(var sui in cur_square_units){var cur_unit=cur_square_units[sui];for(var ui in cur_unit){var cur_unit_square=cur_unit[ui];if(cur_square_peers.indexOf(cur_unit_square)===-1&&cur_unit_square!==cur_square){cur_square_peers.push(cur_unit_square);}}} square_peers_map[cur_square]=cur_square_peers;} return square_peers_map;};Sudoku.prototype._get_all_units=function(rows,cols){var units=[];for(var ri in rows){units.push(this._cross(rows[ri],cols));} for(var ci in cols){units.push(this._cross(rows,cols[ci]));} var row_squares=["ABC","DEF","GHI"];var col_squares=["123","456","789"];for(var rsi in row_squares){for(var csi in col_squares){units.push(this._cross(row_squares[rsi],col_squares[csi]));}} return units;};Sudoku.prototype.board_string_to_grid=function(board_string){var rows=[];var cur_row=[];for(var i in board_string){cur_row.push(board_string[i]);if(i%9==8){rows.push(cur_row);cur_row=[];}} return rows;};Sudoku.prototype.board_grid_to_string=function(board_grid){var board_string="";for(var r=0;r<9;++r){for(var c=0;c<9;++c){board_string+=board_grid[r][c];}} return board_string;};Sudoku.prototype.print_board=function(board){var report=this.validate_board(board);if(report!==true){throw report;} var V_PADDING=" ";var H_PADDING='\n';var V_BOX_PADDING=" ";var H_BOX_PADDING='\n';var display_string="";for(var i in board){var square=board[i];display_string+=square+V_PADDING;if(i%3===2){display_string+=V_BOX_PADDING;} if(i%9===8){display_string+=H_PADDING;} if(i%27===26){display_string+=H_BOX_PADDING;}} console.log(display_string);};Sudoku.prototype.validate_board=function(board){if(!board){return "Empty board";} if(board.length!==this.NR_SQUARES){return "Invalid board size. Board must be exactly "+this.NR_SQUARES+" squares.";} for(var i in board){if(!this._in(board[i],this.DIGITS)&&board[i]!==this.BLANK_CHAR){return "Invalid board character encountered at index "+i+ ": "+board[i];}} return true;};Sudoku.prototype._cross=function(a,b){var result=[];for(var ai in a){for(var bi in b){result.push(a[ai]+b[bi]);}} return result;};Sudoku.prototype._in=function(v,seq){return seq.indexOf(v)!==-1;};Sudoku.prototype._first_true=function(seq){for(var i in seq){if(seq[i]){return seq[i];}} return false;};Sudoku.prototype._shuffle=function(seq){var shuffled=[];for(var i=0;i(seq.length-1)?0:(ti+1);} shuffled[ti]=seq[i];} return shuffled;};Sudoku.prototype._rand_range=function(max,min){min=min||0;if(max){return Math.floor(Math.random()*(max-min))+min;}else{throw "Range undefined";}};Sudoku.prototype._strip_dups=function(seq){var seq_set=[];var dup_map={};for(var i in seq){var e=seq[i];if(!dup_map[e]){seq_set.push(e);dup_map[e]=true;}} return seq_set;};Sudoku.prototype._force_range=function(nr,max,min){min=min||0 nr=nr||0 if(nrmax){return max;} return nr} function emptyCellCoordinatesGen(puzz){var emptyCells=[];for(var i=0;i<9;i++){for(var j=0;j<9;j++){if(puzz[i][j]===0) emptyCells.push([i,j]);}} return emptyCells;} function emptyPuzzleGenerator(){var emptyPuzz=[];for(var i=0;i<9;i++){emptyPuzz[i]=[];for(var j=0;j<9;j++){emptyPuzz[i][j]=0;}} return emptyPuzz;} var stdSolveArray=[1,2,3,4,5,6,7,8,9];function shuffleArray(arr){arr=arr.slice();var randomArray=[];var arrLength=arr.length;while(randomArray.length0&&n-1;} function inCol(num,colIndex){var col=[];puzz.forEach(function(row){col.push(row[colIndex]);});return col.indexOf(num)>-1;} function inBox(num,rowIndex,colIndex){var boxTopLeftCoordinates=[[0,0],[0,3],[0,6],[3,0],[3,3],[3,6],[6,0],[6,3],[6,6]];var correspondingBox=boxTopLeftCoordinates.filter(function(box){return(rowIndex>=box[0]&&rowIndex=box[1]&&colIndex-1;} function isValid(num,rowIndex,colIndex){return!inRow(num,rowIndex,colIndex)&&!inCol(num,colIndex)&&!inBox(num,rowIndex,colIndex);} var i=0 var steps=0 var emptyCell=emptyCellCoordinatesGen(puzz) var n while(i1000000) return false;if(randomize) solveArray=shuffleArray(stdSolveArray);if(puzz[emptyCell[i][0]][emptyCell[i][1]]===0) n=0;else n=solveArray.indexOf(puzz[emptyCell[i][0]][emptyCell[i][1]])+1;while(!isValid(solveArray[n],emptyCell[i][0],emptyCell[i][1])&&n<=solveArray.length-1){n++;} if(n==solveArray.length){puzz[emptyCell[i][0]][emptyCell[i][1]]=0;i--;if(i==-1) return false;continue;} puzz[emptyCell[i][0]][emptyCell[i][1]]=solveArray[n];i++;} return puzz;} function sudoku(puzz){var solveArray=[1,2,3,4,5,6,7,8,9];return solve(false,solveArray,puzz);}