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+="
"
for(let i=0;iLevel '+(i+1)+': '+l[2]+' from '+l[0]+' and '+l[1]+''}
s+=' '
s+="
Play "
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+="Reset "
s+="Menu "
s+='
'
s+="
"
s+=getSVG('drain')
s+='
'
s+="
"
s+=" "
s+=getSVG('tap')
s+='
'
s+='
'
s+=getSVG('puddle')
s+='
'
s+="
"
s+='
'
s+="
"
s+="
You did it!
"
s+="
'
s+="
Play Again "
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+="'}
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+="'
return s}}
class Mouse{constructor(el){console.log('new moose')
el.addEventListener('touchstart',this.onTouchStart.bind(this),false)
el.addEventListener('touchmove',this.onTouchMove.bind(this),false)
window.addEventListener('touchend',this.onTouchEnd.bind(this),false)
el.addEventListener('mousedown',this.onMouseDown.bind(this),false)
el.addEventListener('mousemove',this.onMouseMove.bind(this),false)
window.addEventListener('mouseup',this.onMouseUp.bind(this),false)
this.el=el
this.ratio=1
this.lastTouch=null}
onTouchStart(ev){console.log('onTouchStart',this)
let touch=ev.targetTouches[0]
this.lastTouch=touch
ev.clientX=touch.clientX
ev.clientY=touch.clientY
ev.touchQ=true
this.onMouseDown(ev)}
onTouchMove(ev){let touch=ev.targetTouches[0]
this.lastTouch=touch
ev.clientX=touch.clientX
ev.clientY=touch.clientY
ev.touchQ=true
this.onMouseMove(ev)}
onTouchEnd(ev){let touch=this.lastTouch
ev.clientX=touch.clientX
ev.clientY=touch.clientY
ev.touchQ=true
my.moose.onMouseUp(ev)}
onMouseDown(ev){let mouse=this.mousePos(ev)
console.log('moose doon',mouse.x,mouse.y,my.shapes)
my.drag.onQ=false
my.drag.n=this.hitFind(my.shapes,mouse)
if(my.drag.n>=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 '''{let s=''
s+=lbl.length>0?''+lbl+' ':''
s+='
',edit:()=>' >'+txt+'',inp:()=>'>'+(lbl.length>0?'':''),out:()=>' >'+txt+''+(lbl.length>0?'':''),rad:()=>{let s=''
s+='>\n'
for(let i=0;i \n'
s+=''+opts[i][1]+' \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()