let w,h,ratio,g,my={} function init(){let version='0.642' my.nx=getJSQueryVar('nx',8) my.ny=getJSQueryVar('ny',8) let bdOffsetY=10 let playerColors=['Red','Blue'] my.hovered={x:0,y:0,onQ:false} my.playerN=0 my.players=[{color:playerColors[0],ai:false,pieces:0,score:0},{color:playerColors[1],ai:true,pieces:0,score:0},] my.currVal=0 w=360 h=540 my.tileSz=Math.min((w-bdOffsetY*2)/my.nx,(h-80)/my.ny,50) my.bdWd=my.nx*my.tileSz my.bdHt=my.ny*my.tileSz console.log('my',my) my.bd=new Board() let s='' my.sndHome=document.domain=='localhost'?'/mathsisfun/images/sounds/':'/images/sounds/' s+='' s+='' s+='
' s+=optPopHTML() s+='
' s+='
' s+='' s+=' ' s+='' s+='' s+=' ' s+='' s+=' ' s+=' ' my.soundQ=true s+=soundBtnHTML() s+='
' s+='
Welcome
' s+=wrap({tag:'out',style:'width:100px; border-radius:25px; padding:5px 5px;text-align:center; margin:auto;'},'',' vs ','') s+='
' s+='' s+='
' s+=wrap({cls:'copyrt',style:'left:5px; bottom:-12px'},`© 2021 MathsIsFun.com v${version}`) s+='
' s+='
' docInsert(s) resetBoard() let el=document.getElementById('can') ratio=3 el.width=my.bdWd*ratio el.height=my.bdHt*ratio el.style.width=my.bdWd+'px' el.style.height=my.bdHt+'px' g=el.getContext('2d') g.setTransform(ratio,0,0,ratio,0,0) el.onmousemove=function(evt){if(my.players[my.playerN].ai)return let tile=toTileCoords(evt.offsetX,evt.offsetY) if(tile.x!=my.hovered.x||tile.y!=my.hovered.y){my.hovered.x=tile.x my.hovered.y=tile.y my.hovered.onQ=true my.hovered.clr=my.bd.isValidMove(my.hovered.x,my.hovered.y,my.playerN)?my.style.hoverClr:'transparent' redraw()}} el.onclick=function(evt){if(my.players[my.playerN].ai)return pickTile(my.hovered.x,my.hovered.y)} newGame()} function resetBoard(){my.bd.reset()} function optPopHTML(){let s='' s+='
' s+='
' s+='
' let lblStyle='display:inline-block; width:100px; text-align:right; margin-right:5px; font:18px Arial;' s+='
' s+='Difficulty:' s+='' s+='
' s+='
' s+='
' for(let i=0;i' s+=''+p.color+': ' s+='' s+='Wins: ' s+='0' s+='' s+='
'} s+='
' s+='
' s+='' s+='' s+='
' 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{if(cls.length==0)cls='btn' return '