level=[10,14,12];
minnum=1;
maxnum=6;
ver="on";
color=[0,1,2];
msglevel=['easy','hard','medium'];
msgcolor=['green','blue','red'];
n=81;
s=47;
rand=0;
var b;
td=new Array(n);

function preload()
{
pic=new Image();
pic.src="bg.jpg";
pic.onload=timeout;
}

function timeout()
{
i=0; while (i<n)
{
td[i]="";
i++;
}
message="Computing...";
show();
setTimeout("setup()", 100);
}

function setup()
{
num=new Array(n);
pos=new Array(n);
sym=[0,1,2,3,9,10,11,12,18,19,20,21,27,28,29,30,36,37,38,39,40];
pairs=[11,22,33,44,55,66,77,88,99];
randomnum=new Array(level[0]);
inp="<input type=\"text\" autocomplete=\"off\" id=\"form"+color[0]+"\" maxlength=\"1\" value=\"\" onkeyup=\"javascript:enter(";
end=");\">";
calculate();
i=0; while (i<sym.length)
{
random=Math.floor(Math.random()*(i+1));
randomnum[i]=randomnum[random];
randomnum[random]=i;
i++;
}
i=0; while (i<n) {td[i]="<input type=\"text\" maxLength=\"1\" value=\""+num[i]+"\" readonly>"; i++;}
i=0; while (i<level[0])
{
num[sym[randomnum[i]]]="";
td[sym[randomnum[i]]]=inp+sym[randomnum[i]]+end;
i++;
}
if (num[0]=="") {num[8]=""; num[80]=""; num[72]=""; td[8]=inp+8+end; td[80]=inp+80+end; td[72]=inp+72+end;}
if (num[1]=="") {num[17]=""; num[79]=""; num[63]=""; td[17]=inp+17+end; td[79]=inp+79+end; td[63]=inp+63+end;}
if (num[2]=="") {num[26]=""; num[78]=""; num[54]=""; td[26]=inp+26+end; td[78]=inp+78+end; td[54]=inp+54+end;}
if (num[3]=="") {num[35]=""; num[77]=""; num[45]=""; td[35]=inp+35+end; td[77]=inp+77+end; td[45]=inp+45+end;}
if (num[9]=="") {num[7]=""; num[71]=""; num[73]=""; td[7]=inp+7+end; td[71]=inp+71+end; td[73]=inp+73+end;}
if (num[10]=="") {num[16]=""; num[70]=""; num[64]=""; td[16]=inp+16+end; td[70]=inp+70+end; td[64]=inp+64+end;}
if (num[11]=="") {num[25]=""; num[69]=""; num[55]=""; td[25]=inp+25+end; td[69]=inp+69+end; td[55]=inp+55+end;}
if (num[12]=="") {num[34]=""; num[68]=""; num[46]=""; td[34]=inp+34+end; td[68]=inp+68+end; td[46]=inp+46+end;}
if (num[18]=="") {num[6]=""; num[62]=""; num[74]=""; td[6]=inp+6+end; td[62]=inp+62+end; td[74]=inp+74+end;}
if (num[19]=="") {num[15]=""; num[61]=""; num[65]=""; td[15]=inp+15+end; td[61]=inp+61+end; td[65]=inp+65+end;}
if (num[20]=="") {num[24]=""; num[60]=""; num[56]=""; td[24]=inp+24+end; td[60]=inp+60+end; td[56]=inp+56+end;}
if (num[21]=="") {num[33]=""; num[59]=""; num[47]=""; td[33]=inp+33+end; td[59]=inp+59+end; td[47]=inp+47+end;}
if (num[27]=="") {num[5]=""; num[53]=""; num[75]=""; td[5]=inp+5+end; td[53]=inp+53+end; td[75]=inp+75+end;}
if (num[28]=="") {num[14]=""; num[52]=""; num[66]=""; td[14]=inp+14+end; td[52]=inp+52+end; td[66]=inp+66+end;}
if (num[29]=="") {num[23]=""; num[51]=""; num[57]=""; td[23]=inp+23+end; td[51]=inp+51+end; td[57]=inp+57+end;}
if (num[30]=="") {num[32]=""; num[50]=""; num[48]=""; td[32]=inp+32+end; td[50]=inp+50+end; td[48]=inp+48+end;}
if (num[36]=="") {num[4]=""; num[44]=""; num[76]=""; td[4]=inp+4+end; td[44]=inp+44+end; td[76]=inp+76+end;}
if (num[37]=="") {num[13]=""; num[43]=""; num[67]=""; td[13]=inp+13+end; td[43]=inp+43+end; td[67]=inp+67+end;}
if (num[38]=="") {num[22]=""; num[42]=""; num[58]=""; td[22]=inp+22+end; td[42]=inp+42+end; td[58]=inp+58+end;}
if (num[39]=="") {num[31]=""; num[41]=""; num[49]=""; td[31]=inp+31+end; td[41]=inp+41+end; td[49]=inp+49+end;}
reject();
}

function enter(b)
{
a=document.forms[0].elements[b].value;
tdbegin="<input type=\"text\" autocomplete=\"off\" id=\"form"+color[0]+"\" size=\"1\" maxLength=\"1\" value=\"";
tdend="\" onkeyup=\"javascript:enter("+b+end;
if (a>0&&a<10)
{
td[b]=tdbegin+a+tdend;
num[b]=a;
message="";
verify(b);
}
else if (a=="")
{
td[b]=tdbegin+tdend;
num[b]="";
message="Clear.";
}
else
{
td[b]=tdbegin+tdend;
num[b]="";
message="Invalid entry!";
document.forms[0].elements[b].select();
}
document.getElementById("msg").firstChild.data=message;
}

function calculate()
{
i=n; do
{
i--;
if (!pos[i]>=1)
{
rand=Math.floor((Math.random()*9)+1);
num[i]=rand;
pos[i]=1;
}
else
{
num[i]++;
if (num[i]>9) num[i]=1;
pos[i]++;
}
setarray();
if (rows.find_one(pairs)||cols.find_one(pairs)||blks.find_one(pairs))
{
if (pos[i]<9) i++;
else
{
num[i]=0;
pos[i]=0;
if (pos[i-1]>8) pos[i-1]=1;
i=i+2;
}
}
}
while (i);
}

function show()
{
menu="&nbsp;<a id=\"menu\" href=\"javascript:timeout();\" title=\"Set up new Sudoku\">New<\/a><a id=\"menu\" href=\"javascript:setlevel();\" title=\"Set difficulty level\">Level: "+msglevel[0]+"<\/a><a id=\"menu\" href=\"javascript:setcolor();\" title=\"Set input color\">Color: "+msgcolor[0]+"<\/a><a id=\"menu\" href=\"javascript:setverify();\" title=\"Toggle verifying on/off\">Verify: "+ver+"<\/a><a id=\"menu\" href=\"javascript:about();\" title=\"About Sudoku online\">About<\/a><a id=\"menu\" href=\"mailto:thomas.weibel@bluewin.ch\" title=\"E-mail to the author\">Mail<\/a>&nbsp;";
display="<p id=\"title\">Sudoku<\/p><form><table><tr><td id=\"topleft\">"+td[0]+"<\/td><td id=\"top\">"+td[1]+"<\/td><td id=\"topright\">"+td[2]+"<\/td><td id=\"top\">"+td[3]+"<\/td id=\"top\"><td id=\"top\">"+td[4]+"<\/td><td id=\"topright\">"+td[5]+"<\/td><td id=\"top\">"+td[6]+"<\/td><td id=\"top\">"+td[7]+"<\/td><td id=\"topright\">"+td[8]+"<\/td><\/tr><tr><td id=\"left\">"+td[9]+"<\/td><td>"+td[10]+"<\/td><td id=\"right\">"+td[11]+"<\/td><td>"+td[12]+"<\/td><td>"+td[13]+"<\/td><td id=\"right\">"+td[14]+"<\/td><td>"+td[15]+"<\/td><td>"+td[16]+"<\/td><td id=\"right\">"+td[17]+"<\/td><\/tr><tr><td id=\"bottomleft\">"+td[18]+"<\/td><td id=\"bottom\">"+td[19]+"<\/td><td id=\"bottomright\">"+td[20]+"<\/td><td id=\"bottom\">"+td[21]+"<\/td><td id=\"bottom\">"+td[22]+"<\/td><td id=\"bottomright\">"+td[23]+"<\/td><td id=\"bottom\">"+td[24]+"<\/td><td id=\"bottom\">"+td[25]+"<\/td><td id=\"bottomright\">"+td[26]+"<\/td><\/tr><tr><td id=\"left\">"+td[27]+"<\/td><td>"+td[28]+"<\/td><td id=\"right\">"+td[29]+"<\/td><td>"+td[30]+"<\/td><td>"+td[31]+"<\/td><td id=\"right\">"+td[32]+"<\/td><td>"+td[33]+"<\/td><td>"+td[34]+"<\/td><td id=\"right\">"+td[35]+"<\/td><\/tr><tr><td id=\"left\">"+td[36]+"<\/td><td>"+td[37]+"<\/td><td id=\"right\">"+td[38]+"<\/td><td>"+td[39]+"<\/td><td>"+td[40]+"<\/td><td id=\"right\">"+td[41]+"<\/td><td>"+td[42]+"<\/td><td>"+td[43]+"<\/td><td id=\"right\">"+td[44]+"<\/td><\/tr><tr><td id=\"bottomleft\">"+td[45]+"<\/td><td id=\"bottom\">"+td[46]+"<\/td><td id=\"bottomright\">"+td[47]+"<\/td><td id=\"bottom\">"+td[48]+"<\/td><td id=\"bottom\">"+td[49]+"<\/td><td id=\"bottomright\">"+td[50]+"<\/td><td id=\"bottom\">"+td[51]+"<\/td><td id=\"bottom\">"+td[52]+"<\/td><td id=\"bottomright\">"+td[53]+"<\/td><\/tr><tr><td id=\"left\">"+td[54]+"<\/td><td>"+td[55]+"<\/td><td id=\"right\">"+td[56]+"<\/td><td>"+td[57]+"<\/td><td>"+td[58]+"<\/td><td id=\"right\">"+td[59]+"<\/td><td>"+td[60]+"<\/td><td>"+td[61]+"<\/td><td id=\"right\">"+td[62]+"<\/td><\/tr><tr><td id=\"left\">"+td[63]+"<\/td><td>"+td[64]+"<\/td><td id=\"right\">"+td[65]+"<\/td><td>"+td[66]+"<\/td><td>"+td[67]+"<\/td><td id=\"right\">"+td[68]+"<\/td><td>"+td[69]+"<\/td><td>"+td[70]+"<\/td><td id=\"right\">"+td[71]+"<\/td><\/tr><tr><td id=\"bottomleft\">"+td[72]+"<\/td><td id=\"bottom\">"+td[73]+"<\/td><td id=\"bottomright\">"+td[74]+"<\/td><td id=\"bottom\">"+td[75]+"<\/td><td id=\"bottom\">"+td[76]+"<\/td><td id=\"bottomright\">"+td[77]+"<\/td><td id=\"bottom\">"+td[78]+"<\/td><td id=\"bottom\">"+td[79]+"<\/td><td id=\"bottomright\">"+td[80]+"<\/td><\/tr><\/table><\/form><p id=\"copyright\">&copy; 2010 twb<\/p><p id=\"msg\">"+message+"<\/p><br><br><br><p>"+menu+"<\/p>";
document.getElementById("screen").innerHTML=display;
}

function setlevel()
{
level.unshift(level[level.length-1]);
msglevel.unshift(msglevel[msglevel.length-1]);
level.pop();
msglevel.pop();
timeout();
}

function setcolor(b)
{
color.unshift(color[color.length-1]);
msgcolor.unshift(msgcolor[msgcolor.length-1]);
color.pop();
msgcolor.pop();
i=0; while (i<n)
{
if(num[i]==0)
td[i]="<input type=\"text\" autocomplete=\"off\" id=\"form"+color[0]+"\" size=\"1\" maxLength=\"1\" value=\"\" onkeyup=\"javascript:enter("+i+end;
i++;
}
message="Color: "+msgcolor[0];
show();
}

function setverify ()
{
if (ver=="on")
{
ver="off";
message="Verify: "+ver;
}
else
{
ver="on";
verify(0);
}
show();
}

function setarray()
{
rows=[
[num[0],num[1],num[2],num[3],num[4],num[5],num[6],num[7],num[8]],
[num[9],num[10],num[11],num[12],num[13],num[14],num[15],num[16],num[17]],
[num[18],num[19],num[20],num[21],num[22],num[23],num[24],num[25],num[26]],
[num[27],num[28],num[29],num[30],num[31],num[32],num[33],num[34],num[35]],
[num[36],num[37],num[38],num[39],num[40],num[41],num[42],num[43],num[44]],
[num[45],num[46],num[47],num[48],num[49],num[50],num[51],num[52],num[53]],
[num[54],num[55],num[56],num[57],num[58],num[59],num[60],num[61],num[62]],
[num[63],num[64],num[65],num[66],num[67],num[68],num[69],num[70],num[71]],
[num[72],num[73],num[74],num[75],num[76],num[77],num[78],num[79],num[80]]
];
cols=[
[num[0],num[9],num[18],num[27],num[36],num[45],num[54],num[63],num[72]],
[num[1],num[10],num[19],num[28],num[37],num[46],num[55],num[64],num[73]],
[num[2],num[11],num[20],num[29],num[38],num[47],num[56],num[65],num[74]],
[num[3],num[12],num[21],num[30],num[39],num[48],num[57],num[66],num[75]],
[num[4],num[13],num[22],num[31],num[40],num[49],num[58],num[67],num[76]],
[num[5],num[14],num[23],num[32],num[41],num[50],num[59],num[68],num[77]],
[num[6],num[15],num[24],num[33],num[42],num[51],num[60],num[69],num[78]],
[num[7],num[16],num[25],num[34],num[43],num[52],num[61],num[70],num[79]],
[num[8],num[17],num[26],num[35],num[44],num[53],num[62],num[71],num[80]]
];
blks=[
[num[0],num[1],num[2],num[9],num[10],num[11],num[18],num[19],num[20]],
[num[3],num[4],num[5],num[12],num[13],num[14],num[21],num[22],num[23]],
[num[6],num[7],num[8],num[15],num[16],num[17],num[24],num[25],num[26]],
[num[27],num[28],num[29],num[36],num[37],num[38],num[45],num[46],num[47]],
[num[30],num[31],num[32],num[39],num[40],num[41],num[48],num[49],num[50]],
[num[33],num[34],num[35],num[42],num[43],num[44],num[51],num[52],num[53]],
[num[54],num[55],num[56],num[63],num[64],num[65],num[72],num[73],num[74]],
[num[57],num[58],num[59],num[66],num[67],num[68],num[75],num[76],num[77]],
[num[60],num[61],num[62],num[69],num[70],num[71],num[78],num[79],num[80]]
];
}

Array.prototype.has_joins=function()
{
if (!this.joins)
{
this.joins=[];
var i=0; while (i<this.length)
{
this.joins[i]=this[i].sort().join('');
i++
}
}
};

Array.prototype.find_one=function(el)
{
this.has_joins();
var i=0; while (i<el.length)
{
var j=0; while (j<this.length)
{
if (this.joins[j].indexOf(el[i])>-1) return true;
j++;
}
i++;
}
return false;
};

Array.prototype.min_max=function(min,max)
{
this.has_joins();
var i=0; while (i<this.length)
{
if (this.joins[i].length>max||this.joins[i].length<min) return true;
i++;
}
return false;
};

function reject()
{
setarray();
if (rows.min_max(minnum,maxnum)||cols.min_max(minnum,maxnum)||blks.min_max(minnum,maxnum))
{
setup();
}
else
{
message="Level: "+msglevel[0];
show();
}
}

function verify(b)
{
setarray();
test=num.join();
if (ver=="on")
{
if (rows.find_one(pairs)||cols.find_one(pairs)||blks.find_one(pairs))
{
message="Invalid!";
document.forms[0].elements[b].select();
}
else if (test.indexOf(",,")==-1) message="Congratulations: Sudoku solved!";
else message="Ok.";
}
else message="Ok.";
}

function about()
{
message="Sudoku 2.2 by www.thomasweibel.ch";
document.getElementById("msg").firstChild.data=message;
}
