var w,h,g,g2,my={};function wordsearchMain(){var version='0.52';w=675;h=500;my.hiTiles=[]
my.drag={onQ:false,x:0,y:0}
my.bd=[];my.opt={wd:12,ht:12,wordN:15,overlapTgt:2,maxAttempts:3,fill:'match',case:'up',dirType:'wasdqezx',dict:'math'}
my.cases={up:{type:'up',name:'UPPER'},low:{type:'low',name:'lower'},title:{type:'title',name:'Title'},rand:{type:'rand',name:'rANdoM'},vary:{type:'vary',name:'vARiATIons'}}
my.dicts={math:{name:'Mathematics',type:'file',url:'math-large.txt',words:''},measure:{name:'Measurement',type:'file',url:'measure.txt',words:''},time:{name:'Time',type:'file',url:'time.txt',words:''},seasons:{name:'Seasons',type:'file',url:'seasons.txt',words:''},money:{name:'Money',type:'file',url:'money.txt',words:''},shapes:{name:'Shapes',type:'file',url:'shapes.txt',words:''},comp:{name:'Computers',type:'file',url:'computers.txt',words:''},energy:{name:'Energy',type:'file',url:'energy.txt',words:''},elements:{name:'Elements',type:'file',url:'elements.txt',words:''},science:{name:'Science',type:'file',url:'science.txt',words:''},plants:{name:'Plants',type:'file',url:'plants.txt',words:''},happy:{name:'Happy',type:'file',url:'happy.txt',words:''},positive:{name:'Positive',type:'file',url:'positive.txt',words:''},dogs:{name:'Dogs',type:'file',url:'dogs.txt',words:''},pals:{name:'Palindromes',type:'file',url:'palindromes.txt',words:''},country:{name:'Countries',type:'file',url:'country.txt',words:''},adjectives:{name:'Adjectives',type:'file',url:'adjectives.txt',words:''},adverbs:{name:'Adverbs',type:'file',url:'adverbs.txt',words:''},verbs:{name:'Verbs',type:'file',url:'verbs.txt',words:''},preps:{name:'Prepositions',type:'file',url:'prepositions.txt',words:''},prons:{name:'Pronouns',type:'file',url:'pronouns.txt',words:''},cons:{name:'Conjunctions',type:'file',url:'conjunctions.txt',words:''},num:{name:'Numbers',type:'num',url:'',words:''},rand:{name:'Random Letters',type:'ltr',url:'',words:''},}
my.fills={alpha:{type:'alpha',name:'Letters'},match:{type:'match',name:'Similar Letters'},blank:{type:'blank',name:'Blanks'}}
my.dirTypes={ds:{dirStr:'ds',name:'Down, right'},wasd:{dirStr:'wasd',name:'Up,down,left,right'},qezx:{dirStr:'qezx',name:'Diagonals'},wasdqezx:{dirStr:'wasdqezx',name:'All'}}
my.dirs={d:{id:'d',name:'horizontal',move:{x:1,y:0},dir:'right',compass:'E'},a:{id:'a',name:'horizontalBack',move:{x:-1,y:0},dir:'left',compass:'W'},s:{id:'s',name:'vertical',move:{x:0,y:1},dir:'down',compass:'S'},w:{id:'w',name:'verticalUp',move:{x:0,y:-1},dir:'up',compass:'N'},x:{id:'x',name:'diagonal',move:{x:1,y:1},dir:'',compass:'SE'},e:{id:'e',name:'diagonalUp',move:{x:1,y:-1},dir:'',compass:'NE'},q:{id:'q',name:'diagonalBack',move:{x:-1,y:-1},dir:'',compass:'NW'},z:{id:'z',name:'diagonalUpBack',move:{x:-1,y:1},dir:'',compass:'SW'},}
my.presets={short:{name:'Short',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},sml:{name:'Small',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},med:{name:'Medium',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},wide:{name:'Wide',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},lrg:{name:'Large',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},num:{name:'Numbers',cols:6,rows:6,diff:1,dict:'images/dict-short.txt'},}
my.clrs=["#0000ff","#00ff00","#ff8800","#660066","#99ff00","#0099ff","#00ff99","#9900ff","#ff0099","#006666","#666600","#990000","#009999","#ff9900","#ff0000","#003399","#ff00ff","#993333","#330099"];my.clrN=0
var s='';my.imgHome=(document.domain=='localhost')?'/mathsisfun/images/':'/images/'
my.sndHome=(document.domain=='localhost')?'/mathsisfun/images/sounds/':'/images/sounds/'
s+='';s+='';s+='';s+='';my.snds=[];my.soundQ=true
s+=''
s+='
';s+='
'
s+='
Title
'
s+='
'
s+='
'
s+=''
s+=''
my.snds=[];my.soundQ=true
s+=' '
s+=soundBtnHTML()
s+='
'
s+='
';s+='
';s+='
';s+=optPopHTML();s+='
';s+='
© 2019 MathsIsFun.com v'+version+'
';s+='
';s+='
';s+='';document.write(s);var el=document.getElementById('canvas1');var ratio=3;el.width=window.innerWidth*ratio
el.height=window.innerHeight*ratio
g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0);var el2=document.getElementById('canvas2');el2.width=window.innerWidth*ratio
el2.height=window.innerHeight*ratio
g2=el2.getContext("2d");g2.setTransform(ratio,0,0,ratio,0,0);el2.addEventListener('mousedown',function(ev){mouseDown(ev)})
el2.addEventListener('mouseup',function(){mouseUp()})
el2.addEventListener('touchstart',function(ev){var touch=ev.targetTouches[0];ev.clientX=touch.clientX;ev.clientY=touch.clientY;ev.touchQ=true;mouseDown(ev)})
el2.addEventListener('touchend',function(ev){mouseUp(ev)})
el2.addEventListener('mousemove',function(ev){mouseMove(ev)})
el2.addEventListener('touchmove',function(ev){console.log('touchmove')
var touch=ev.targetTouches[0];ev.clientX=touch.clientX;ev.clientY=touch.clientY;ev.touchQ=true;mouseMove(ev)})
my.wordStr='angle,area,Apex,Calculate,centimetre,Circle,Cone,decimal,degrees,diameter,Digit,equation,equilateral,Estimate,factor,Fraction,Hexagon,integer,isosceles,litre,multiple,negative,Pentagon,positive,prime,Prism,quotient,radius,Random,Spiral,times,Volume,Zero'
radioSet('fill',my.opt.fill)
radioSet('case',my.opt.case)
radioSet('dirType',my.opt.dirType)
radioSet('dict',my.opt.dict)
optPop()}
function dictLoad(){console.log('dictLoad',my.opt.dict)
var url=my.imgHome+'words/'+my.opt.dict.url
var rawFile=new XMLHttpRequest();rawFile.open("GET.html",url,true);rawFile.onreadystatechange=function(){if(rawFile.readyState===4){if(rawFile.status===200||rawFile.status==0){my.opt.dict.words=rawFile.responseText
if(my.opt.dict.words.length==0)my.opt.dict.words=my.wordStr
gameNew()}}}
rawFile.send(null);}
function tileAt(x,y){var xn=Math.floor((x-my.borderLt)/my.boxWd)
var yn=Math.floor((y-my.borderTp)/my.boxWd)
if(xn<0)return null
if(yn<0)return null
if(xn>=my.opt.wd)return null
if(yn>=my.opt.ht)return null
if(my.bd.length==0)return null
return my.bd[xn][yn]}
function boxLeft(xn){return my.borderLt+my.boxWd*xn}
function boxTop(yn){return my.borderTp+my.boxWd*yn}
function mouseDown(ev){console.log('mouseDown')
var rect=g.canvas.getBoundingClientRect();var x=ev.clientX-rect.left
var y=ev.clientY-rect.top
var tile=tileAt(x,y)
my.tileFrom=tile
my.tileTo=tile
my.drag.onQ=true
my.drag.x=x
my.drag.y=y
ev.preventDefault()
console.log('mousedown',my.drag)}
function mouseMove(ev){if(!my.drag.onQ)return
var rect=g.canvas.getBoundingClientRect();var x=ev.clientX-rect.left
var y=ev.clientY-rect.top
g.clearRect(0,0,g.canvas.width,g.canvas.height)
g.strokeStyle='black'
g.beginPath()
g.moveTo(my.drag.x,my.drag.y)
g.lineTo(x,y)
g.stroke()
var tile=tileAt(x,y)
if(my.tileFrom==null)return;my.tileTo=tile
wordHilite(my.tileFrom,my.tileTo);ev.preventDefault();}
function mouseUp(){my.drag.onQ=false
tilesHiliteClear()
g.clearRect(0,0,g.canvas.width,g.canvas.height)
var found=wordHilite(my.tileFrom,my.tileTo)
if(found==undefined)return
tilesHiliteClear()
var foundn=-1
for(var i=0;i=my.clrs.length)my.clrN=0
g2.lineWidth=my.boxWd*0.9
g2.lineCap="round"
g2.beginPath()
g2.moveTo(boxLeft(my.tileFrom.xn)+my.boxWd/2,boxTop(my.tileFrom.yn)+my.boxWd/2)
g2.lineTo(boxLeft(my.tileTo.xn)+my.boxWd/2,boxTop(my.tileTo.yn)+my.boxWd/2)
g2.stroke()
if(my.words.length==0){soundPlay('sndWin')
winAnim()}}
function parseWords(s){var LF=String.fromCharCode(10);var CR=String.fromCharCode(13);s=s.split(CR+LF).join(",");s=s.split(CR).join(",");s=s.split(LF).join(",");var words=s.split(",")
words.sort()
var goods=[]
var prevWord=''
var regex=new RegExp(/^[a-zA-Z0-9 ]+$/i);for(var i=0;i20)continue
if(word==prevWord)continue
prevWord=word
word=word.toLowerCase()
if(!regex.test(word))continue
goods.push(word)}
console.log('goods',words.length,goods.length)
console.log('goods',goods.join(','))
return goods}
function randomNums(){var maxLen=Math.min(my.opt.wd,my.opt.ht,10);console.log("maxLen="+maxLen);var words=[]
for(var i=0;i<50;i++){var len=randomInt(4,maxLen+1);words.push(randomNum(len,true));}
return words}
function randomNum(digits,decQ){var s="";for(var i=0;i0){var index=Math.floor(Math.random()*ctr);ctr--;var temp=arr[ctr];arr[ctr]=arr[index];arr[index]=temp;}
return arr;}
function gameNew(){switch(my.opt.dict.type){case 'file':if(my.opt.dict.words.length==0){dictLoad()
return}
break
case 'num':my.opt.dict.words=randomNums().join(',')
break
case 'ltr':my.opt.dict.words=randomStrings().join(',')
break
default:console.log('Dont know how to load the words')}
document.getElementById('title').innerHTML=my.opt.dict.name
var dh=Math.max(document.documentElement.clientHeight,window.innerHeight||0)
var dw=Math.max(document.documentElement.clientWidth,window.innerWidth||0)
my.vmin=Math.min(dh,dw)/100
console.log('my.vmin',my.vmin)
my.borderTp=11*my.vmin
my.borderLt=1*my.vmin
g.clearRect(0,0,g.canvas.width,g.canvas.height)
g2.clearRect(0,0,g2.canvas.width,g2.canvas.height)
var div=document.getElementById("board");while(div.firstChild){div.removeChild(div.firstChild);}
my.opt.orientations=my.opt.dirType.dirStr.split('')
console.log('my.opt',my.opt)
var words=parseWords(my.opt.dict.words)
shuffle(words)
var fwords=(my.opt.case=='vary')?wordsVar(words):wordsFilter(words,my.opt.wordN*4)
var p=new Puzzle()
var puzzle=p.fill(fwords);console.log('puzzle:',puzzle);my.bdSz=my.opt.wd
my.boxWd=Math.min(15,70/Math.max(my.opt.wd,my.opt.ht))*my.vmin
console.log('my',my)
my.bd=[]
for(var i=0;i1){if(Math.pow(word.length,2)>=my.opt.wordN){var wordComb=wordCapComb(word)
shuffle(wordComb)
return wordComb.slice(0,my.opt.wordN)}}}}
function wordsFilter(words,maxN){var wordCount=0;var maxLen=Math.max(my.opt.ht,my.opt.wd)
var currWords=[];console.log('maxLen',maxLen,my.opt)
for(var i=0;i1&&word.length<=maxLen){switch(my.opt.case.type){case 'up':word=word.toUpperCase()
break
case 'low':word=word.toLowerCase()
break
case 'title':word=word.charAt(0).toUpperCase()+word.slice(1)
break
case 'rand':var wordRand=''
for(var j=0;j=maxN)break;}}
console.log('currWords',currWords)
return currWords}
function wordCapComb(str){var n=str.length
var arr=[]
for(var i=0;i<(1<'
for(var i=0;i'}
s+=''
s+=''
for(var i=0;i'}
s+='
'
var div=document.getElementById('words')
div.innerHTML=s}
function tilesHiliteClear(){for(var i=0;i'+wordRev)
return{wordFwd:wordFwd,wordRev:wordRev}}
function Tile(wd,ht,xn,yn,val){this.wd=wd
this.ht=ht
this.xn=xn
this.yn=yn
this.val=val
this.bgClr='#fef'
this.fgClr='black'
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 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.clrSet=function(clr){this.bgClr=clr
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='black'
this.drawNum(this.val,fgClr)}
Tile.prototype.drawNum=function(v,clr){var g=this.g
g.clearRect(0,0,this.wd,this.ht)
g.strokeStyle='black'
g.lineWidth=1
g.fillStyle=this.bgClr
if(my.clrNumQ&&!this.origQ)g.fillStyle='#ffe'
g.beginPath()
var gap=1
g.rect(gap,gap,this.wd-2*gap,this.ht-2*gap)
g.fill()
if(my.clrNumQ)clr=my.clrs[v][1];g.fillStyle=clr
g.font=Math.round(this.wd*0.75)+'px Arial';g.textAlign='center'
g.beginPath()
g.fillText(v,Math.round(this.wd*0.5),Math.round(this.wd*0.8))
g.fill()}
Tile.prototype.hilite=function(onQ){if(onQ){this.bgClr='#bcf'}else{this.bgClr='#fef'}
this.draw()}
Tile.prototype.win=function(){this.bgClr='#ffe'
this.draw()}
Tile.prototype.setxy=function(lt,tp){this.div.style.left=lt+'px';this.div.style.top=tp+'px';}
var Puzzle=function(){}
Puzzle.prototype.fill=function(words){this.bd=[]
for(var i=0;i=my.opt.wordN)break}else{if(false){return null;}}}
my.words=my.words.sort(function(a,b){var nameA=a.toUpperCase();var nameB=b.toUpperCase();if(nameAnameB)return 1
return 0})
switch(my.opt.fill.type){case 'alpha':var ltrs='abcdefghijklmnoprstuvwy'
if(my.opt.case.type=='up')ltrs=ltrs.toUpperCase()
this.fillBlanks(ltrs);break
case 'match':var ltrs=''
for(var i=0;i=0)locs.push({x:i,y:j,move:dir.move,overlap:lap})}}}
return locs}
Puzzle.prototype.locCheck=function(word,xn,yn,move){var overlapN=0
var len=word.length-1
if(xn+len*move.x<0)return-1
if(xn+len*move.x>=my.opt.wd)return-1
if(yn+len*move.y<0)return-1
if(yn+len*move.y>=my.opt.wd)return-1
for(var i=0;i0){var n=Math.floor(Math.random()*ltrs.length);var ltr=ltrs[n];}
this.bd[i][j]=ltr}}}}
function winAnim(){console.log('winAnim',my.bd)
var ms=50
for(var i=0;i '
s+=' .speaker { height: 30px; width: 30px; position: relative; overflow: hidden; display: inline-block; vertical-align:top; } '
s+=' .speaker span { display: block; width: 9px; height: 9px; background-color:'+onClr+'; margin: 10px 0 0 1px; }'
s+=' .speaker span:after { content: ""; position: absolute; width: 0; height: 0; border-style: solid; border-color: transparent '+onClr+' transparent transparent; border-width: 10px 16px 10px 15px; left: -13px; top: 5px; }'
s+=' .speaker span:before { transform: rotate(45deg); border-radius: 0 60px 0 0; content: ""; position: absolute; width: 5px; height: 5px; border-style: double; border-color:'+onClr+'; border-width: 7px 7px 0 0; left: 18px; top: 9px; transition: all 0.2s ease-out; }'
s+=' .speaker:hover span:before { transform: scale(.8) translate(-3px, 0) rotate(42deg); }'
s+=' .speaker.mute span:before { transform: scale(.5) translate(-15px, 0) rotate(36deg); opacity: 0; }'
s+=' .speaker.mute span { background-color:'+offClr+'; }'
s+=' .speaker.mute span:after {border-color: transparent '+offClr+' transparent '+offClr+';}'
s+=' '
s+='
'
return s}
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 radioHTML(prompt,id,lbls,checkId){var s='';s+='';s+='
';s+=prompt;s+='
';s+='
';for(var i=0;i'
s+='';s+=lbl.name
s+=' ';}
s+='
';s+='
';return s;}
function radioHTMLa(prompt,id,lbls,checkId){var s='';s+='';s+='
';s+=prompt;s+='
';s+='
';for(var prop in lbls){var lbl=lbls[prop]
var idi=prop
var chkStr=(lbl.id==checkId)?' checked ':'';s+=' ';}
s+='
';s+='
';return s;}
function optPopHTML(){var s='';s+='';s+='
';s+='';s+=' '
s+='';s+='
'
s+='
';var sliders=[{id:'wd',name:'Width',val:my.opt.wd,min:1,max:16,step:1,fnName:'onJoe'},{id:'ht',name:'Height',val:my.opt.ht,min:1,max:16,step:1,fnName:'onJoe'},{id:'wordN',name:'Words',val:my.opt.wordN,min:1,max:20,step:1,fnName:'onJoe'},{id:'overlapTgt',name:'Overlap',val:my.opt.overlapTgt,min:0,max:5,step:1,fnName:'onJoe'},];for(var i=0;i
';if(i==2)s+='Try to fit:
'
s+=''+slider.name+':
'
s+='';s+=''+slider.val+'
';s+=''}
s+='
'
s+='';s+=radioHTMLa('Fill spaces:','fill',my.fills,'',0);s+='
'
s+='';s+=radioHTMLa('Letter case:','case',my.cases,'',0);s+='
'
s+='';s+=radioHTMLa('Directions:','dirType',my.dirTypes,'',0);s+='
'
s+='';s+=radioHTMLa('Words:','dict',my.dicts,'',0);s+='
'
s+='';return s;}
function optPop(){var pop=document.getElementById('optpop');pop.style.transitionDuration="0.3s";pop.style.opacity=1;pop.style.left='3vmin'}
function optYes(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.left='-120vmin';var div=document.querySelector('input[name="'+'dict'+'"]:checked')
my.opt.dict=my.dicts[div.id];var div=document.querySelector('input[name="'+'fill'+'"]:checked')
my.opt.fill=my.fills[div.id];var div=document.querySelector('input[name="'+'case'+'"]:checked')
my.opt.case=my.cases[div.id];var div=document.querySelector('input[name="'+'dirType'+'"]:checked')
my.opt.dirType=my.dirTypes[div.id];gameNew()}
function optNo(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.left='-999px';}
function onJoe(a,val,id){var div=document.getElementById(id)
div.innerHTML=val
my.opt[id]=parseInt(val)
console.log('onJoe',a,val,id,my.opt)}
function radioSet(name,setValue){var divs=document.querySelectorAll('input[name="'+name+'"]')
for(var i=0;i