var w,h,ratio,el,el2,g,g2,my={};function gomokuMain(mode){var version='0.64';my.typ=typeof mode!=='undefined'?mode:'bla';my.last={xn:-1,yn:-1}
my.hdrHt=65
w=Math.min(500,window.innerWidth,window.innerHeight-my.hdrHt)
h=w+my.hdrHt
my.bdSzs=[{title:'9 by 9',sz:9},{title:'13 by 13',sz:13},{title:'19 by 19',sz:19}];my.bdSz=19
my.game={board:[]}
my.players=[{name:'empty'},{name:'Black',clr:'black',lvl:0},{name:'White',clr:'white',lvl:1},];my.playerNo=1
my.player=my.players[my.playerNo]
my.lvls=[{name:'Human',title:'Human'},{name:'Easy',title:'AI Easy',depth:0,bestn:3},{name:'Medium',title:'AI Medium',depth:1,bestn:2},{name:'Hard',title:'AI Hard',depth:2,bestn:0},]
var s='';my.sndHome=(document.domain=='localhost')?'/mathsisfun/images/sounds/':'/images/sounds/'
s+=' '
s+=' '
s+=' '
my.snds=[];my.imgHome=(document.domain=='localhost')?'/mathsisfun/games/images/':'/games/images/'
s+='
';s+='
';s+='
';s+='
New ';s+='
Options ';s+='
'
my.soundQ=true
s+=soundBtnHTML()
s+='
';s+=popHTML()
s+='
';s+='
© 2018 MathsIsFun.com v'+version+'
';s+='
';document.write(s);ratio=3;el=document.getElementById('canvas1');el.width=w*ratio;el.height=h*ratio;el.style.width=w+"px";el.style.height=h+"px";g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0)
el2=document.getElementById('canvas2');el2.width=w*ratio;el2.height=h*ratio;el2.style.width=w+"px";el2.style.height=h+"px";g2=el2.getContext("2d");g2.setTransform(ratio,0,0,ratio,0,0)
el2.addEventListener('touchstart',touchStart,false);el2.addEventListener("mousemove",mouseMove,false);el2.addEventListener("mousedown",mouseDown,false);my.playQ=true
gameNew()}
function gameNew(){clearTimeout(my.timeid)
var pcWd=Math.min(60,w/my.bdSz,(h-my.hdrHt)/my.bdSz)
var bdWd=pcWd*(my.bdSz-1)
my.rect={lt:pcWd/2,tp:pcWd/2+my.hdrHt,wd:bdWd,ht:bdWd}
my.rect.rt=my.rect.lt+my.rect.wd
my.rect.bt=my.rect.tp+my.rect.ht
my.rect.pcWd=pcWd
console.log('my.rect',my,my.rect)
my.moveN=0
var player=my.players[my.playerNo]
document.getElementById('info').style.color=player.clr
document.getElementById('info').innerHTML=player.name+" goes first"
var b=[]
for(var i=0;i0){my.playQ=false
var mid=Math.round(my.bdSz/2)-1
my.game.board[mid][mid]=my.playerNo
soundPlay('sndmove')
turnNext()}else{my.playQ=true}}
function boardDraw(){var rowN=my.bdSz
var colN=my.bdSz
g.clearRect(0,0,g.canvas.width,g.canvas.height)
g.lineWidth=0.7
var bit=0.8
for(var i=0;i';s+='Black: '
s+=radioHTML('','blackLvl',my.lvls,'',my.players[1].lvl)
s+='
'
s+='White: '
s+=radioHTML('','whiteLvl',my.lvls,'',my.players[2].lvl)
s+='
'
s+=' '
s+=' '
s+='Board Size: '
s+=radioHTML('','bdSz',my.bdSzs,'',2);s+='
'
s+=' '
s+='';s+='(will start new game) '
s+='✔ ';s+='✘ ';s+='
';s+='';return s;}
function radioHTML(prompt,id,lbls,func,n){var s='';s+='';s+=prompt;for(var i=0;i';s+=''+lbl.title+' ';s+=' '}
s+='
';return s;}
function posLegal(xn,yn){if(xn<0)return false
if(yn<0)return false
if(xn>=my.bdSz)return false
if(yn>=my.bdSz)return false
if(my.game.board[xn][yn]>0)return false
return true}
function turnNext(){my.playQ=false
var c=new AI()
if(c.full(my.game.board)){boardDraw()
document.getElementById('info').style.color='red'
document.getElementById('info').innerHTML="A Draw!"
my.playQ=false
soundPlay('sndlose')
return}
if(c.terminalState(my.game.board)){boardDraw()
var player=my.players[my.playerNo]
document.getElementById('info').style.color=player.clr
document.getElementById('info').innerHTML=player.name+" Wins!"
my.playQ=false
if(player.lvl==0){soundPlay('sndwin')}else{soundPlay('sndlose')}
return}
my.playerNo=(my.playerNo==1)?2:1
var player=my.players[my.playerNo]
document.getElementById('info').style.color=player.clr
document.getElementById('info').innerHTML=player.name
boardDraw()
my.moveN++
if(my.players[my.playerNo].lvl>0){my.playQ=false
my.timeid=setTimeout(aiMove,1000)}else{my.playQ=true}}
function aiMove(){var c=new AI()
var move=c.getMove(my.game.board)
console.log('move',move)
if(typeof move==="undefined"){boardDraw()
document.getElementById('info').style.color='red'
document.getElementById('info').innerHTML="AI stuck!"
my.playQ=false
soundPlay('sndlose')
return}
var xn=move[0]
var yn=move[1]
my.last={xn:xn,yn:yn}
my.game.board[xn][yn]=my.playerNo
soundPlay('sndmove')
turnNext()
my.last={xn:-1,yn:-1}
setTimeout(boardDraw,2000);}
CanvasRenderingContext2D.prototype.pieceDraw=function(xn,yn,type,hoverq){var size=my.rect.pcWd/2
var x=my.rect.lt+xn*my.rect.pcWd
var y=my.rect.tp+yn*my.rect.pcWd
if(hoverq){this.beginPath()
this.fillStyle='hsla(60,90%,10%,0.2)'
this.arc(x+size*0.35,y+size*0.35,size*1.1,0,Math.PI*2,true)
this.fill()
this.beginPath()
this.lineWidth=4
this.strokeStyle='hsla(50,100%,90%,0.3)'
this.arc(x,y,size*1.1,0,Math.PI*2,true)
this.stroke()}else{this.beginPath()
this.fillStyle='hsla(240,0%,0%,0.3)'
this.arc(x+size*0.13,y+size*0.13,size*1.03,0,Math.PI*2,true)
this.fill()}
let hiliteQ=(xn==my.last.xn&&yn==my.last.yn)
if(hiliteQ){this.beginPath()
this.fillStyle='hsla(240,100%,50%,0.3)'
this.arc(x,y,size*1.15,0,Math.PI*2,true)
this.fill()}
var gradient
if(type==1){this.beginPath()
gradient=this.createRadialGradient(x+size*0.3,y+size*0.2,0,x,y,size*1.6);gradient.addColorStop(0,'hsla(240,10%,50%,1)');gradient.addColorStop(1,'black');this.fillStyle=gradient
this.arc(x,y,size,0,Math.PI*2,true)
this.fill()
this.beginPath()
gradient=this.createRadialGradient(x-size*0.5,y-size*0.5,0,x,y,size*1.6);gradient.addColorStop(0,'hsla(0,0%,70%,1)');gradient.addColorStop(0.3,'hsla(0,100%,100%,0)');this.fillStyle=gradient
this.arc(x,y,size*1,0,Math.PI*2,true)
this.fill()}else{this.beginPath()
gradient=this.createRadialGradient(x-size*0.4,y-size*0.6,0,x,y,size*1.4);gradient.addColorStop(0,'white');gradient.addColorStop(0.4,'hsla(240,100%,93%,1)');this.fillStyle=gradient
this.arc(x,y,size,0,Math.PI*2,true)
this.fill()}}
CanvasRenderingContext2D.prototype.ball=function(size,clr,hiClr,x,y){this.beginPath();var gradient=this.createRadialGradient(x-size*0.4,y-size*0.6,0,x,y,size*1.4);gradient.addColorStop(0,hiClr);gradient.addColorStop(0.6,clr);this.fillStyle=gradient;this.arc(x,y,size,0,Math.PI*2,true);this.fill();}
function soundBtnHTML(){var onClr='#444'
var offClr='#888'
var s=''
s+=''
s+='
'
return s}
function soundPlay(id,simulQ){if(!my.soundQ)return
simulQ=typeof simulQ!=='undefined'?simulQ:false
if(simulQ){if(id.length>0)document.getElementById(id).play()}else{my.snds.push(id)
soundPlayQueue(id)}}
function soundPlayQueue(id){var div=document.getElementById(my.snds[0])
div.play()
div.onended=function(){my.snds.shift();if(my.snds.length>0)soundPlayQueue(my.snds[0]);};}
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 AI(){this.minimaxCache={};}
AI.prototype.nearbyMoves=function(grid){var nearby=[];for(var i=0;iscore){score=moveScore;position=[i,j];}
if(moveScore>bestlow){if(bests.length==0){bests.push({pos:[i,j],score:moveScore})}else{for(var n=0;nbests[n].score){bests.splice(n,0,{pos:[i,j],score:moveScore})
break}}
if(bests.length>4)bests.length=4}
bestlow=bests[bests.length-1].score}}}}
this.minimaxCache={};console.log('bests final',bestsFmt(bests),position)
var choosen=Math.floor(Math.random()*lvl.bestn)
choosen=Math.min(choosen,bests.length-1)
position=bests[choosen].pos
var elapsed=(performance.now()-timeStt)/1000
console.log('position',player.name,choosen,elapsed,position)
return position;}
function bestsFmt(bests){var s=''
for(var i=0;icoord!==offsetCoord);if((j+4)in grid&&!grid[i][j+offsetCoord]&&grid[i][j+otherCoords[0]]===color&&grid[i][j+otherCoords[1]]===color&&grid[i][j+otherCoords[2]]===color&&grid[i][j+otherCoords[3]]===color)return[i,j+offsetCoord];if((i+4)in grid&&!grid[i+offsetCoord][j]&&grid[i+otherCoords[0]][j]===color&&grid[i+otherCoords[1]][j]===color&&grid[i+otherCoords[2]][j]===color&&grid[i+otherCoords[3]][j]===color)return[i+offsetCoord,j];if((i+4)in grid&&(j+4)in grid&&!grid[i+offsetCoord][j+offsetCoord]&&grid[i+otherCoords[0]][j+otherCoords[0]]===color&&grid[i+otherCoords[1]][j+otherCoords[1]]===color&&grid[i+otherCoords[2]][j+otherCoords[2]]===color&&grid[i+otherCoords[3]][j+otherCoords[3]]===color)return[i+offsetCoord,j+offsetCoord];if((i-4)in grid&&(j+4)in grid&&!grid[i-offsetCoord][j+offsetCoord]&&grid[i-otherCoords[0]][j+otherCoords[0]]===color&&grid[i-otherCoords[1]][j+otherCoords[1]]===color&&grid[i-otherCoords[2]][j+otherCoords[2]]===color&&grid[i-otherCoords[3]][j+otherCoords[3]]===color)return[i-offsetCoord,j+offsetCoord];}}}}
AI.prototype.full=function(grid){for(var i=0;i