var w,h,my={};function tictactoewsMain(){var version='0.54';console.log('ver',version) w=360;my.borderTp=220 h=w+my.borderTp+15 my.opts={name:'user'} my.bdSzs=[3,4,5,6,7,8] my.winLens=[3,4,5] my.replaceQ=false my.playerTypes=[{name:'Human',aiQ:false,sockQ:false},{name:'Human (Remote)',aiQ:false,sockQ:true},{name:'Computer (Beginner)',aiQ:true,levelMax:1,timeMax:3000,sockQ:false},{name:'Computer (Medium)',aiQ:true,levelMax:3,timeMax:3000,sockQ:false},{name:'Computer (Challenging)',aiQ:true,levelMax:4,timeMax:10000,sockQ:false},{name:'Computer (Hard)',aiQ:true,levelMax:6,timeMax:10000,sockQ:false}] my.players=[{name:"O",type:my.playerTypes[0],score:0},{name:"X",type:my.playerTypes[0],score:0}];my.playerN=0 my.playerStartN=0 my.sockQ=false my.sock=new Sock('tic') my.sockPlayerN=0 my.nick='Me' my.partnerQ=false my.AI=new AI() my.gameOverQ=false var s='';my.sndHome='../images/sounds/index.html' if(document.domain=='localhost')my.sndHome='../node/images/sounds/index.html' if(document.domain=='www.mathsisfun.com')my.sndHome='../images/sounds/index.html' console.log('sounds',document.domain,my.sndHome) s+='';s+='';s+='' s+='' s+='' my.snds=[];s+='' s+='
';s+='
' s+='
' s+='' s+='' my.soundQ=true s+=' ' s+=soundBtnHTML() s+='
' s+='
' s+='
' s+='
' s+='
';s+='
'+optGet('name')+'
' s+=' vs ' s+='
Them
' s+='
' s+='';s+='
Player X
' s+='
';s+=optPopHTML();s+='';s+='
© 2019 MathsIsFun.com v'+version+'
';s+='
';document.write(s);this.clrs=[["Blue",'#0000FF'],["Red",'#FF0000'],["Black",'#000000'],["Green",'#00cc00'],["Orange",'#FFA500'],["Slate Blue",'#6A5ACD'],["Lime",'#00FF00'],["Spring Green",'#00FF7F'],["Teal",'#008080'],["Gold",'#ffd700'],["Med Purple",'#aa00aa'],["Light Blue",'#ADD8E6'],["Navy",'#000080'],["Purple",'#800080'],["Dark SeaGreen",'#8FBC8F']];my.clrNum=0;radioSet('bdSz',my.bdSzs,3) radioSet('winLen',my.winLens,3) optPop()} function gameNew(rmtAskQ){if(false){my.sockQ=false my.sock=new Sock() my.sockPlayerN=0 my.nick='Me' my.partnerQ=false} rmtAskQ=typeof rmtAskQ!=='undefined'?rmtAskQ:false console.log('gameNew rmtAskQ='+rmtAskQ) my.bdSz=Math.floor(document.querySelector('input[name="bdSz"]:checked').value) my.winLen=Math.floor(document.querySelector('input[name="winLen"]:checked').value) optSet('name',document.getElementById('name').value) my.code=document.getElementById('code').value my.publicQ=!document.getElementById("privateQ").checked console.log('bdSz,winLen,publicQ',my.bdSz,my.winLen,my.publicQ) my.sockQ=false my.localPlayerN=0 for(var i=0;i0){my.gameOverQ=true msg(my.players[my.playerN].name+' wins!') winShow(line) my.players[my.playerN].score++ if(my.localPlayerN==my.playerN){soundPlay('sndWin')}else{soundPlay('sndFail')} var s='' for(var i=0;i=my.bdSz)return-1 if(yn>=my.bdSz)return-1 return bd[xn][yn]} function bdFmt(bd){var s='' for(var yn=0;yn0){if(playerPrev==this.aiplayer){return 20-depth;}else{return depth-20;}} if(depth>my.players[this.aiplayer].type.levelMax)return getRandomInt(-5,5) var elapsed=performance.now()-this.stt if(depth>3&&elapsed>my.players[this.aiplayer].type.timeMax)return 0 depth+=1;var availableMoves=this.getAvailableMoves(bd);if(availableMoves.length==0){return getRandomInt(-5,5)} var move,result;if(playerN===this.aiplayer){for(var i=0;ialpha){alpha=result;if(depth==1){this.choice=move;}}else if(alpha>=beta){return alpha;}} return alpha;}else{for(var i=0;i';s+='';} s+='';return s;} function radioSet(id,lbls,setValue){for(var i=0;i';s+='
'+p.name+' player:
';s+='Type: ';s+=getDropdownHTML(my.playerTypes,'','playerType'+i,i);s+='';} s+='';s+='
';s+=radioHTML('Board Size','bdSz',my.bdSzs,'');s+=radioHTML('Winning Length','winLen',my.winLens,'');s+='
' var url=(document.domain=='localhost')?'http://localhost:3001':'https://mathbro.com:3001' s+='
';s+='Server: ' s+='';s+='
' my.code=nameRand() s+='
';s+='Name (optional): ' s+='';s+='
' s+='Code: ' s+='';s+='
' s+='Partner must have code: ' s+='' s+='
' s+='
';s+='';s+='';s+='
';s+='';return s;} function optPop(){var pop=document.getElementById('optpop');pop.style.transitionDuration="0.3s";pop.style.opacity=1;pop.style.zIndex=12;pop.style.left=(w-400)/2+'px';} function optYes(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.zIndex=1;pop.style.left='-999px';gameNew()} function optNo(){var pop=document.getElementById('optpop');pop.style.opacity=0;pop.style.zIndex=1;pop.style.left='-999px';} function getDropdownHTML(opts,funcName,id,chkNo){var s='';s+='';return s;} function soundBtnHTML(){var onClr='blue' var offClr='#bbb' 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]) try{div.play()}catch(e){console.log('soundPlayQueue fail',my.snds)} 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 Timer(g,rad,secs,clr,funcEnd){this.g=g;this.rad=rad;this.secs=secs;this.clr=clr;this.funcEnd=funcEnd;this.x=rad;this.y=rad;this.stt=performance.now();this.stopQ=false;} Timer.prototype.update=function(){};Timer.prototype.restart=function(secs){this.secs=secs;this.stt=performance.now();this.stopQ=false;requestAnimationFrame(this.draw.bind(this));};Timer.prototype.more=function(secs){this.stt+=secs*1000;};Timer.prototype.stop=function(){this.stopQ=true;};Timer.prototype.draw=function(){if(this.stopQ)return;var now=performance.now();var elapsed=now-this.stt;var ratio=Math.min(1,elapsed/this.secs/1000);var g=this.g;g.beginPath();g.fillStyle="#def";g.arc(this.x,this.y,this.rad,0,2*Math.PI);g.fill();g.beginPath();g.moveTo(this.x,this.y);g.fillStyle=this.clr;g.arc(this.x,this.y,this.rad,-Math.PI/2,ratio*2*Math.PI-Math.PI/2);g.fill();if(ratio<1){requestAnimationFrame(this.draw.bind(this));}else{this.funcEnd();}};function Tile(wd,ht,lt,tp){this.wd=wd this.ht=ht this.bgClr='#def' this.fgClr='black' this.playerN=-1 var div=document.createElement("div");div.style.width=wd+'px' div.style.height=ht+'px' div.style.position='absolute' div.style.top=tp+'px' div.style.left=lt+'px' this.div=div var me=this div.addEventListener('mouseover',function(){if(!activeQ())return if(my.replaceQ){if(me.playerN!=my.playerN){}}else{if(me.playerN==-1){me.drawPlayer(my.playerN,'#bcf')}}}) div.addEventListener('mouseleave',function(){if(!activeQ())return if(my.replaceQ){if(me.playerN!=my.playerN){}}else{if(me.playerN==-1){me.drawPlayer(-1)}}}) div.addEventListener('click',function(){if(!activeQ())return if(my.replaceQ){if(me.playerN!=my.playerN){me.playerN=my.playerN me.draw() update(me) if(my.sockQ)my.sock.moveSend(me.xn,me.yn,me.playerN)}}else{if(me.playerN==-1){me.playerN=my.playerN me.draw() update(me) if(my.sockQ)my.sock.moveSend(me.xn,me.yn,me.playerN)}}}) var can=document.createElement('canvas');can.style.position="absolute";can.style.top='0px' can.style.left='0px' can.style.width='100%' can.style.height='100%' can.width=wd can.height=ht this.g=can.getContext("2d");div.appendChild(can) document.getElementById('board').appendChild(div);this.draw()} Tile.prototype.draw=function(){var fgClr='darkblue' if(this.playerN==1)fgClr='darkred' this.drawPlayer(this.playerN,fgClr)} Tile.prototype.drawPlayer=function(playerN,fgClr){fgClr=typeof fgClr!=='undefined'?fgClr:'black' this.fgClr=fgClr var g=this.g g.clearRect(0,0,this.wd,this.ht) g.strokeStyle='black' g.lineWidth=1 g.fillStyle=this.bgClr g.beginPath() g.rect(2,2,this.wd-4,this.ht-4) g.stroke() g.fill() if(playerN>=0){g.strokeStyle=this.fgClr switch(my.players[playerN].name){case 'O':g.lineWidth=2 g.beginPath() g.arc(this.wd/2,this.ht/2,this.wd/3,0,2*Math.PI) g.stroke() break case 'X':g.lineWidth=2 var edge=this.wd*0.2 g.beginPath() g.moveTo(edge,edge) g.lineTo(this.wd-edge,this.wd-edge) g.stroke() g.beginPath() g.moveTo(edge,this.wd-edge) g.lineTo(this.wd-edge,edge) g.stroke() break default:}}} Tile.prototype.win=function(){this.bgClr='#ffe' this.draw()} Tile.prototype.setxy=function(lt,tp){this.div.style.left=lt+'px';this.div.style.top=tp+'px';} function optGet(name){var val=localStorage.getItem(`remote.${name}`) if(val==null)val=my.opts[name] return val} function optSet(name,val){localStorage.setItem(`remote.${name}`,val) my.opts[name]=val} class Sock{constructor(gameType){this.socket=null this.queue=[] this.lines=[] this.gameType=gameType} send(msg){if(this.socket==null){this.queue.push(msg) this.connect()} if(this.socket.readyState===1){this.socket.send(msg)}} waitForConnection(callback,interval){if(this.socket.readyState===1){callback();}else{var that=this;interval*=2 setTimeout(function(){that.waitForConnection(callback,interval);},interval);}} connect(){var that=this var socket=new WebSocket('wss://www.mathbro.com:3002/echo');socket.onopen=function(ev){console.log("[open] Connection established");console.log("Sending to server");for(var i=0;i