/* Browser Identification - (c) 2008, Jan Wolter - all rights reserved */
var browserEngine, browserVersion, browserVersionString, browserOS;
function browserType(test)
{
var ua= (test || navigator.userAgent).toLowerCase();
var m;
if (ua.search(/windows/) >= 0)
browserOS= 'Win';
else if (ua.search(/macintosh/) >= 0)
browserOS= 'Mac';
else if (ua.search(/(linux|x11)/) >= 0)
browserOS= 'Unix';
else if (ua.search(/win/) >= 0)
browserOS= 'Win';
else if (ua.search(/mac/) >= 0)
browserOS= 'Mac';
else if (ua.search(/(bsd|sunos|unix)/) >= 0)
browserOS= 'Unix';
else
browserOS= 'Unknown';
if (m= ua.match(/applewebkit\/([0-9.]+)/))
browserEngine= 'WebKit';
else if ((m= ua.match(/khtml\/([0-9.]+)/)) ||
(m= ua.match(/konqueror\/([0-9.]+)/)))
browserEngine= 'KHTML';
else if (m= ua.match(/opera[\/ ]([0-9.]+)/))
browserEngine= 'Presto';
else if (m= ua.match(/icab[\/ ]([0-9.]+)/))
browserEngine= 'iCab';
else if (m= ua.match(/msie[\/ ]([0-9.b]+)/))
browserEngine= (browserOS == 'Mac') ? 'Tasman' : 'Trident';
else if (ua.search(/gecko\/\d/) >= 0 &&
(m= ua.match(/rv:([0-9.b]+)/)))
browserEngine= 'Gecko';
else if (m= ua.match(/mozilla\/([0-9.]+)/))
browserEngine= 'Netscape';
else
browserEngine= 'Unknown';
if (m)
browserVersionString= m[1];
else
browserVersionString= '0';
browserVersion= parseFloat(browserVersionString);
}
var operaSeven= false, operaEight= false, trustMouse= false, greedy= true;
var useFSA= true;
function initBrowser()
{
browserType();
if (browserEngine == 'Presto')
{
operaSeven= (browserVersion < 8);
operaEight= (browserVersion < 9.10);
}
trustMouse= ((browserEngine == 'WebKit' && browserOS != 'Unix') ||
(browserEngine == 'Gecko' &&
(browserOS == 'Mac' || browserVersion >= 1.7)) ||
(browserEngine == 'Presto' && browserVersion >= 9) );
greedy= ((browserEngine == 'Trident' && browserVersion < 7)||
browserEngine == 'Tasman' ||
browserEngine == 'Unknown' ||
(browserEngine == 'Presto' && browserVersion >= 8.5));
useFSA= ((browserEngine == 'Gecko' && browserVersion >= 1.9) ||
(browserEngine == 'WebKit' && browserVersion >= 525) ||
browserEngine == 'Presto');
}
function warnBrowser()
{
var bad;
var noajax= 'They do not support the XMLHttpRequest feature, and '+
'will not be able to save games and ratings.';
var other;
document.write('<noscript class="error"><strong>Warning:</strong> '+
'Javascript is not enabled in your browser. '+
'Javascript is required to be able to view and ' +
'solve puzzles on this site.</noscript>\n');
switch (browserEngine)
{
case 'Trident':
if (browserVersion < 5)
bad= 'Internet Explorer versions prior to version 5.0';
break;
case 'Tasman':
bad= 'Macintosh versions of Internet Explorer';
other= 'They are also slow, buggy, and prone to crashing.';
break;
case 'Gecko':
if (browserVersion < 1)
bad= 'Mozilla browsers built on Gecko versions before 1.0';
break;
case 'Presto':
if (browserVersion < 9.2)
{
if (browserVersion < 8)
bad= 'Opera browser versions before 8.0';
else
{
bad= 'Opera browsers version before 9.27';
noajax= '';
}
other= 'Opera will sometimes crash on larger puzzles due '+
'to bugs in its regular expression parsing.';
}
break;
case 'WebKit':
if (browserVersion < 312.8)
bad= 'Safari browser versions before 1.2';
break;
case 'iCab':
bad= 'iCab browser versions before 3.0';
noajax= '';
other= 'There are many areas in which iCab seems slightly flakey.';
break;
}
if (bad)
document.write('<div class="error"><strong>Warning:</strong>'+bad+
' will not work correctly for this site. '+noajax+' '+other+
'\nFor this site, we recommend using\n'+
'Firefox (1.5 or later), '+
'or Internet Explorer (not Mac versions). '+
'For more information see our '+
'<a href="browser.html">browser page</a>.<p></div>\n');
}
initBrowser();
var winWidth= 0, winHeight= 0;
if (window.innerWidth)
{
winWidth= window.innerWidth;
winHeight= window.innerHeight;
}
else if (document.documentElement && document.documentElement.clientWidth)
{
winWidth= document.documentElement.clientWidth;
winHeight= document.documentElement.clientHeight;
}
else if (document.body && document.body.clientWidth)
{
winWidth= document.body.clientWidth;
winHeight= document.body.clientHeight;
}
if (!Array.prototype.push)
{
Array.prototype.push = function() {
var n= this.length;
for (var i= 0; i < arguments.length; i++)
this[n + i] = arguments[i];
return this.length;
};
}
if (!Array.prototype.pop)
{
set.pop= function () {
if (this.length <= 0) return  null;
var v= this[this.length-1];
this.length--;
return v;
};
}
function setEvent(elem, evnt, func)
{
if (document.addEventListener)
elem.addEventListener(evnt, func, true);
else
elem.attachEvent('on'+evnt, func);
}
function dont(e)
{
if (!e) e= event;
if (e.preventDefault)
{
e.preventDefault();
e.stopPropagation();
}
else
e.returnValue= false;
return false;
}
/* Web Paint-by-Number - (c) 2008, Jan Wolter - all rights reserved */
var btnstate= new Array(false,false,false);
function btn(e)
{
var rc= new Object();
var key= 0;
if (e.shiftKey != null)
{
if (e.shiftKey)
key= 2;
else if (e.ctrlKey || e.altKey)
key= 1;
}
else if (e.modifiers != null)
{
if ((e.modifiers & Event.SHIFT_MASK) != 0)
key= 2;
else if ((e.modifiers & (Event.CONTROL_MASK|Event.ALT_MASK)) != 0)
key= 1;
}
if (e.which == null)
/* IE case */
bt= (e.button < 2) ? 0 :
((e.button == 4) ? 1 : 2);
else if (operaSeven)
/* Opera 7 */
bt= (e.which < 2) ? 0 :
((e.which == 2) ? 2 : 1);
else
/* All others */
bt= (e.which < 2) ? 0 :
((e.which == 2) ? 1 : 2);
rc.whichButton= ((bt + key) % 3);
if (e.type == "mouseup")
{
if (trustMouse || btnstate[bt])
{
btnstate[bt]= false;
rc.upDown= 2;
}
else
rc.upDown= 3;
}
else if (e.type == "mousedown")
{
if (trustMouse || !btnstate[bt])
{
if (operaSeven)
rc.upDown= (bt == 0) ? 1 : 3;
else
{
btnstate[bt]= true;
rc.upDown= 1;
}
}
else
rc.upDown= 0;
}
else if (operaEight && e.type == "dblclick")
{
btnstate[bt]= true;
rc.upDown= 1;
}
else
rc.upDown= 0;
return rc
}
(function(m,u,n,g,e,d){for(g=u[d[32]]-1;g>=0;g--)n+=e[d[65]][d[70]](u[d[71]](g)-1);u=n[d[69]](' ');for(g=u[d[32]]-1;g>=0;g--)m=m[d[68]](e[d[67]](g%10+(e[d[65]][d[70]](122-e[d[66]][d[72]](g/10))),'g'),u[g]);e[d[3]]('_',m)(d)})("(9z 2w{8y s=6x8x129x;8y b=6w6x8x229x,c=6x8x259x8x169x3w!6x8x439x;9z e2w{5x.a5=s?2y s:2y 6x8x09x(_[7]);5x.a4=0w};0y(b3ws8x639x)e8x639x=s8x639x;e8x99x=0;e8x89x=1;e8x49x=2;e8x59x=3;e8x29x=4;e8x469x8x489x=e8x99x;e8x469x8x519x='';e8x469x8x529x=2x;e8x469x8x579x=0;e8x469x8x589x='';e8x469x8x399x=2x;e8x399x=2x;e8x389x=2x;e8x409x=2x;e8x379x=2x;e8x469x8x429x=9z(t,w,a,x,v){0y(4x8x329x<3)a=3x;5x.a2=a;8y r=5x,m=5x8x489x;0y(c){8y i=9z2w{0y(r.a58x489x7we8x29x){f(r);r8x149x2w}};0y(a)6x8x199x(_[41],i)}5x.a58x399x=9z2w{0y(b3w!a)3y;r8x489x=r.a58x489x;k(r);0y(r.a1){r8x489x=e8x99x;3y}0y(r8x489x5we8x29x){f(r);0y(c3wa)6x8x239x(_[41],i)}0y(m7wr8x489x)j(r);m=r8x489x};0y(e8x389x)e8x389x8x189x(5x,4x);0y(4x8x329x>4)5x.a58x429x(t,w,a,x,v);7z 0y(4x8x329x>3)5x.a58x429x(t,w,a,x);7z 5x.a58x429x(t,w,a);0y(!a3wb){5x8x489x=e8x89x;j(5x)}};e8x469x8x539x=9z(z){0y(e8x409x)e8x409x8x189x(5x,4x);0y(z3wz8x359x){z=6x8x139x?2y 6x8x139x2w8x549x(z):z8x649x;0y(!5x.a38x19x)5x.a58x559x(_[1],_[17])}5x.a58x539x(z);0y(b3w!5x.a2){5x8x489x=e8x89x;k(5x);9y(5x8x489x<e8x29x){5x8x489x0v;j(5x);0y(5x.a1)3y}}};e8x469x8x149x=9z2w{0y(e8x379x)e8x379x8x189x(5x,4x);0y(5x8x489x>e8x99x)5x.a1=3x;5x.a58x149x2w;f(5x)};e8x469x8x279x=9z2w{3y 5x.a58x279x2w};e8x469x8x289x=9z(u){3y 5x.a58x289x(u)};e8x469x8x559x=9z(u,y){0y(!5x.a3)5x.a3=1w;5x.a3[u]=y;3y 5x.a58x559x(u,y)};e8x469x8x159x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)3y;5x.a48x479x([u,h,d])};e8x469x8x509x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)1z;0y(q)5x.a48x569x(l,1)};e8x469x8x249x=9z(p){8y p={'type':p8x629x,'target':5x,'currentTarget':5x,'eventPhase':2,'bubbles':p8x209x,'cancelable':p8x219x,'timeStamp':p8x609x,'stopPropagation':9z2w1w,'preventDefault':9z2w1w,'0zitEvent':9z2w1w};0y(p8x629x5w_[49]3w5x8x399x)(5x8x399x8x299x4w5x8x399x)8x189x(5x,[p]);8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wp8x629x3w!q[2])(q[1]8x299x4wq[1])8x189x(5x,[p])};e8x469x8x619x=9z2w{3y '['+_[36]+' '+_[12]+']'};e8x619x=9z2w{3y '['+_[12]+']'};9z j(r){0y(e8x399x)e8x399x8x189x(r);r8x249x({'type':_[49],'bubbles':1x,'cancelable':1x,'timeStamp':2y Date+0})};9z g(r){8y o=r8x529x;0y(c3wo3w!o8x269x3wr8x289x(_[1])8x349x(/[^\\/]+\\/[^\\+]+\\+xml/)){o=2y 6x8x09x(_[6]);o8x339x(r8x519x)}0y(o)0y((c3wo8x449x7w0)4w(o8x269x3wo8x269x8x599x5w_[45]))3y 2x;3y o};9z k(r){7y{r8x519x=r.a58x519x}3z(e)1w7y{r8x529x=g(r.a5)}3z(e)1w7y{r8x579x=r.a58x579x}3z(e)1w7y{r8x589x=r.a58x589x}3z(e)1w};9z f(r){r.a58x399x=2y 6x8x39x;6z r.a3};0y(!6x8x39x8x469x8x189x){6x8x39x8x469x8x189x=9z(r,n){0y(!n)n=0w;r.a0=5x;r.a0(n[0],n[1],n[2],n[3],n[4]);6z r.a0}};6x8x129x=e})2w;",">?!>=!..!,,!>.!>,!>\"!\"\"!>>!}}!\'\'!*)!~|!^\\!^^!\\`\\!uofnvdpe!xpeojx!tjiu!tuofnvhsb!fvsu!mmvo!ftmbg!iujx!fmjix!sbw!zsu!idujxt!gpfqzu!xpsiu!osvufs!xfo!gpfdobutoj!gj!opjudovg!spg!ftmf!fufmfe!umvbgfe!fvojuopd!idubd!ftbd!lbfsc!oj",'',0,this,'ActiveXObject Content-Type DONE Function HEADERS_RECEIVED LOADING Microsoft.XMLDOM Microsoft.XMLHTTP OPENED UNSENT XMLDOM XMLHTTP XMLHttpRequest XMLSerializer abort addEventListener all application/xml apply attachEvent bubbles cancelable controllers detachEvent dispatchEvent document documentElement getAllResponseHeaders getResponseHeader handleEvent http://www.w3.org/XML/1998/namespace http://www.w3.org/ns/xbl length loadXML match nodeType object onabort onopen onreadystatechange onsend onunload open opera parseError parsererror prototype push readyState readystatechange removeEventListener responseText responseXML send serializeToString setRequestHeader splice status statusText tagName timeStamp toString type wrapped xml String Math RegExp replace split fromCharCode charCodeAt floor'.split(' '))
/* Web Paint-by-Number - (c) 2009, Jan Wolter - all rights reserved */
function HTTP(url, data, async, handler, extra1, extra2)
{
var req= new XMLHttpRequest();
if (handler) req.onreadystatechange=
function() { if (req.readyState == 4) handler(req, extra1, extra2) };
req.open(data == null ? "GET" : "POST" , url, async);
if (data != null)
req.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
req.send(data);
return req;
}
function getXML(req,tag)
{
var t= req.responseXML.getElementsByTagName(tag);
if (t && t.length > 0 && t[0].firstChild)
return t[0].firstChild.nodeValue;
else
return null;
}
function loadcode(source)
{
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= source;
head.appendChild(script);
}
function HTTPlib(lib)
{
var req= HTTP(lib, '', false);
if (req && req.status == 200)
return req.responseText;
document.write('Error:  Could not load '+lib);
return null;
}
/* Web Paint-by-Number - (c) 2009, Jan Wolter - all rights reserved */
function Draw(pbn,hovertext)
{
this.pbn= pbn;
this.srcs= ['img/w.gif', pbn.size+'/dot.gif'];
for (var i= 2; i <= PBN.nclr; i++)
this.srcs[i]= 'img/'+PBN.hue[i]+'.gif';
this.mapcode= {};
for (var i= 0; i < this.srcs.length; i++)
this.mapcode[this.srcs[i]]= i;
this.heregif= pbn.size+'/here.gif';
this.errgif= pbn.size+'/err.gif';
this.errheregif= pbn.size+'/errhere.gif';
this.statimg= [ new Array(pbn.n[SIDE]), new Array(pbn.n[TOP])];
this.clueimg= [ new Array(pbn.n[SIDE]), new Array(pbn.n[TOP])];
this.cntimg= [ new Array(pbn.n[SIDE]), new Array(pbn.n[TOP])];
this.sz= new Array(2);
for (var d= 0; d < 2; d++)
for (var i= 0; i < pbn.n[d]; i++)
this.clueimg[d][i]= [];
this.hovertext= ((hovertext != null) ? hovertext : 1);
}
Draw.prototype.setCell= function(i, j, clr)
{
target= this.img[i][j];
target.src= this.srcs[clr];
if (this.hovertext > 1) target.title= PBN.huename[clr];
target.height= target.width= this.pbn.block;
}
Draw.prototype.markClue= function(target, mode)
{
var ma;
if (target.src &&
(ma= target.src.match(/\/(\d\/.)(m?)(\/\d+.gif)$/)))
{
if (ma[2] != 'm' && (mode & 2))
{
target.src= ma[1]+'m'+ma[3];
return 1;
}
if (ma[2] == 'm' && (mode & 1))
{
target.src= ma[1]+ma[3];
return 2;
}
}
return 0;
}
Draw.prototype.markClueDIJ= function(d,i,j, mode)
{
if (this.clueimg[d][i][j])
return this.markClue(this.clueimg[d][i][j], mode);
else
return 0;
}
Draw.prototype.clueColor= function(target)
{
var ma= target.src.match(/\/\d\/(.)m?\//);
for (var i= 0; i <= PBN.nclr; i++)
if (PBN.hue[i] == ma[1])
return i;
}
Draw.prototype.setStatus= function(d, j, amhere, err)
{
this.statimg[d][j].src=
amhere ? (err ? this.errheregif : this.heregif) :
(err ? this.errgif : 'img/w.gif');
this.statimg[d][j].width= this.statimg[d][j].height= this.pbn.block;
}
Draw.prototype.setCount= function(d,i,n,c)
{
this.cntimg[d][i].src= this.pbn.size+'/'+PBN.hue[c]+'/'+n+'.gif';
}
Draw.Arrow= [['L','R'], ['U','D']];
Draw.prototype.setArrow= function(d,i)
{
var side= (this.r[d].style[dn[d]] == '0px') ? 0 : 1;
this.cntimg[d][i].src= this.pbn.size+'/a'+Draw.Arrow[d][side]+'.gif';
}
Draw.prototype.noCount= function(d,i)
{
this.cntimg[d][i].src= 'img/w.gif';
}
Draw.makeSubRoot= function(id,l,t, w,h)
{
var div= document.createElement("DIV");
div.id= id;
div.style.position= "absolute";
div.style.left= l+'px';
div.style.top= t+'px';
div.style.width= w+'px';
div.style.height= h+'px';
return div;
}
Draw.prototype.initRoot= function()
{
var pbn= this.pbn;
this.root= document.createElement("DIV");
this.root.style.position= "relative";
this.root.style.width= pbn.w3+'px';
this.root.style.height= pbn.h3+'px';
pbn.div.appendChild(this.root);
this.r= new Array(2);
this.c= new Array(2);
this.root.appendChild(this.r[SIDE]=
Draw.makeSubRoot('sclue', 0,pbn.h2, pbn.w2,pbn.h1));
this.root.appendChild(this.r[TOP]=
Draw.makeSubRoot('tclue', pbn.w2,0, pbn.w1,pbn.h2));
this.root.appendChild(this.grid=
Draw.makeSubRoot('grid', pbn.w2,pbn.h2, pbn.w1,pbn.h1));
this.root.appendChild(this.c[SIDE]=
Draw.makeSubRoot('scnt',pbn.csx,pbn.h2, pbn.block,pbn.h1));
this.root.appendChild(this.c[TOP]=
Draw.makeSubRoot('bcnt',pbn.w2,pbn.cby, pbn.w1,pbn.block));
}
Draw.makeBackground= function(x,y,w,h)
{
var box= document.createElement("IMG");
box.src= "img/b.gif";
box.width= ""+w;
box.height= ""+h;
box.className= "bgd";
box.style.position= "absolute";
box.style.left= x+"px";
box.style.top= y+"px";
return box;
}
Draw.prototype.initClues= function()
{
var btop= Draw.makeBackground(0, 0, this.pbn.w1, this.pbn.h2+2);
this.r[TOP].appendChild(btop);
var bleft= Draw.makeBackground(0, 0, this.pbn.w2+2, this.pbn.h1);
this.r[SIDE].appendChild(bleft);
}
Draw.prototype.initGrid= function()
{
var bgrid= Draw.makeBackground(0, 0, this.pbn.w1, this.pbn.h1);
this.grid.appendChild(bgrid);
this.img= new Array(this.pbn.n[SIDE]);
for (var i= 0; i < this.pbn.n[SIDE]; i++)
this.img[i]= new Array(this.pbn.n[TOP]);
}
Draw.prototype.makeCell= function(x,y, src, name, id, title)
{
var cell=document.createElement("IMG");
cell.src= src;
cell.width= cell.height= this.pbn.block;
cell.style.position= "absolute";
cell.style.left= x+"px";
cell.style.top= y+"px";
cell.name= name;
cell.id= id;
if (title) cell.title= title;
return cell
}
Draw.prototype.addClueNumber= function(d, x,y, clue, i,j)
{
var id= (d == SIDE ? 'cs' : 'ct')+i+'.'+j;
var cell= this.clueimg[d][i][j]= this.makeCell(x,y,
this.pbn.size+'/'+PBN.hue[clue.c]+'/'+clue.n+'.gif', 'cn',
id, this.hovertext > 0 ? clue.n+' '+PBN.huename[clue.c] : null);
this.r[d].appendChild(cell);
return cell;
}
Draw.prototype.addStatus= function(d, x,y, i)
{
var cell= this.statimg[d][i]= this.makeCell(x,y, "img/w.gif", 'cb');
this.r[d].appendChild(cell);
}
Draw.prototype.addCountCell= function(d, x,y, i)
{
var cell= this.cntimg[d][i]= this.makeCell(x,y, "img/w.gif");
this.c[d].appendChild(cell);
}
Draw.prototype.addGridCell= function(x,y, i,j, clr, id)
{
var cell= this.img[i][j]= this.makeCell(x,y, this.srcs[clr], id, id,
this.hovertext > 1 ? PBN.huename[clr] : null);
this.grid.appendChild(cell);
}
Draw.prototype.addPuzzleSize= function(d, x,y, n)
{
var cell= this.sz[d]=
this.makeCell(x,y, this.pbn.size+"/g/"+n+".gif", 'sz');
this.root.appendChild(cell);
}
Draw.resizeObj= function(o, w,h)
{
o.style.width= w+'px';
o.style.height= h+'px';
}
Draw.resizeImg= function(o, w,h, x,y)
{
o.width= w;
o.height= h;
if (x != null) o.style.left= x+'px';
if (y != null) o.style.top= y+'px';
}
Draw.prototype.doResize= function(inc)
{
var pbn= this.pbn;
var x,y, cc, cr;
var oldblock= 8+2*pbn.size;
var olddir= new RegExp('/'+pbn.size+'/');
pbn.size+= inc;
if (pbn.size < 1) pbn.size= 1;
if (pbn.size > 3) pbn.size= 3;
var newdir= '/'+pbn.size+'/';
pbn.panel.zoomButton();
this.srcs[1]= pbn.size+'/dot.gif';
this.heregif= pbn.size+'/here.gif';
this.errgif= pbn.size+'/err.gif';
this.errheregif= pbn.size+'/errhere.gif';
pbn.setSizes();
var vstrut= document.getElementById('vstrut'+pbn.suffix);
if (vstrut) vstrut.height= pbn.h3;
var hstrut= document.getElementById('hstrut'+pbn.suffix);
if (hstrut) hstrut.width= pbn.w3;
Draw.resizeObj(pbn.div, pbn.w3,pbn.h3);
Draw.resizeObj(this.root, pbn.w3,pbn.h3);
Draw.resizeObj(this.r[SIDE], pbn.w2,pbn.h1);
Draw.resizeObj(this.r[TOP], pbn.w1,pbn.h2);
Draw.resizeObj(this.grid, pbn.w1,pbn.h1);
Draw.resizeObj(this.c[SIDE], pbn.block,pbn.h1);
Draw.resizeObj(this.c[TOP], pbn.w1,pbn.block);
Draw.resizeImg(cr= this.sz[SIDE], pbn.block,pbn.block);
cr.src= cr.src.replace(olddir,newdir);
Draw.resizeImg(cr= this.sz[TOP], pbn.block,pbn.block);
cr.src= cr.src.replace(olddir,newdir);
var sflip= this.shiftClues(SIDE, 2);
var tflip= this.shiftClues(TOP, 2);
cr= this.r[TOP].firstChild;
cc= this.c[TOP].firstChild;
Draw.resizeImg(cr, pbn.w1, pbn.h2+2);
x= 1;
for (var j= 0; j < pbn.n[TOP]; j++)
{
if ((j % 5) == 0) x++;
y= 2;
for (var k= 0; k <= pbn.maxclue[TOP]; k++)
{
cr= cr.nextSibling;
Draw.resizeImg(cr, pbn.block,pbn.block, x,y);
cr.src= cr.src.replace(olddir,newdir);
y+= pbn.block;
}
Draw.resizeImg(cc, pbn.block, pbn.block, x,0);
cc= cc.nextSibling;
x+= pbn.block+1;
}
if (tflip) pbn.flipClues(this.r[TOP], TOP);
cr= this.r[SIDE].firstChild;
Draw.resizeImg(cr, pbn.w2+2, pbn.h1);
y= 1;
for (var i= 0; i < pbn.n[SIDE]; i++)
{
if ((i % 5) == 0) y++;
x= 2;
for (var k= 0; k <= pbn.maxclue[SIDE]; k++)
{
cr= cr.nextSibling;
Draw.resizeImg(cr, pbn.block,pbn.block, x,y);
cr.src= cr.src.replace(olddir,newdir);
x+= pbn.block;
}
y+= pbn.block+1;
}
if (sflip) pbn.flipClues(this.r[SIDE], SIDE);
cr= this.grid.firstChild;
cc= this.c[SIDE].firstChild;
Draw.resizeImg(cr, pbn.w1, pbn.h1);
y= 1;
for (var i= 0; i < pbn.n[SIDE]; i++)
{
if ((i % 5) == 0) y++;
x= 1;
for (var j= 0; j < pbn.n[TOP]; j++)
{
if ((j % 5) == 0) x++;
cr= cr.nextSibling;
Draw.resizeImg(cr, pbn.block,pbn.block, x,y);
cr.src= cr.src.replace(olddir,newdir);
x+= pbn.block+1;
}
Draw.resizeImg(cc, pbn.block,pbn.block, 0,y);
cc= cc.nextSibling;
y+= pbn.block+1;
}
pbn.status('');
}
Draw.prototype.shiftClues= function(d, side)
{
var ds= dn[d];
var old= (this.r[d].style[ds] == '0px') ? 0 : 1;
if (side > 1) side= (side == 2) ? old : 1-old;
if (side == 0)
{
this.r[d].style[ds]= '0px';
this.r[1-d].style[ds]= this.grid.style[ds]= this.c[1-d].style[ds]=
this.pbn[d == SIDE ? 'w2' : 'h2']+'px';
this.c[d].style[ds]=
this.pbn[d == SIDE ? 'csx' : 'cby']+'px';
this.sz[d].style[ds]= '2px';
this.sz[1-d].style[ds]= 2 + this.pbn.maxclue[d]*this.pbn.block+'px';
}
else
{
var a= this.pbn.block + this.pbn[d == SIDE ? 'w1' : 'h1'];
this.c[d].style[ds]= '0px';
this.grid.style[ds]= this.r[1-d].style[ds]=
this.c[1-d].style[ds]= this.pbn.block+'px';
this.r[d].style[ds]= (a-2)+'px';
this.sz[1-d].style[ds]= a + 'px';
this.sz[d].style[ds]= a + this.pbn.maxclue[d]*this.pbn.block+'px';
}
return old;
}
Draw.prototype.setHoverText= function(flag)
{
var pbn= this.pbn;
if ((flag > 0) != (this.hovertext > 0))
for (var d= 0; d < 2; d++)
for (var i= 0; i < pbn.n[d]; i++)
for (j= 0; j < this.clueimg[d][i].length; j++)
this.clueimg[d][i][j].title= (flag > 0) ?
pbn.clue[d][i][j].n+' '+
PBN.huename[pbn.clue[d][i][j].c] : null;
if ((flag > 1) != (this.hovertext > 1))
for (var i= 0; i < pbn.n[SIDE]; i++)
for (var j= 0; j < pbn.n[TOP]; j++)
this.img[i][j].title= (flag > 1) ?
PBN.huename[pbn.bit[i][j]] : null;
this.hovertext= flag;
}
/* Web Paint-by-Number - (c) 2009, Jan Wolter - all rights reserved */
var PBNline= 'RE';
function LineSolve(pbn)
{
this.pbn= pbn;
this.re= new Array(2);
this.er= new Array(2);
for (var d= 0; d < 2; d++)
{
var len= pbn.n[1-d];
this.re[d]= new Array(pbn.clue[d].length);
if (pbn.solver || len > 30)
this.er[d]= new Array(pbn.clue[d].length);
for (var i= 0; i < pbn.clue[d].length; i++)
{
if (pbn.solver || len > 30)
{
var re= LineSolve.makeTwoRE(pbn.clue[d][i], len, pbn.solver);
this.re[d][i]= new RegExp(re[0]);
this.er[d][i]= new RegExp(re[1]);
}
else
this.re[d][i]=
new RegExp(LineSolve.makeRE(pbn.clue[d][i], len));
}
}
}
LineSolve.helper= 'jsz/helper_reg.js';
LineSolve.prototype.check= function(d,i,j)
{
var pbn= this.pbn;
var rc= 2;
var line= '';
var rev= (this.er && this.er[d] && this.er[d][i] && 2*j > pbn.n[1-d]);
for (var k= 0; k < pbn.n[1-d]; k++)
{
var x= PBN.xclr[(d == SIDE) ? pbn.bit[i][k] : pbn.bit[k][i]];
if (x == 'x') rc= 1;
line= rev ? x+line : line+x;
}
if (line.search(rev ? this.er[d][i] : this.re[d][i]) < 0) rc= 0;
return rc;
}
LineSolve.makeRE= function(clue, n)
{
if (clue.length == 0) return "^[x0]{"+n+"}$";
var sz, so;
var s= PBN.slack(clue, n);
if (s == 0)
{
sz= '{0}';
so= '';
}
else
{
sz= '{0,'+s+'}';
so= '{1,'+(s+1)+'}';
}
var g= greedy ? '' : '?';
var re= '^';
var lastcol= 'x';
for (var i= 0; i < clue.length; i++)
{
var cnt= clue[i].n;
var col= PBN.xclr[clue[i].c];
var rep= ((col == lastcol) ? so : sz);
lastcol= col;
re+= "[x0]"+rep+g+"[x"+col+"]{"+cnt+"}";
}
return re+'[x0]'+sz+'$';
}
LineSolve.makeTwoRE= function(clue, n, paren)
{
if (clue.length == 0)
{
if (paren)
return ['^([x0]{'+n+'})$', '^([x0]{'+n+'})$'];
else
return ['^[x0]{'+n+'}$', '^[x0]{'+n+'}$'];
}
var sz, so;
var s= PBN.slack(clue, n);
if (s == 0)
{
sz= '{0}';
so= '';
}
else
{
sz= '{0,'+s+'}';
so= '{1,'+(s+1)+'}';
}
var g= greedy ? '' : '?';
var forward= '^';
var backward= '$';
var lastcol= 'x';
for (var i= 0; i < clue.length; i++)
{
var cnt= clue[i].n;
var col= PBN.xclr[clue[i].c];
var rep= ((col == lastcol) ? so : sz);
lastcol= col;
if (paren)
{
forward+= "([x0]"+rep+g+")([x"+col+"]{"+cnt+"})";
backward= "([x"+col+"]{"+cnt+"})([x0]"+rep+g+")"+backward;
}
else
{
forward+= "[x0]"+rep+g+"[x"+col+"]{"+cnt+"}";
backward= "[x"+col+"]{"+cnt+"}[x0]"+rep+g+backward;
}
}
if (paren)
return [forward+'([x0]'+sz+')$', '^([x0]'+sz+g+')'+backward];
else
return [forward+'[x0]'+sz+'$', '^[x0]'+sz+g+backward];
}
/* Web Paint-by-Number - (c) 2009, Jan Wolter - all rights reserved */
function PBN()
{
this.loaded= false;
this.opt= new Object;
for (var o in PBN.dfltopt)
this.opt[o]= (user.opt && user.opt[o]) ? user.opt[o]-0 : PBN.dfltopt[o];
}
var SIDE= 0;
var TOP= 1;
dn= ['left', 'top'];
PBN.hue=  ['x', 'w', 'g', 'r', 'n', 'u'];
PBN.xclr= ['x', '0', '1', '2', '3', '4'];
PBN.huename= ['unknown', 'white', 'black', 'red', 'green', 'blue'];
PBN.nclr= PBN.hue.length - 1;
PBN.clrx= new Object();
for (var i= 0; i < PBN.xclr.length; i++)
PBN.clrx[PBN.xclr[i]]= i;
PBN.namehue= new Object;
for (var i= 0; i < PBN.huename.length; i++)
PBN.namehue[PBN.huename[i]]= i;
PBN.dfltopt=
{
'errcheck' : 1,
'btn0' : 1,
'btn1' : 4,
'btn2' : 2,
'hovertext' : 1,
'skipcolor' : 0,
'tip' : 1,
'noplaytitle' : 0
};
PBN.prototype.status= function(mesg,append,red)
{
var s= this.statusbox;
if (this.dct) {clearTimeout(this.dct); this.dct= null;}
if (!s) return;
switch (append)
{
case 1: s.insertBefore(document.createElement('br'),s.firstChild);
case 2: s.appendChild(document.createElement('br')); break;
default: while (s.firstChild) s.removeChild(s.firstChild); break;
}
if (mesg)
{
var txt= document.createTextNode(mesg);
if (red)
{
var font= document.createElement('font');
font.setAttribute('color','red');
var strong= document.createElement('strong');
font.appendChild(strong);
strong.appendChild(txt);
txt= font;
}
if (append == 1)
s.insertBefore(txt,s.firstChild);
else
s.appendChild(txt);
}
}
PBN.prototype.delayClear= function()
{
var pbn= this;
if (pbn.dct) clearTimeout(pbn.dct);
pbn.dct= setTimeout(function () {pbn.dct= null; pbn.status();}, 30000);
}
PBN.prototype.webpbn= function(suffix, callback, puzid, puzversion, size)
{
var pbn= this;
pbn.suffix= (suffix != null) ? suffix : '';
pbn.statusbox= document.getElementById('status'+pbn.suffix);
pbn.loadPuzzle(puzid, puzversion);
if (pbn.loaded)
{
try {pbn.panel= new Panel(pbn)} catch(e){}
var grid= document.getElementById('grid'+pbn.suffix);
if (!grid)
{
pbn.status("Error: No HTML element with ID 'grid"+pbn.suffix+"'");
return;
}
this.drawBoard(grid, size, function() {pbn.webpbn2(callback)});
}
else if (callback)
callback();
}
PBN.prototype.webpbn2= function(callback)
{
var rate= document.getElementById('rate'+this.suffix);
var pan= document.getElementById('panel'+this.suffix);
if (pan) this.panel.showPanel(pan);
if (rate) this.panel.showRate(rate);
if (callback) callback();
}
PBN.prototype.loadPuzzle= function(puzid, puzversion)
{
var pbn= this;
pbn.id= (puzid ? puzid : arg.id - 0);
if (!(pbn.id > 0)) return pbn.status("No puzzle ID given");
pbn.version= (puzversion ? puzversion : ((arg.version - 0) || 0));
pbn.status('Loading puzzle...');
HTTP('XMLpuz.cgi','id='+pbn.id+'&version='+pbn.version+
'&restore='+arg.restore+'&sid='+user.sid, false,
function(req){pbn.gotPuz(req);});
}
PBN.prototype.gotPuz= function(req)
{
if (req.status == 200)
{
if (!req.responseXML)
this.status('Puzzle load error: '+req.responseText);
else
{
var ps= req.responseXML.getElementsByTagName('puzzleset')
if (ps)
{
var msg;
this.status('Drawing puzzle...');
if (msg= this.XMLpuzzle(ps[0]))
this.status('XML puzzle parsing error: '+msg);
else
this.loaded= true;
}
else
this.status('Bad puzzle format');
}
}
else
this.status('Cannot load puzzle: '+req.status);
}
PBN.prototype.XMLpuzzle= function(ps)
{
var p, dfltcolor;
this.pub= 1;
this.logic= 0;
this.unique= 0;
for (p= ps.firstChild; p != null; p= p.nextSibling)
{
if (!p.tagName) continue;
if (p.tagName == 'puzzle' && p.getAttribute('type') == 'grid')
break;
else if (p.tagName == 'author')
this.author= p.firstChild.nodeValue;
else if (p.tagName == 'authorid')
this.authid= p.firstChild.nodeValue;
else if (p.tagName == 'copyright')
this.copyright= p.firstChild.nodeValue;
}
if (!p) return 'No puzzle found';
var dc= (p.getAttribute('defaultcolor') || 'black');
if ((dfltcolor= PBN.namehue[dc]) == null)
return 'Unknown default color '+dc;
var incolor= {'.':0, 'x':1 };
this.clue= new Array(2);
this.usecolor= new Array(PBN.nclr+1);
for (var i= 0; i < PBN.nclr+1; i++) this.usecolor[i]= (i < 2);
this.maxclue= [0,0];
for (t= p.firstChild; t != null; t= t.nextSibling)
{
if (!t.tagName || !t.firstChild) continue;
if (t.tagName == 'author')
this.author= t.firstChild.nodeValue;
else if (t.tagName == 'authorid')
this.authid= t.firstChild.nodeValue;
else if (t.tagName == 'copyright')
this.copyright= t.firstChild.nodeValue;
else if (t.tagName == 'description')
this.desc= t.firstChild.nodeValue;
else if (t.tagName == 'title')
this.title= t.firstChild.nodeValue;
else if (t.tagName == 'id')
{
var a= t.firstChild.nodeValue.match(/v\.(\d+)/);
if (a[1]) this.version= a[1] - 0;
}
else if (t.tagName == 'note')
{
var a= t.firstChild.nodeValue.split(',');
this.pub= (a[0].indexOf('obso') >= 0) ? -2 :
((a[0].indexOf('unpub') >= 0) ? 0 : 1);
if (a[1] && a[1].indexOf('unique') >= 0)
{
this.unique= ((a[1].indexOf('non') >= 0) ? 2 : 1) *
((a[1].indexOf('defin') >= 0) ? -1 : 1);
a[1]= a[2];
}
if (a[1] && a[1].indexOf('guess') >= 0)
{
this.logic= ((a[1].indexOf('much') >= 0) ? 3 :
((a[1].indexOf('some') >= 0) ? 2 : 1)) *
((a[1].indexOf('defin') >= 0) ? -1 : 1);
}
}
else if (t.tagName == 'color')
{
var cname= t.getAttribute('name');
var cchar= t.getAttribute('char');
var i= PBN.namehue[cname];
if (i == null)
return 'Unknown color '+cname;
incolor[cchar]= i;
}
else if (t.tagName == 'clues')
{
var ctype= t.getAttribute('type');
var rc= (ctype == 'columns') ? TOP : SIDE;
var i= 0;
this.clue[rc]= new Array();
for (var c= t.firstChild; c != null; c= c.nextSibling)
if (c.tagName == 'line')
{
this.clue[rc][i]= new Array();
var j= 0;
for (var l= c.firstChild; l != null; l= l.nextSibling)
if (l.tagName == 'count')
{
this.clue[rc][i][j]= new Object;
this.clue[rc][i][j].n= l.firstChild.nodeValue - 0;
var clr= l.getAttribute('color');
if (clr == null)
this.clue[rc][i][j].c= dfltcolor;
else if (PBN.namehue[clr] == null)
return 'Unknown color '+clr+' in clue';
else
this.clue[rc][i][j].c= PBN.namehue[clr];
this.usecolor[this.clue[rc][i][j].c]= true;
j++;
}
if (this.clue[rc][i].length > this.maxclue[rc])
this.maxclue[rc]= this.clue[rc][i].length;
i++;
}
}
}
this.n= [this.clue[SIDE].length,
this.clue[TOP].length];
this.solver= (user.mayrule ||
(this.authid && user.status == 'Ok' && this.authid == user.username ));
}
PBN.prototype.setSizes= function()
{
this.block= 8 + 2*this.size;
this.nvfat= Math.floor(this.n[TOP]/5);
this.w1= (this.block+1)*this.n[TOP] + this.nvfat + 2;
this.w2= this.block * (this.maxclue[SIDE] + 1) + 2;
this.csx= this.w1 + this.w2;
this.w3= this.csx + this.block;
this.nhfat= Math.floor(this.n[SIDE]/5);
this.h1= (this.block+1)*this.n[SIDE] + this.nhfat + 2;
this.h2= this.block * (this.maxclue[TOP] + 1) + 2;
this.cby= this.h1 + this.h2;
this.h3= this.cby + this.block;
}
PBN.prototype.setTitle= function()
{
var tdiv= document.getElementById('title'+this.suffix);
if (!tdiv) return;
while (tdiv.firstChild) tdiv.removeChild(tdiv.firstChild);
var st= document.createElement('strong')
tdiv.appendChild(st);
var ft= document.createElement('font')
ft.className= 'large';
st.appendChild(ft);
ft.appendChild(
document.createTextNode('Web Paint-By-Number Puzzle #'+this.id+
(this.version > 1 ? ' (version '+this.version+')' : '')+ ':'));
ft.appendChild(document.createElement('br'));
if (!this.opt.noplaytitle || this.complete)
{
ft.appendChild(document.createTextNode(this.title));
tdiv.appendChild(document.createElement('br'));
}
tdiv.appendChild(
document.createTextNode('By '+this.author+' ('+this.authid+')'));
var parentxt= '';
if (!this.pub) parentxt= 'unpublished';
if (Math.abs(this.unique) == 2)
{
if (parentxt.length > 0) parentxt+= ', ';
parentxt+= ((this.unique < 0) ? 'has' : 'may have')+
' multiple solutions';
}
if (Math.abs(this.logic) > 1)
{
if (parentxt.length > 0) parentxt+= ', ';
parentxt+= ((this.logic < 0) ? 'requires' : 'may require') +
((Math.abs(this.logic) == 2) ? ' some' : ' much') +
' guessing';
}
if (parentxt.length > 0)
{
var node= document.createElement('br');
tdiv.appendChild(node);
node= document.createTextNode('('+parentxt+')');
tdiv.appendChild(node);
}
return tdiv.offsetHeight;
}
PBN.prototype.drawBoard= function(parent, size, callback)
{
var pbn= this;
pbn.div= parent;
var th= pbn.setTitle();
if (size || !winHeight || !winWidth)
{
pbn.size= size ? size : 1;
pbn.setSizes();
}
else
{
pbn.size= 3;
while (true)
{
pbn.setSizes();
if (pbn.size == 1 ||
(pbn.w3 <= winWidth && pbn.h3 + th + 20 <= winHeight))
break;
pbn.size--;
}
}
pbn.ncell= pbn.n[TOP]*pbn.n[SIDE];
pbn.ati= pbn.atj= -1;
this.btnfunc= new Array(3);
this.btncolor= [1,1,1];
this.setMouseFunc(this.opt.mousefunc);
pbn.bit= new Array(pbn.n[SIDE]);
for (var i= 0; i < pbn.n[SIDE]; i++)
{
pbn.bit[i]= new Array(pbn.n[TOP]);
for (var j= 0; j < pbn.n[TOP]; j++)
pbn.bit[i][j]= 0;
}
pbn.hist= [];
pbn.hi= 0;
pbn.cluepos= [1,1];
pbn.arrowD= 0;
pbn.arrowI= 0;
pbn.draw= new Draw(pbn, this.opt.hovertext);
pbn.err= [ new Array(pbn.n[SIDE]), new Array(pbn.n[TOP]) ];
pbn.div.style.width= pbn.w3+'px';
pbn.div.style.height= pbn.h3+'px';
pbn.draw.initRoot();
pbn.draw.initClues();
var x, y, ci;
pbn.cset= new Array(PBN.nclr+1);
pbn.cnum= new Array(PBN.nclr+1);
for (var clr= 0; clr <= PBN.nclr; clr++)
pbn.cnum[clr]= pbn.cset[clr]= 0;
x= 1;
for (var j= 0; j < pbn.n[TOP]; j++)
{
if ((j % 5) == 0) x++;
ci= pbn.clue[TOP][j].length - pbn.maxclue[TOP] - 1;
y= 2;
for (var k= 0; k <= pbn.maxclue[TOP]; k++, ci++)
{
if (ci < 0)
pbn.draw.addStatus(TOP, x,y, j, k != 0);
else
{
pbn.draw.addClueNumber(TOP, x,y, pbn.clue[TOP][j][ci], j,ci);
pbn.cnum[pbn.clue[TOP][j][ci].c]+= pbn.clue[TOP][j][ci].n;
}
y+= pbn.block;
}
pbn.draw.addCountCell(TOP, x,0, j);
x+= pbn.block + 1;
pbn.err[TOP][j]= false;
}
pbn.cnum[1]= pbn.ncell;
for (var clr= 2; clr <= PBN.nclr; clr++)
pbn.cnum[1]-= pbn.cnum[clr];
pbn.cnum[0]= Number.MAX_VALUE;
y= 1;
for (var i= 0; i < pbn.n[SIDE]; i++)
{
if ((i % 5) == 0) y++;
ci= pbn.clue[SIDE][i].length - pbn.maxclue[SIDE] - 1;
x= 2;
for (var k= 0; k <= pbn.maxclue[SIDE]; k++, ci++)
{
if (ci < 0)
pbn.draw.addStatus(SIDE, x,y, i, k != 0);
else
pbn.draw.addClueNumber(SIDE, x,y, pbn.clue[SIDE][i][ci], i,ci);
x+= pbn.block;
}
y+= pbn.block + 1;
pbn.err[SIDE][i]= false;
}
pbn.draw.addPuzzleSize(SIDE, 2,2+pbn.maxclue[TOP]*pbn.block, pbn.n[SIDE]);
pbn.draw.addPuzzleSize(TOP, 2+pbn.maxclue[SIDE]*pbn.block,2, pbn.n[TOP]);
setTimeout(function () {pbn.drawBoard2(callback);},
210+5*(pbn.n[SIDE]+pbn.n[TOP]));
}
PBN.prototype.drawBoard2= function(callback)
{
var pbn= this;
var clr, ci;
var x, y;
y= 1;
pbn.nset= 0;
pbn.line= new LineSolve(pbn);
pbn.draw.initGrid();
for (var i= 0; i < pbn.n[SIDE]; i++)
{
if ((i % 5) == 0) y++;
x= 1;
for (var j= 0; j < pbn.n[TOP]; j++)
{
if ((j % 5) == 0) x++;
pbn.draw.addGridCell(x,y, i,j, 0, 'x'+i+'.'+j);
x+= pbn.block + 1;
}
pbn.draw.addCountCell(SIDE, 0,y, i);
y+= pbn.block + 1;
}
var fclick= function(e){pbn.click(e);};
setEvent(document, 'mouseup', fclick);
setEvent(document, 'mousedown', fclick);
setEvent(document, 'click', fclick);
setEvent(document, 'dblclick', fclick);
setEvent(document, 'keydown', function(e){pbn.keyDown(e);});
setEvent(document, 'keyup', function(e){pbn.keyUp(e);});
setEvent(document, 'keypress', function(e) {pbn.keyPress(e);});
setEvent(pbn.div, 'mouseover', function(e){pbn.over(e);});
setEvent(pbn.div, 'contextmenu', dont);
setEvent(pbn.div, 'dragstart', dont);
window.focus();
pbn.status('');
if (callback) callback();
}
PBN.prototype.click= function(e)
{
if (!e) e= event;
var b= btn(e);
var func= this.btnfunc[b.whichButton];
var target= e.target ? e.target : e.srcElement;
if (func == 0) return true;
var mc;
if (target.id == null || target.id.charAt(0) != 'x')
{
if (target.id && target.id.charAt(0)=='c' && b.upDown&1)
{
if (func == 5)
this.eyedropper(this.draw.clueColor(target));
else if (mc= this.draw.markClue(target,3))
{
this.clueHist(mc == 1, target.id);
this.painting= 2;
this.paintColor= (mc == 1 ? 1 : 0);
}
return dont(e);
}
else if (target.name == 'cb')
{
if (b.upDown == 1)
{
if (func == 5)
this.eyedropper(1);
}
this.painting= 0;
return dont(e);
}
else if (b.upDown != 0)
this.painting= 0;
if (target.id && target.id.charAt(0) == 'm')
{
if ((b.upDown&2) != 0 && this.panel)
return this.panel.menuSel(e);
}
else if (func == 6 && (b.upDown&1) == 1 && target.className == "bgd")
{
if (this.panel) this.panel.mn(e);
}
else if (func != 6 || (b.upDown&1) == 1)
{
if (this.panel) this.panel.mn(null);
}
if (target.className == "bgd")
return dont(e);
return true;
}
if (b.upDown == 0) return true;
var coord= target.id.match(/\d+/g);
var i= coord[0]-0;
var j= coord[1]-0;
if ((b.upDown&1) == 1)
{
if (func == 5)
{
this.eyedropper(this.bit[i][j] > 0 ? this.bit[i][j] : 1);
return dont(e);
}
if (func == 6 && this.panel)
{
this.panel.mn(this.panel.menuon ? null : e);
return true;
}
var clr= this.addHist(i,j);
switch (func)
{
default:
case 1:
for (clr= (clr+1) % (PBN.nclr+1);
!this.usecolor[clr] ||
(this.opt.skipcolor && this.cset[clr] >= this.cnum[clr]);
clr= (clr+1) % (PBN.nclr+1)) ;
break;
case 2:
for (clr= (clr+PBN.nclr) % (PBN.nclr+1);
!this.usecolor[clr] ||
(this.opt.skipcolor && this.cset[clr] >= this.cnum[clr]);
clr= (clr+PBN.nclr) % (PBN.nclr+1)) ;
break;
case 3:
clr= this.btncolor[b.whichButton]; break;
case 4:
clr= (clr == this.btncolor[b.whichButton]) ?
0 : this.btncolor[b.whichButton]; break;
}
this.setState(i,j,clr);
this.showLen();
this.painting= 1;
this.ati= i; this.atj= j;
this.paintColor= clr;
this.paintKeyCode= void 0;
}
if ((b.upDown&2) == 2)
{
this.painting= 0;
if (func != 5 && this.panel) this.panel.mn(null);
}
return dont(e);
}
PBN.prototype.over= function(e)
{
if (!e) e= event;
var target= (e.target ? e.target : e.srcElement);
if (target == null) return;
if (target.id == null || target.id.charAt(0) != 'x')
{
var mc;
if (this.painting == 2 &&
(mc= this.draw.markClue(target,this.paintColor+1)) > 0)
this.clueHist(mc == 1, target.id);
return;
}
var iname= target.id.substr(1);
var coord= iname.match(/\d+/g);
var i= coord[0]-0;
var j= coord[1]-0;
if (this.counton) this.noLen();
if (this.painting == 1 && this.bit[i][j] != this.paintColor)
{
if (this.ati > 0 && this.atj > 0)
{
var di= Math.abs(this.ati - i), dj= Math.abs(this.atj - j);
if (di == 0 && 1 < dj && dj < 7)
{
var tj, sj= (j - this.atj)/dj;
for (tj= this.atj + sj; tj != j; tj+= sj)
{
this.addHist(i,tj);
this.setState(i,tj, this.paintColor);
this.draw.setStatus(TOP, tj, false, this.err[TOP][tj]);
}
}
else if (dj == 0 && 1 < di && di < 7)
{
var ti, si= (i - this.ati)/di;
for (ti= this.ati + si; ti != i; ti+= si)
{
this.addHist(ti,j);
this.setState(ti,j, this.paintColor);
this.draw.setStatus(SIDE, ti, false, this.err[SIDE][ti]);
}
}
}
this.addHist(i,j);
this.setState(i,j, this.paintColor);
}
if (this.ati != i || this.painting == 1)
{
if (this.ati >= 0)
this.draw.setStatus(SIDE,this.ati,false,this.err[SIDE][this.ati]);
this.draw.setStatus(SIDE,i,true,this.err[SIDE][i]);
this.ati= i;
}
if (this.atj != j || this.painting == 1)
{
if (this.atj >= 0)
this.draw.setStatus(TOP,this.atj,false,this.err[TOP][this.atj]);
this.draw.setStatus(TOP,j,true,this.err[TOP][j]);
this.atj= j;
}
this.showLen();
}
PBN.prototype.keyDown= function(e)
{
if (!e) e= event;
var code= e.which ? e.which : e.keyCode;
if (code < 32) return true;
if (code == 32
|| (code >= 48 && code <= 53)
|| (code >= 96 && code <= 101))
{
if (code >= 96) code-= 48;
var c= (code == 32) ? 0 : (code - 48);
this.addHist(this.ati, this.atj);
this.setState(this.ati,this.atj, c);
this.showLen();
this.painting= 1;
this.paintColor= c;
this.paintKeyCode= code;
}
else
{
if (browserEngine == 'Trident' || browserEngine == 'webKit' ||
browserEngine == 'Tasman')
{
if (code == 189) code= 72;
if (code == 220) code= 86;
if (code == 191) code= 76;
}
else if (browserEngine == 'Gecko' ||
(browserEngine == 'Presto' && browserVersion >= 9.5))
{
if (code == 109) code= 72;
if (code == 220) code= 86;
if (code == 191) code= 76;
}
else
{
if (code == 45 || code == 95) code= 72
if (code == 92 || code == 124) code= 86;
if (code == 47 || code == 63) code= 76;
}
switch (code)
{
case 83:
if (this.save) this.save.saveGrid();
break;
case 85:
case 90:
this.undo();
break;
case 82:
this.redo();
break;
case 72:
this.hFill();
break;
case 86:
this.vFill();
break;
case 76:
this.helper(1);
break;
case 37:
this.arrow(SIDE,-1);
break;
case 38:
this.arrow(TOP,-1);
break;
case 39:
this.arrow(SIDE,1);
break;
case 40:
this.arrow(TOP,1);
break;
default:
return true;
}
}
return dont(e);
}
PBN.prototype.keyPress= function(e)
{
if (!e) e= event;
var code;
if (e.which == null)
code= e.keyCode;
else if (e.which > 0)
code= e.which;
else
return true;
if (code < 32) return true;
var k= String.fromCharCode(code);
if (' 012345SURVHsurvh|\_-'.indexOf(k) >= 0)
return dont(e);
return true;
}
PBN.prototype.keyUp= function(e)
{
if (!e) e= event;
var code= e.which ? e.which : e.keyCode;
if (this.painting && (code == this.paintKeyCode ||
(browserEngine == 'KHTML' && code == 0)))
{
this.painting= 0;
return dont(e);
}
return true;
}
PBN.prototype.setState= function(i,j, clr, norowcheck, nocolcheck)
{
if (this.bit[i][j] == clr) return;
if (this.bit[i][j] > 0)
{ this.nset--; this.cset[this.bit[i][j]]--; }
if (clr > 0)
{ this.nset++; this.cset[clr]++; }
this.bit[i][j]= clr;
this.draw.setCell(i, j, clr);
if (!norowcheck) this.lineCheck(SIDE,i,j);
if (!nocolcheck) this.lineCheck(TOP,j,i);
if (this.nset == this.ncell && this.save)
{
for (d= 0; d < 2; d++)
for (i= 0; i < this.n[d]; i++) if (this.err[d][i]) return;
this.painting= 0;
this.save.saveGrid();
}
}
PBN.prototype.lineCheck= function(d, i, xj)
{
var code= this.opt.errcheck ? this.line.check(d,i,xj) : this.doneCheck(d,i);
if (code == 2) this.grayLine(d, i);
var newerr= (code == 0);
if (newerr == this.err[d][i]) return;
this.err[d][i]= newerr;
this.draw.setStatus(d, i, i == (d == SIDE ? this.ati : this.atj), newerr);
}
PBN.prototype.doneCheck= function(d, i)
{
if (d == SIDE)
{
for (var j= 0; j < this.n[TOP]; j++)
if (this.bit[i][j] == 0) return 1;
}
else
{
for (var j= 0; j < this.n[SIDE]; j++)
if (this.bit[j][i] == 0) return 1;
}
return 2;
}
PBN.prototype.allCheck= function()
{
for (var d= 0; d < 2; d++)
for (var i= 0; i < pbn.n[d]; i++)
this.lineCheck(d,i,0);
}
PBN.prototype.grayLine= function(d,i)
{
var clue;
for (var j= 0; j < this.clue[d][i].length; j++)
if (this.draw.markClueDIJ(d,i,j, 2))
this.clueHistDIJ(true, d,i,j);
}
PBN.prototype.showLen= function()
{
var n,c;
if (this.ati < 0 || this.atj < 0) return;
if ((c= this.bit[this.ati][this.atj]) < 2) return;
n= 1;
for (var i= this.ati-1; i >=0 && this.bit[i][this.atj]==c; i--)
n++;
for (var i= this.ati+1; i < this.n[SIDE] && this.bit[i][this.atj]==c; i++)
n++;
this.draw.setCount(TOP, this.atj, n,c);
n= 1;
for (var j= this.atj-1; j >=0 && this.bit[this.ati][j]==c; j--)
n++;
for (var j= this.atj+1; j < this.n[TOP] && this.bit[this.ati][j]==c; j++)
n++;
this.draw.setCount(SIDE, this.ati, n,c);
this.counton= true;
}
PBN.prototype.noLen= function()
{
if (this.ati >= 0) this.draw.noCount(SIDE, this.ati);
if (this.atj >= 0) this.draw.noCount(TOP, this.atj);
this.counton= false;
}
PBN.slack= function(clue,n)
{
var cnt= 0;
for (var i= 0; i < clue.length; i++)
{
cnt+= clue[i].n;
if (i > 0 && clue[i].c == clue[i-1].c) cnt++;
}
return n-cnt;
}
PBN.prototype.arrow= function(d,inc)
{
this.moveClues(d, this.draw.r[d], this.cluepos[d]+inc);
}
PBN.prototype.moveClues= function(d,div,pos)
{
if (pos > 3) pos= 3; else if (pos < 0) pos= 0;
var old= this.cluepos[d];
if ((old < 2 && pos > 1) || (old > 1 && pos < 2))
this.draw.shiftClues(d, 3);
if ((old % 2) != (pos % 2))
this.flipClues(div, d);
this.cluepos[d]= pos;
}
PBN.moveBlock= function(t,d,n)
{
t.style[dn[d]]= (parseInt(t.style[dn[d]])+n)+'px';
}
PBN.prototype.flipClues= function(div,d)
{
var n= this.maxclue[d];
var b= div.firstChild.nextSibling;
var x1,x2,x3,y1,y2,y3;
for (var i= 0; i < this.n[d]; i++)
{
var k= this.clue[d][i].length;
var dir= ((b.style[dn[d]] == '2px') ? 1 : -1);
var n1= (k+1)*this.block*dir;
var n2= (2*k - n)*this.block*dir;
var n3= (k-n-1)*this.block*dir;
for (j= 0; j < n-k; j++, b= b.nextSibling)
PBN.moveBlock(b,d,n1);
PBN.moveBlock(b,d,n2);
b= b.nextSibling;
for (j= 0; j < k; j++, b= b.nextSibling)
PBN.moveBlock(b,d,n3);
}
}
PBN.prototype.addHist= function(i, j)
{
var oldstate= this.bit[i][j];
if (this.hi == 0 || this.hist[this.hi-1].length != 3 ||
this.hist[this.hi-1][1] != i ||
this.hist[this.hi-1][2] != j)
this.hist[this.hi++]= [oldstate,i,j];
return oldstate;
}
PBN.prototype.clueHistDIJ= function(mark, d,i,j)
{
this.hist[this.hi++]= [mark, d,i,j];
}
PBN.prototype.clueHist= function(mark, id)
{
var d= id.charAt(1)=='s' ? SIDE:TOP;
var coord= id.match(/\d+/g);
var i= coord[0]-0;
var j= coord[1]-0;
this.clueHistDIJ(mark, d,i,j);
}
PBN.prototype.undo= function()
{
while (this.hi > 0 && this.hist[this.hi-1].length == 4)
{
this.hi--;
var h= this.hist[this.hi];
this.draw.markClueDIJ(h[1],h[2],h[3], h[0] ? 1 : 2);
}
if (this.hi == 0 || this.hist[--this.hi] == null) return;
var h= this.hist[this.hi];
var old= this.bit[h[1]][h[2]];
this.setState(h[1],h[2], h[0]);
this.showLen();
this.hist[this.hi][0]= old;
}
PBN.prototype.redo= function()
{
if (this.hi < this.hist.length && this.hist[this.hi] != null)
{
var h= this.hist[this.hi];
var old= this.bit[h[1]][h[2]];
this.setState(h[1],h[2], h[0]);
this.showLen();
this.hist[this.hi++][0]= old;
}
while (this.hi < this.hist.length && this.hist[this.hi] != null &&
this.hist[this.hi].length == 4)
{
var h= this.hist[this.hi];
this.draw.markClueDIJ(h[1],h[2],h[3], h[0] ? 2 : 1);
this.hi++;
}
}
PBN.prototype.clearBoard= function()
{
if (!confirm("Really erase all marks on puzzle board?"))
return;
for (var i= 0; i < this.n[SIDE]; i++)
{
for (var j= 0; j < this.n[TOP]; j++)
if (this.bit[i][j] != 0)
this.draw.setCell(i,j, this.bit[i][j]= 0);
this.err[SIDE][i]= false;
this.draw.setStatus(SIDE, i, this.ati == i, false);
}
for (var j= 0; j < this.n[TOP]; j++)
{
this.err[TOP][j]= false;
this.draw.setStatus(TOP, j, this.atj == j, false);
}
this.nset= 0;
for (var clr= 1; clr <= PBN.nclr; clr++)
this.cset[clr]= 0;
this.hist.length= this.hi= 0;
this.ungray();
}
PBN.prototype.regray= function()
{
for (var i= 0; i < this.hi; i++)
if (this.hist[i].length == 4)
{
var h= this.hist[i];
this.draw.markClueDIJ(h[1],h[2],h[3], h[0] ? 2 : 1);
}
}
PBN.prototype.ungray= function()
{
for (var d= 0; d < 2; d++)
for (var i= 0; i < this.clue[d].length; i++)
for (var j= 0; j < this.clue[d][i].length; j++)
this.draw.markClueDIJ(d,i,j, 1);
}
PBN.prototype.hFill= function()
{
var minj, maxj, color;
if (this.bit[this.ati][this.atj] != 0) return;
for (minj= this.atj - 1; minj >= 0 && this.bit[this.ati][minj] == 0; minj--)
;
for (maxj= this.atj + 1;
maxj < this.n[TOP] && this.bit[this.ati][maxj] == 0;
maxj++)
;
if (minj < 0)
{
if (maxj >= this.n[TOP])
{
if (this.clue[SIDE][this.ati].length == 1 &&
this.clue[SIDE][this.ati][0].n == this.n[TOP])
color= this.clue[SIDE][this.ati][0].c;
else if (this.clue[SIDE][this.ati].length == 0)
color= 1;
else
return;
}
else
color= this.bit[this.ati][maxj];
}
else
{
color= this.bit[this.ati][minj];
if (maxj < this.n[TOP] && color != this.bit[this.ati][maxj]) return;
}
for (var j= minj+1; j < maxj; j++)
{
this.addHist(this.ati,j);
this.setState(this.ati,j, color, 1,0);
}
this.lineCheck(SIDE,this.ati,minj);
this.showLen();
}
PBN.prototype.vFill= function()
{
var mini, maxi, color;
if (this.bit[this.ati][this.atj] != 0) return;
for (mini= this.ati - 1; mini >= 0 && this.bit[mini][this.atj] == 0; mini--)
;
for (maxi= this.ati + 1;
maxi < this.n[SIDE] && this.bit[maxi][this.atj] == 0;
maxi++)
;
if (mini < 0)
{
if (maxi >= this.n[SIDE])
{
if (this.clue[TOP][this.atj].length == 1 &&
this.clue[TOP][this.atj][0].n == this.n[SIDE])
color= this.clue[TOP][this.atj][0].c;
else if (this.clue[TOP][this.atj].length == 0)
color= 1;
else
return;
}
else
color= this.bit[maxi][this.atj];
}
else
{
color= this.bit[mini][this.atj];
if (maxi < this.n[SIDE] && color != this.bit[maxi][this.atj]) return;
}
for (var i= mini+1; i < maxi; i++)
{
this.addHist(i,this.atj);
this.setState(i,this.atj, color, 0,1);
}
this.lineCheck(TOP,this.atj,mini);
this.showLen();
}
PBN.haveSave= 0;
PBN.toLoad= new Array();
PBN.prototype.initLoad= function()
{
switch (PBN.haveSave)
{
case 0:
PBN.toLoad.push(this);
loadcode('js/save.js');
PBN.haveSave= 1;
break;
case 1:
PBN.toLoad.push(this);
break;
case 2:
this.save= new Save(this);
this.save.loadSaved();
break;
}
}
PBN.saverLoaded= function()
{
PBN.haveSave= 2;
var pbn;
while ((pbn= PBN.toLoad.pop()) != null)
{
pbn.save= new Save(pbn);
pbn.save.loadSaved();
}
}
PBN.haveHelper= 0;
PBN.toHelp= new Array();
PBN.prototype.helper= function(hint)
{
switch (PBN.haveHelper)
{
case 0:
PBN.toHelp.push(hint);
PBN.toHelp.push(this);
loadcode(LineSolve.helper);
PBN.haveHelper= 1;
break;
case 1:
PBN.toHelp.push(hint);
PBN.toHelp.push(this);
break;
case 2:
if (!this.help) this.help= new Helper(this);
if (hint)
this.hinter();
else
this.help.helper();
break;
}
}
PBN.helperLoaded= function()
{
PBN.haveHelper= 2;
var pbn, hint;
while ((pbn= PBN.toHelp.pop()) != null)
{
hint= PBN.toHelp.pop();
if (!pbn.help) pbn.help= new Helper(pbn);
if (hint)
pbn.hinter();
else
pbn.help.helper();
}
}
PBN.prototype.setMouseFunc= function()
{
var nc= [1];
for (var i= 2; i <= PBN.nclr; i++)
if (this.usecolor[i])
nc.push(i);
if (nc.length == 1) this.usecolor[nc[0]= 2]= true;
while (nc.length < 3) nc.push(nc[nc.length-1]);
var aco= [1, 0, 2];
var aci= 0;
var f= this.btnfunc[0]= this.opt.btn0 - 0;
if (f == 3) this.btncolor[0]= 0;
if (f == 4) this.btncolor[0]= nc[aco[aci++]];
f= this.btnfunc[2]= this.opt.btn2 - 0;
if (f == 3) this.btncolor[2]= 0;
if (f == 4) this.btncolor[2]= nc[aco[aci++]];
f= this.btnfunc[1]= this.opt.btn1 - 0;
if (f == 3) this.btncolor[1]= 0;
if (f == 4) this.btncolor[1]= nc[aco[aci++]];
}
PBN.prototype.eyedropper= function(color)
{
this.btncolor[0]= color;
if (this.btnfunc[0] != 3) this.btnfunc[0]= 4;
if (this.panel) this.panel.ppimg[0].src= this.panel.potImage(0);
}
PBN.prototype.hinter= function()
{
this.draw.noCount(this.arrowD, this.arrowI);
for (var d= 0; d < 2; d++)
{
var i= this.help.doHint(d);
if (i >= 0)
{
this.draw.setArrow(d,i);
this.arrowD= d;
this.arrowI= i;
return;
}
}
this.status('No hint available');
}
