//sudoku.alanlai.net
function Board(){
this.cells=new Array();
for(var i=0;i<81;++i)
this.cells[i]=0;
}
function CopyBoard(dest,src){
for(var i=0;i<81;++i)
dest.cells[i]=src.cells[i];
}
function CountConstraints(val){
var cc=0;
for(var i=1;i<=9;++i)
if(((1<<i)&val)!=0)++cc;
return cc;
}
function MostConstrained(){
var max=-1,maxp=-1;
for(var i=0;i<81;++i){
if((this.cells[i]&1)==0){
v=CountConstraints(this.cells[i]);
if(v>=max){
max=v;
maxp=i;
}}}
return maxp;
}
Board.prototype.mostConstrained=MostConstrained;
function AllOptions(val){
var cc=new Array;
var n=0;
for(var i=1;i<=9;++i)
if(((1<<i)&val)==0)cc[n++]=i;
return cc;
}
function SetValue(pos,val){
var x=pos%9;
var y=Math.floor(pos/9);
var x0=Math.floor(x/3)*3;
var y0=Math.floor(y/3)*3;
var add=(1<<val);
for(var k=0;k<9;++k){
this.cells[x+k*9]|=add;
this.cells[k+y*9]|=add;
this.cells[x0+(k%3)+9*(y0+Math.floor(k/3))]|=add;}
this.cells[pos]=1023-(1<<val);
}
Board.prototype.setValue=SetValue;
function CellText(d){
if(d&1){
for(var i=1;i<=9;++i)
if((d|(1<<i))==1023)return ""+i;
return "_";
}else{
return "?"+AllOptions(d);
}}
function AsHTML(){
var ans="";
for(var y=0;y<9;++y){
ans=ans+"<tr>"
for(var x=0;x<9;++x){
ans=ans+"<td class='box' style='FONT:24px bold' width=30 height=30><div id='C"+(x+y*9)+"' style='background:#3399ff'>"+CellText(this.cells[x+y*9])+"</div><\/td>";
}
ans=ans+"<\/tr>";
}
return "<table class=root-table>"+ans+"<\/table>"
}
Board.prototype.asHTML=AsHTML;
function IsOK(){
for(var i=0;i<81;++i){
if((this.cells[i]&1022)==1022){
return false;
}}
return true;
}
function IsSolved(){
for(var i=0;i<81;++i){
if((this.cells[i]&1)==0)return false;
}
return true;
}
Board.prototype.isSolved=IsSolved;
Board.prototype.isOK=IsOK;
var theOne=new Board();
var numSol;
function SearchSolutions(){
while(this.isOK()){
if(this.isSolved()){
if(1<++numSol)return this;
CopyBoard(theOne,this);return null;}
var p=this.mostConstrained();
if(p<0)return null;
var l=AllOptions(this.cells[p]);
if(l.length<1)return null;
for(var i=1;i<l.length;++i){
var nb=new Board();
CopyBoard(nb,this);
nb.setValue(p,l[i]);
nb=nb.searchSolutions();
if(nb)return nb;}
this.setValue(p,l[0]);}
return null;
}
Board.prototype.searchSolutions=SearchSolutions;
function DrawInput(){
var ans="";
for(var y=0;y<9;++y){
ans=ans+"<tr>"
for(var x=0;x<9;++x){
ans=ans+"<td class='box' width=30 height=30><input size=1 type=text id='C"+(x+y*9)+"'><\/td>";
}
ans=ans+"<\/tr>"
}
document.write("<form name=f><table class=root-table>"+ans+"<\/table></form>");
}
function solve_click(){
var theSec=new Board();
if(navigator.appName=="Netscape")
var language=navigator.language;
else
var language=navigator.browserLanguage;
var code=language.substring(0,2);
numSol=0;
for(var i=0;i<81;++i){
var v=document.getElementById("C"+i).value
if(v>="1"&&v<="9")theSec.setValue(i,parseInt(v));}
var rsp=theSec.searchSolutions();
var ans;
if(numSol==0){
if(code=="zh")ans="<p><center>没有答案<\/center><\/p>";
else if(code=="ko")ans="<p><center>해답이 없다<\/center><\/p>";
else if(code=="ja")ans="<p><center>解答がない<\/center><\/p>";
else if(code=="es")ans="<p><center>Ninguna solución<\/center><\/p>";
else if(code=="ru")ans="<p><center>Никакое решение<\/center><\/p>";
else if(code=="pt")ans="<p><center>Nenhuma solução<\/center><\/p>";
else if(code=="de")ans="<p><center>Keine Lösung<\/center><\/p>";
else if(code=="fr")ans="<p><center>Aucune solution<\/center><\/p>";
else ans="<p><center>No solution<\/center><\/p>";
}
if(numSol==1){
if(code=="zh")ans="<p><center>有效的數獨 - 獨一無二之解决案 !<\/center><\/p>"+theOne.asHTML();
else if(code=="ko")ans="<p><center>유효한 수독 - 유일무이의 해결책 !<\/center><\/p>"+theOne.asHTML();
else if(code=="ja")ans="<p><center>有効な数独 - 唯一無二の解決策 !<\/center><\/p>"+theOne.asHTML();
else if(code=="es")ans="<p><center>Sudoku válido - Uno y sólo una solución !<\/center><\/p>"+theOne.asHTML();
else if(code=="ru")ans="<p><center>Действительный Sudoku - Один и только одно решение !<\/center><\/p>"+theOne.asHTML();
else if(code=="pt")ans="<p><center>Sudoku válido - Um e solução de único !<\/center><\/p>"+theOne.asHTML();
else if(code=="de")ans="<p><center>Gültig Sudoku - Ein und nur eine Lösung !<\/center><\/p>"+theOne.asHTML();
else if(code=="fr")ans="<p><center>Sudoku valide - une et seulement une solution !<\/center><\/p>"+theOne.asHTML();
else ans="<p><center>Valid Sudoku - One and only one solution !<\/center><\/p>"+theOne.asHTML();
}
if(numSol==2){
if(code=="zh")ans="<p><center>無效的數獨 - 有多個答案 !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="ko")ans="<p><center>무효의 수독 - 다수의 해답이 있다 !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="ja")ans="<p><center>無効の数独 - 多数の解答がある !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="es")ans="<p><center>Sudoku inválido - Más de una solución !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="ru")ans="<p><center>Инвалид Садоку - больше чем одно решение !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="pt")ans="<p><center>Sudoku de inválido - mais de uma solução !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="de")ans="<p><center>Ungültig Sudoku - Mehr als eine Lösung !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else if(code=="fr")ans="<p><center>Sudoku inadmissible - plus d'une solution !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
else ans="<p><center>Invalid Sudoku - More than one solution !<\/center><\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
}
document.getElementById("answer").innerHTML=ans;
}