'
s+=''
return s}
function optpop(){let pop=document.getElementById('optpop')
pop.style.transitionDuration='0.3s'
pop.style.opacity=1
pop.style.zIndex=12
pop.style.left=(w-320)/2+'px'}
function optYes(){let pop=document.getElementById('optpop')
pop.style.opacity=0
pop.style.zIndex=1
pop.style.left='-999px'
newGame()}
function optNo(){let pop=document.getElementById('optpop')
pop.style.opacity=0
pop.style.zIndex=1
pop.style.left='-999px'}
function updatePiecesCount(){let tiles=my.bd.getTiles()
my.players[0].pieces=0
my.players[1].pieces=0
for(let y=0;y0){if(my.soundQ)document.getElementById('sndmove').play()
endTurn()}
my.hovered.onQ=false
redraw()}
function tie(){msg('Tied Game!')
let half=(my.nx*my.ny)/2
my.players[0].pieces=half
my.players[1].pieces=half
pieceCountShow()}
function win(player){msg(my.players[player].color+' Wins!')
let pieceTot=my.players[0].pieces+my.players[1].pieces
let emptyCount=my.nx*my.ny-pieceTot
my.players[player].pieces+=emptyCount
pieceCountShow()
my.players[player].score++
document.getElementById('player-0-score').innerHTML=my.players[0].score
document.getElementById('player-1-score').innerHTML=my.players[1].score}
function pieceCountShow(){document.getElementById('player-0-pieces').innerHTML=my.players[0].pieces
document.getElementById('player-1-pieces').innerHTML=my.players[1].pieces}
function msg(s){let msgDiv=document.getElementById('message')
msgDiv.innerHTML=s}
function endTurn(){updatePiecesCount()
my.playerN=my.playerN==0?1:0
msg(my.players[my.playerN].color+"'s turn",0)
if(!my.bd.canMakeMove(my.playerN)){msg(my.players[my.playerN].color+' cannot move, loses turn',0)
my.playerN=my.playerN==0?1:0}
if(!my.bd.canMakeMove(0)&&!my.bd.canMakeMove(1)){if(my.players[0].pieces==my.players[1].pieces){tie()}else{win(my.players[0].pieces>my.players[1].pieces?0:1)}}
if(my.players[my.playerN].ai){setTimeout(aiTurn,1200)}}
function aiTurn(){let res=my.bd.makeBestMove(my.difficulty,my.playerN)
my.prevBd=my.bd.bd
console.log('aiTurn',res)
if(res.n>0){if(my.soundQ)document.getElementById('sndmove').play()
endTurn()}
redraw()
g.strokeStyle=my.style.moveHi
g.lineWidth=3
g.strokeRect(res.i*my.tileSz,res.j*my.tileSz,my.tileSz,my.tileSz)
setTimeout(redraw,2000)}
function toTileCoords(x,y){x=Math.min(my.nx-1,Math.max(0,Math.floor(x/my.tileSz)))
y=Math.min(my.ny-1,Math.max(0,Math.floor(y/my.tileSz)))
return{x:x,y:y,}}
function newGame(){resetBoard()
my.difficulty=document.getElementById('difficulty').selectedIndex+1
console.log('my.difficulty',my.difficulty)
let player0=document.getElementById('player-0')
my.players[0].ai=player0.options[player0.selectedIndex].text=='Computer'
let player1=document.getElementById('player-1')
my.players[1].ai=player1.options[player1.selectedIndex].text=='Computer'
updatePiecesCount()
redraw()
msg(my.players[my.playerN].color+"'s turn",0)
if(my.players[my.playerN].ai)aiTurn()}
function drawGrid(){g.lineWidth=1
let clrs=my.style.edgeClrs
for(let j=0;j0){this.moveCount--
let bd=this.hist[this.moveCount].bd
for(let x=0;x-1){return false}
for(let ddx=-1;ddx<=1;ddx++){for(let ddy=-1;ddy<=1;ddy++){if(this.getFld(nn+ddx,mm+ddy,ll)==1-player){let cc=0,dd=1
do{dd++
cc=this.getFld(nn+dd*ddx,mm+dd*ddy,ll)}while(cc==1-player)
if(cc==player){return true}}}}
return false}
canMakeMove(player){return this.able2Move(player)}
init(){for(let i=0;i=my.nx)return-1
if(mm<0)return-1
if(mm>=my.ny)return-1
return this.Fld[nn][mm][ll]}
makeRealMove(nn,mm,p){console.log('makeRealMove',nn,mm,p)
let player=p
if(this.Fld[nn][mm][0]>-1){return 0}
let flipN=0
let hh=new Array(9)
let ll=-1
for(let ddx=-1;ddx<=1;ddx++){for(let ddy=-1;ddy<=1;ddy++){ll++
hh[ll]=0
if(this.getFld(nn+ddx,mm+ddy,0)==1-player){let cc
let dd=1
do{dd++
cc=this.getFld(nn+dd*ddx,mm+dd*ddy,0)}while(cc==1-player)
if(cc==player){hh[ll]=dd
do{dd--
this.Fld[nn+dd*ddx][mm+dd*ddy][0]=player
flipN++}while(dd>1)}}}}
if(flipN==0)return 0
this.Fld[nn][mm][0]=player
this.moveCount++
this.maxMoveCount=this.moveCount
this.histUpdate(player,nn,mm)
return flipN}
histUpdate(player,nn,mm){if(this.hist.length<=this.moveCount)this.hist[this.moveCount]=[]
let clone=[]
for(let x=0;x0){for(ddx=0;ddx-1){return 0}
for(ddx=-1;ddx<=1;ddx++){for(ddy=-1;ddy<=1;ddy++){if(this.getFld(nn+ddx,mm+ddy,rr)==1-player){dd=1
do{dd++
cc=this.getFld(nn+dd*ddx,mm+dd*ddy,rr)}while(cc==1-player)
if(cc==player){do{dd--
this.Fld[nn+dd*ddx][mm+dd*ddy][rr]=player
if(rr>0){my.currVal+=this.FVal[nn+dd*ddx][mm+dd*ddy]+MoveVal}
flipN++}while(dd>1)}}}}
if(flipN>0){this.Fld[nn][mm][rr]=player}
return flipN}
doBestMove(difficulty,p){let player=p
let D=difficulty
if(this.moveCount>=my.nx*my.ny-10){D++}
D=Math.min(D++,2)
this.getBestMove(0,D,player)
let flipN=this.makeRealMove(this.best_i,this.best_j,player)
console.log('doBestMove',difficulty,p,flipN)
return{i:this.best_i,j:this.best_j,n:flipN}}
getBestMove(depth,ll,p){let player=p
let best_val=-10000
let nvalid=0
let rr=depth+1
let MoveVal=1
let act_val=0
if(this.moveCount>40){MoveVal=this.moveCount-40}
for(let i=0;i0){nvalid++
act_val=(5+rr)*(my.currVal+this.FVal[i][j]+MoveVal)
if(rr0){return best_val+10*nvalid}else{return 0}}
bdDebug(){let s=''
for(let j=0;j'}
document.getElementById('debug').innerHTML=s}
able2Move(player){for(let 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: blue; margin: 10px 0 0 1px; }'
s+=' .speaker span:after { content: ""; position: absolute; width: 0; height: 0; border-style: solid; border-color: transparent blue 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: blue; 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+=' '
s+='
'
return s}
function soundToggle(){let btn='sound'
if(my.soundQ){my.soundQ=false
document.getElementById(btn).classList.add('mute')}else{my.soundQ=true
document.getElementById(btn).classList.remove('mute')}}
my.opts={name:'user'}
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 '