let my={} let version='0.91' let units='liters' let moves=0,minMoves=0,waterOffset=0 let w=480 let h=360 my.shapes=[] my.zIndex=1 let playQ=false let dragQ=false function init(){my.drag={n:0,onq:false,holdX:0,holdY:0} my.opts={name:'user'} my.tapDrop={x:40,y:110,wd:100,ht:250} my.drainDrop={x:370,y:40,wd:100,ht:280} my.tapFlowHt=0 my.tapFlowInc=3 my.lvls=[[5,3,2,4],[5,4,2,4],[5,3,1,4],[5,3,4,6],[4,3,2,0],[7,5,6,0],[8,5,4,10],[9,4,6,0],[10,7,9,0],[11,6,8,14],[11,7,5,12],[11,9,8,14],[12,11,6,14],[13,11,8,0],[7,3,2,0],] docInsert(getHTML()) makeShapes() my.waterPattern=gettapPattern() showIntro() my.can=new Can('can',w,h,2) my.moose=new Mouse(my.can.el)} function getHTML(){let s='' s+='
' s+='' s+="
" s+="
The Jugs Puzzle
" s+='

' s+="
" s+='
You have 2 jugs of different sizes & an unlimited supply of water. Can you measure the exact amount of water needed?
' s+='
' s+='
' s+="' s+="" s+='
' s+="
" s+="You need exactly "+units+' in one jug ' s+=wrap({id:'dragTip',pos:'abs',style:'left:140px; top:90px; color:red; font:22px Arial;'},'DRAG the jugs to fill and empty') s+="
" s+="" s+="" s+='
' s+="
" s+=getSVG('drain') s+='
' s+="
" s+="" s+=getSVG('tap') s+='
' s+='
' s+=getSVG('puddle') s+='
' s+="
" s+='
' s+="' s+='
0
' s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`) s+='
' return s} function gettapPattern(){let canvas=document.getElementById('tap-canvas') let g=canvas.getContext('2d') g.fillStyle='rgba(0,200,255,0.8)' for(let i=0;i<50;i++){g.beginPath() g.arc(Math.random()*canvas.width,Math.random()*canvas.height,Math.random()*4,0,Math.PI*2) g.fill()} g.fillStyle='rgba(0,100,255,0.8)' g.fillRect(0,0,canvas.width,canvas.height) let pattern=g.createPattern(canvas,'repeat') g.clearRect(0,0,canvas.width,canvas.height) return pattern} function getJugsHTML(){let s='' function jugN(n,sz){let letter=['a','b','c','d'][n] s+="
" s+="
" s+="
" s+="
" s+='
' s+='
'} for(let i=0;i<2;i++){jugN(i,my.shapes[i].size*15)} return s} function makeShapes(){let alphas=['a','b'] my.shapes=[] for(let i=0;i<2;i++){my.shapes.push(new Shape(160+i*100,130,0,0,alphas[i]))}} function Shape(x,y,size,value,letter){this.x=x this.y=y this.size=size this.value=value this.letter=letter this.wd=65 this.ht=30*this.size console.log('Shape',size,value,letter,this.ht) let el=document.createElement('canvas') el.style.position='absolute' document.getElementById('main10').appendChild(el) let ratio=2 el.width=(this.wd+5)*ratio el.height=this.ht*ratio el.style.width=this.wd+5+'px' el.style.height=this.ht+'px' el.style.zIndex=my.zIndex++ this.el=el this.g=el.getContext('2d') this.g.setTransform(ratio,0,0,ratio,0,0)} Shape.prototype.moveMe=function(){this.el.style.left=this.x+'px' this.el.style.top=this.y+'px' this.jugEl.style.left=this.x+'px' this.jugEl.style.top=this.y+'px'} Shape.prototype.drawMe=function(){this.wd=65 this.ht=15*this.size let g=this.g g.clearRect(0,0,this.el.width,this.el.height) let fraction=this.value/this.size this.jugEl=document.getElementById('jug-'+this.letter) this.waterEl=document.getElementById('jug-'+this.letter+'-water') let max=Number(this.jugEl.clientHeight) max=Math.min(max,this.jugEl.clientHeight-2) this.waterEl.style.height=max*fraction+'px' this.label=document.getElementById('jug-'+this.letter+'-label') this.label.innerHTML=Math.round(this.value)+'
'+units} function animStt(){console.log('animStt',my.anim) anim()} function anim(){let animQ=false let g,canvas let speed=0.08 if(my.anim.type=='tap'){let shape=my.anim.toShape document.getElementById('dragTip').style.display='none' canvas=document.getElementById('tap-canvas') g=canvas.getContext('2d') my.anim.g=g my.tapFlowHt+=my.tapFlowInc if(my.tapFlowHt>10)my.tapFlowInc=-2 if(my.tapFlowHt<0)my.tapFlowInc=4 waterOffset=shape.y+shape.ht-140+my.tapFlowHt-shape.value*15 g.fillStyle=my.waterPattern g.translate(0,waterOffset) g.clearRect(0,0,canvas.width,300) g.fillRect(0,0,canvas.width,-waterOffset) g.translate(0,-waterOffset) if(shape.value0){shape.value-=speed shape.drawMe() animQ=true}} if(my.anim.type=='tfr'){let fromShape=my.anim.fromShape let toShape=my.anim.toShape console.log('tfr',fromShape,toShape) if(fromShape.value>0&&toShape.value" s+="" s+='' return s} if(name=='tap'){s+="" s+="" s+='' return s} if(name=='puddle'){s+="" s+="=0){console.log('drrragin!',my.drag.n) let shape=my.shapes[my.drag.n] my.drag.holdX=mouse.x-shape.x my.drag.holdY=mouse.y-shape.y shape.shadQ=true document.getElementById('jug-'+shape.letter).style.zIndex=my.zIndex++ my.drag.onQ=true} ev.preventDefault()} onMouseMove(ev){let mouse=this.mousePos(ev) if(my.drag.onQ){let shape=my.shapes[my.drag.n] let pt={x:mouse.x-my.drag.holdX,y:mouse.y-my.drag.holdY} shape.x=pt.x shape.y=pt.y shape.moveMe()}else{if(this.hitFind(my.shapes,mouse)>=0){document.body.style.cursor='pointer'}else{document.body.style.cursor='default'}}} onMouseUp(ev){let mouse=this.mousePos(ev) if(my.drag.onQ){my.drag.onQ=false let shape=my.shapes[my.drag.n] if(this.hitTest(my.tapDrop,mouse)){moves++ my.anim={type:'tap',toShape:shape} animStt() return} if(this.hitTest(my.drainDrop,mouse)){moves++ my.anim={type:'drain',fromShape:shape} animStt() return} for(let i=0;ishape.x+shape.wd)return false if(mouse.y>shape.y+shape.ht)return false return true} hit2Test(shape1,shape2){if(shape1.x+shape2.wdshape2.x+shape2.wd)return false if(shape1.y+shape1.htshape2.y+shape2.ht)return false return true}} function optGet(name){let val=localStorage.getItem(`mif.${name}`) if(val==null)val=my.opts[name] return val} function optSet(name,val){localStorage.setItem(`mif.${name}`,val) my.opts[name]=val} function getJSQueryVar(varName,defaultVal){let scripts=document.getElementsByTagName('script') let lastScript=scripts[scripts.length-1] let scriptName=lastScript.src let bits=scriptName.split('?') if(bits.length<2)return defaultVal let query=bits[1] console.log('query: ',query) let vars=query.split('&') for(let i=0;i{if(cls.length==0)cls='btn' return '{if(cls.length==0)cls='radio' return '0?(s+=' onclick="'+fn+'"'):'')},sel:()=>{if(cls.length==0)cls='select' let s='' s+=lbl.length>0?'':''),out:()=>' >'+txt+''+(lbl.length>0?'':''),rad:()=>{let s='' s+='>\n' for(let i=0;i\n' s+='
\n'} s+='' return s},sel:()=>{let s='' s+='>\n' for(let i=0;i'+opt.descr+'\n'} s+='' if(lbl.length>0)s+='' return s},sld:()=>'>',}[tag]()||'' s+='\n' return s.trim()} init()