new file: Files/flashplayer_32_sa.exe new file: favicon.ico new file: globe.gif new file: imgs/download.png new file: imgs/zuck.jpg new file: index.html new file: other.ico new file: script.js new file: site.webmanifest new file: sitemap.html new file: styles/backround.css new file: styles/border.css new file: styles/fonts/Titillium_Web/OFL.txt new file: styles/fonts/Titillium_Web/TitilliumWeb-Black.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Bold.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Italic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Light.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Regular.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf new file: styles/fonts/webfontkit-20221027-163353/generator_config.txt new file: styles/fonts/webfontkit-20221027-163353/specimen_files/grid_12-825-55-15.css new file: styles/fonts/webfontkit-20221027-163353/specimen_files/specimen_stylesheet.css new file: styles/fonts/webfontkit-20221027-163353/stylesheet.css new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-demo.html new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff2 new file: styles/fonts/webfontkit-20221027-165950/generator_config.txt new file: styles/fonts/webfontkit-20221027-165950/specimen_files/grid_12-825-55-15.css new file: styles/fonts/webfontkit-20221027-165950/specimen_files/specimen_stylesheet.css new file: styles/fonts/webfontkit-20221027-165950/stylesheet.css new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-demo.html new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff2 new file: styles/style.css new file: tools/2048/.gitignore new file: tools/2048/.jshintrc new file: tools/2048/CONTRIBUTING.md new file: tools/2048/LICENSE.txt new file: tools/2048/README.md new file: tools/2048/Rakefile new file: tools/2048/favicon.ico new file: tools/2048/index.html new file: tools/2048/js/animframe_polyfill.js new file: tools/2048/js/application.js new file: tools/2048/js/bind_polyfill.js new file: tools/2048/js/classlist_polyfill.js new file: tools/2048/js/game_manager.js new file: tools/2048/js/grid.js new file: tools/2048/js/html_actuator.js new file: tools/2048/js/keyboard_input_manager.js new file: tools/2048/js/local_storage_manager.js new file: tools/2048/js/tile.js new file: tools/2048/meta/apple-touch-icon.png new file: tools/webretro/cores/neocd_libretro.js new file: tools/webretro/cores/neocd_libretro.wasm new file: tools/webretro/cores/nestopia_libretro.js new file: tools/webretro/cores/nestopia_libretro.wasm new file: tools/webretro/cores/o2em_libretro.js new file: tools/webretro/cores/o2em_libretro.wasm new file: tools/webretro/cores/opera_libretro.js new file: tools/webretro/cores/opera_libretro.wasm
490 lines
24 KiB
JavaScript
490 lines
24 KiB
JavaScript
var w,h,my={};function battleshipMain(){var version='0.52';w=360;h=500;my.shipSets=[[2,3,4,5],[2,3,3,4,5],[2,3,4,5,6],[6]];my.shipSetN=2
|
|
my.bdSzs=[8,10,12];my.playerTypes=[{name:'Human',aiQ:false},{name:'Computer (Beginner)',aiQ:true,levelMax:1,timeMax:3000},{name:'Computer (Medium)',aiQ:true,levelMax:3,timeMax:3000},{name:'Computer (Challenging)',aiQ:true,levelMax:4,timeMax:10000},{name:'Computer (Hard)',aiQ:true,levelMax:6,timeMax:10000}];my.clrs0=[["Light Blue Grey",'#D8D8e8'],["Silver",'#d0d0d0'],["Grey 1",'#a898a8'],["Grey 2",'#b8a8a8']];my.clrs1=[["Blue 1",'#bDD8E6'],["Sky Blue",'#97CEEB'],["Aqua",'#aaffff'],["Antique White",'#FAEBD7'],["Blue 2",'#7A9ACD']];my.players=[new Player('Human','blue','rgba(0,0,255,0.3)','board0',my.clrs0),new Player('Computer','red','rgba(255,0,0,0.4)','board1',my.clrs1)]
|
|
my.playerN=0
|
|
my.playerStartN=0
|
|
my.borderTp=123
|
|
var s='';my.sndHome=(document.domain=='localhost')?'/mathsisfun/images/sounds/':'/images/sounds/'
|
|
s+='<audio id="sndWin" src="'+my.sndHome+'kids-cheer.mp3" preload="auto"></audio>';s+='<audio id="sndWinAI" src="'+my.sndHome+'computer-happy.mp3" preload="auto"></audio>';s+='<audio id="sndHit" src="'+my.sndHome+'boom-quiet.mp3" preload="auto"></audio>';s+='<audio id="sndMiss" src="'+my.sndHome+'splash-quiet.mp3" preload="auto"></audio>';s+='<audio id="sndSunk" src="'+my.sndHome+'water-echo.mp3" preload="auto"></audio>';my.snds=[];s+='<style>'
|
|
s+='.btn { display: inline-block; position: relative; text-align: center; margin: 2px; text-decoration: none; font: bold 14px/25px Arial, sans-serif; color: #268; border: 1px solid #88aaff; border-radius: 10px;cursor: pointer; background: linear-gradient(to top right, rgba(170,190,255,1) 0%, rgba(255,255,255,1) 100%); outline-style:none;}'
|
|
s+='.btn:hover { background: linear-gradient(to top, rgba(255,255,0,1) 0%, rgba(255,255,255,1) 100%); }'
|
|
s+='.yy { border: solid 2px #eeeeaa; background: linear-gradient(to top, rgba(255,220,130,1) 0%, rgba(255,255,255,1) 100%); }'
|
|
s+='.hi { border: solid 2px #eeeeaa; background: linear-gradient(to top, rgba(130,220,255,1) 0%, rgba(255,255,255,1) 100%); }'
|
|
s+='.lo { border: solid 1px #888888; background: linear-gradient(to top, rgba(170,170,170,1) 0%, rgba(205,205,205,1) 100%); }'
|
|
s+='</style>'
|
|
s+='<div id="main" style="position:relative; width:'+w+'px; min-height:'+h+'px; margin:auto; display:block; border: 1px solid black; border-radius: 10px;">';s+='<div id="top" style="font: 24px Arial; text-align:center; margin-top:3px; height:95px; ">'
|
|
s+='<div id="btns" style="font: 18px Arial;">'
|
|
s+='<button id="optBtn" type="button" style="z-index:2;" class="btn" onclick="optPop()">Options</button>'
|
|
s+='<button id="newBtn" type="button" style="z-index:2;" class="btn" onclick="gameNew()">New Game</button>'
|
|
my.soundQ=true
|
|
s+=' '
|
|
s+=soundBtnHTML()
|
|
s+='<div id="scores" style="font: 18px Arial; background-color:#def; margin:2px;"></div>'
|
|
s+='<button id="readyBtn" type="button" style="z-index:2;" class="btn" onclick="playerReady()">Ready!</button>'
|
|
s+='<button id="nextBtn" type="button" style="z-index:2;" class="btn" onclick="next()">Next</button>'
|
|
s+='</div>'
|
|
s+='<div id="msg" style="font: 24px Arial; text-align:center; margin-top:3px;">Player X</div>'
|
|
s+='</div>'
|
|
s+='<div id="board0" style="transition: opacity 2s linear;"></div>';s+='<div id="board1" style="transition: opacity 2s linear;"></div>';s+=optPopHTML();s+='<div style="font: 11px Arial; color: #6600cc; position:absolute; bottom:5px; left:5px; text-align:center;">© 2020 MathsIsFun.com v'+version+'</div>';s+='</div>';document.write(s);document.getElementById('scores').innerHTML='Human:0 Computer:0'
|
|
gameNew()}
|
|
function gameNew(){my.placedQ=false
|
|
my.activeQ=false
|
|
my.nextQ=false
|
|
my.bdSz=Math.floor(document.querySelector('input[name="bdSz"]:checked').value)
|
|
console.log('bdSz',my.bdSz)
|
|
var id=document.querySelector('input[name="shipSet"]:checked').id
|
|
my.shipSetN=(id.match(/\d+$/)||[]).pop();console.log('my.shipSetN',my.shipSetN)
|
|
my.boxWd=Math.min(70,(Math.min(w,h-90))/my.bdSz)
|
|
for(var i=0;i<my.players.length;i++){var p=my.players[i]
|
|
var div=document.getElementById("playerType"+i);p.type=my.playerTypes[div.selectedIndex]
|
|
p.bdClear()}
|
|
for(var i=0;i<my.players.length;i++){var p=my.players[i]
|
|
if(p.type.aiQ){p.bd=bdMake(p.bgClr,p.bdName,p.clrs)
|
|
p.autoPlace()}else{p.bd=bdMake(p.bgClr,p.bdName,p.clrs)
|
|
p.autoPlace()
|
|
p.shipsDrag(true)}}
|
|
my.playerN=my.playerStartN
|
|
my.playerN=0
|
|
my.players[my.playerN].bdShow(false)
|
|
my.players[my.playerN].shipsShow(true)
|
|
my.players[1-my.playerN].bdShow(true)
|
|
my.players[1-my.playerN].shipsShow(true)
|
|
msg(my.players[my.playerN].name+"'s Turn")
|
|
if(my.players[my.playerN].type.aiQ){console.log('gameNew ai move')
|
|
var xn=randomInt(0,my.bdSz-1)
|
|
var yn=randomInt(0,my.bdSz-1)
|
|
var tile=my.players[my.playerN].bd[xn][yn]
|
|
tile.playerN=my.playerN
|
|
tile.draw()
|
|
update(tile)}
|
|
btnVis('readyBtn',true)
|
|
btnVis('nextBtn',false)
|
|
placeCheck()
|
|
msg('Place your ships')}
|
|
function msg(s){document.getElementById('msg').innerHTML=s}
|
|
function placeCheck(){console.log('placeCheck')
|
|
var p=my.players[1]
|
|
console.log('p1',p)
|
|
var ships=p.ships
|
|
var othrs=[]
|
|
var outsideN=0
|
|
var collideN=0
|
|
for(var i=0;i<ships.length;i++){var ship=ships[i];if(!ship.insideQ()){outsideN++}
|
|
if(ship.intersectsQ(othrs)){collideN++}
|
|
othrs.push(ship)}
|
|
var s=''
|
|
if(outsideN>0)s+='Ship Outside! '
|
|
if(collideN>0)s+='Ship Collision!'
|
|
msg(s)
|
|
if(s.length>0){btnVis('readyBtn',false)}else{btnVis('readyBtn',true)}
|
|
console.log('placeCheck',s)}
|
|
function bdMake(clr,bdName,clrs){my.borderLt=(w-my.bdSz*my.boxWd)/2
|
|
var pts=getRandomPts(my.bdSz,my.bdSz,3,clrs);var bd=[]
|
|
for(var xn=0;xn<my.bdSz;xn++){bd[xn]=[]
|
|
for(var yn=0;yn<my.bdSz;yn++){var clr=getClrAt(pts,xn,yn);var tile=new Tile(my.boxWd,my.boxWd,boxLeft(xn),boxTop(yn),clr,bdName)
|
|
tile.xn=xn;tile.yn=yn;bd[xn][yn]=tile}}
|
|
return bd}
|
|
function boxLeft(xn){return my.borderLt+my.boxWd*xn}
|
|
function boxTop(yn){return my.borderTp+my.boxWd*yn}
|
|
function update(tile){var hiti=hitCheck(tile)
|
|
console.log('hiti=',hiti)
|
|
tile.hit(hiti>=0)
|
|
var p=my.players[my.playerN];var winQ=p.winCheck()
|
|
if(winQ){msg(p.name+' wins!')
|
|
if(p.type.aiQ){soundPlay('sndWinAI')}else{soundPlay('sndWin')}
|
|
my.activeQ=false
|
|
btnVis('nextBtn',false)
|
|
my.players[my.playerN].score++
|
|
var s=''
|
|
for(var i=0;i<my.players.length;i++){var p=my.players[i]
|
|
s+=p.name+':'+p.score+' '}
|
|
document.getElementById('scores').innerHTML=s}else{my.nextQ=false
|
|
btnVis('nextBtn',true)
|
|
setTimeout(nextIfNotAlready,2000)}}
|
|
function nextIfNotAlready(){if(!my.nextQ){btnVis('nextBtn',false)
|
|
next()}}
|
|
function btnVis(name,onQ){var div=document.getElementById(name)
|
|
if(onQ){div.style.visibility='visible'}else{div.style.visibility='hidden'}}
|
|
function hitCheck(tile){var p0=my.players[my.playerN]
|
|
return p0.hitCheck(tile.xn,tile.yn)}
|
|
function playerReady(){my.placedQ=true
|
|
my.activeQ=true
|
|
var p0=my.players[0]
|
|
var p1=my.players[1]
|
|
p0.shipsDrag(false)
|
|
p0.bdShow(true)
|
|
p0.shipsShow(false)
|
|
p1.bdShow(false)
|
|
p1.shipsShow(false)
|
|
btnVis('readyBtn',false)
|
|
btnVis('nextBtn',false)
|
|
my.nextQ=false
|
|
msg('Fire!')}
|
|
function next(){my.nextQ=true
|
|
btnVis('nextBtn',false)
|
|
my.players[my.playerN].bdShow(false)
|
|
my.playerN=1-my.playerN
|
|
my.players[my.playerN].bdShow(true)
|
|
var msgStr=my.players[my.playerN].name+"'s Turn"
|
|
if(my.players[my.playerN].type.aiQ){my.activeQ=false
|
|
setTimeout(doAI,500)}else{my.activeQ=true}
|
|
msg(msgStr)}
|
|
function doAI(){my.players[my.playerN].doAI()}
|
|
function bdPlayer(bd,xn,yn){if(xn<0)return-1
|
|
if(yn<0)return-1
|
|
if(xn>=my.bdSz)return-1
|
|
if(yn>=my.bdSz)return-1
|
|
return bd[xn][yn]}
|
|
function bdFmt(bd){var s=''
|
|
for(var yn=0;yn<my.bdSz;yn++){for(var xn=0;xn<my.bdSz;xn++){var playerN=bd[xn][yn]
|
|
if(playerN==-1){s+='~'}else{s+=+playerN}}
|
|
s+='\n'}
|
|
return s}
|
|
function radioHTML(prompt,id,lbls,func,chkN){var s='';s+='<div style="display:inline-block; border: 1px solid white; border-radius:5px; padding:3px; margin:3px; background-xnor:rgba(255,255,255,0.5);">';s+=prompt;for(var i=0;i<lbls.length;i++){var lbl=lbls[i];var idi=id+i;var chkStr=(i==chkN)?' checked ':'';s+='<input id="'+idi+'" type="radio" name="'+id+'" value="'+lbl+'" onclick="'+func+'('+i+');" autocomplete="off" '+chkStr+' >';s+='<label for="'+idi+'">'+lbl+' </label>';}
|
|
s+='</div>';return s;}
|
|
function randomInt(min,max){return Math.floor(Math.random()*(max-min+1))+min;}
|
|
function optPopHTML(){var s='';s+='<div id="optpop" style="position:absolute; left:-500px; top:0px; width:360px; padding: 5px; border-radius: 9px; background-color: #bcd; box-shadow: 10px 10px 5px 0px rgba(40,40,40,0.75); transition: all linear 0.3s; opacity:0; text-align: center; font: 14px Arial;">';s+='<div id="optInside" style=" display:none; margin: 5px auto 5px auto;">';for(var i=0;i<my.players.length;i++){var p=my.players[i];s+='<div style="font: 15px Verdana; color:white; background-color: #57a; padding: 0 0 15px 0; border-radius: 10px; border: 3px 3px 3px 3px; margin:3px; ">';s+='<div style="font: 20px Verdana; color:lightblue; padding:7px 0 6px 0;">'+p.name+' player:</div>';s+='Type: ';s+=dropdownHTML(my.playerTypes,'','playerType'+i,i);s+='</div>';}
|
|
s+='</div>';s+='<div style="position:relative; margin:auto; text-align:center; font:14px Arial; background-color:lightblue; margin: 5px 0 1px 0; padding: 5px 0 5px 0;">';s+=radioHTML('Board Size','bdSz',my.bdSzs,'',0);s+='</div>'
|
|
s+='<div style="position:relative; margin:auto; text-align:center; font:14px Arial; background-color:lightblue; margin: 5px 0 1px 0; padding: 5px 0 5px 0;">';s+=radioHTML('Ships','shipSet',my.shipSets,'',0);s+='</div>'
|
|
s+='<div style="float:right; margin: 0 0 5px 10px;">';s+='(starts new game)'
|
|
s+='<button id="optYes" onclick="optYes()" style="z-index:2; font: 22px Arial;" class="btn" >✔</button>';s+=' '
|
|
s+='<button onclick="optNo()" style="z-index:2; font: 22px Arial;" class="btn" >✘</button>';s+='</div>';s+='</div>';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 dropdownHTML(opts,funcName,id,chkN){var s='';s+='<select id="'+id+'" style="font: 14px Arial; color: #6600cc; background: white; padding: 1px;line-height:30px; border-radius: 5px;">';for(var i=0;i<opts.length;i++){var idStr=id+i;var chkStr=i==chkN?'selected':'';s+='<option id="'+idStr+'" value="'+opts[i].name+'" style="height:21px;" '+chkStr+' >'+opts[i].name+'</option>';}
|
|
s+='</select>';return s;}
|
|
function soundBtnHTML(){var s=''
|
|
s+='<style> '
|
|
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+=' .speaker.mute span { background-color: #bbb; }'
|
|
s+=' .speaker.mute span:after {border-color: transparent #bbb transparent #bbb;}'
|
|
s+=' </style>'
|
|
s+='<div id="sound" onClick="soundToggle()" class="speaker"><span></span></div>'
|
|
return s}
|
|
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 soundPlay(name,simulQ){if(!my.soundQ)return
|
|
simulQ=typeof simulQ!=='undefined'?simulQ:true
|
|
if(simulQ){if(name.length>0){var div=document.getElementById(name)
|
|
if(div.currentTime>0&&div.currentTime<div.duration){console.log('soundPlay cloned',div.currentTime,div.duration)
|
|
div.cloneNode(true).play()}else{div.play()}}}else{my.snds.push(name)
|
|
soundPlayQueue()}}
|
|
function soundPlayQueue(){var div=document.getElementById(my.snds[0])
|
|
div.play()
|
|
div.onended=function(){my.snds.shift();if(my.snds.length>0)soundPlayQueue();};}
|
|
function Tile(wd,ht,lt,tp,clr,bdName){this.wd=wd
|
|
this.ht=ht
|
|
this.xn=Math.round(lt/my.boxWd)
|
|
this.yn=Math.round(tp/my.boxWd)
|
|
this.bgClr=clr
|
|
this.fgClr='black'
|
|
this.status='clear'
|
|
this.sunkQ=false
|
|
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(!my.activeQ)return
|
|
if(me.status!='clear')return
|
|
me.drawStatus('over')})
|
|
div.addEventListener('mouseleave',function(){if(!my.activeQ)return
|
|
if(me.status!='clear')return
|
|
if(!me.onQ)return
|
|
me.drawStatus()})
|
|
div.addEventListener('click',function(){if(!my.activeQ)return
|
|
if(me.status!='clear')return
|
|
my.activeQ=false
|
|
update(me)})
|
|
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(bdName).appendChild(div);this.draw()}
|
|
Tile.prototype.hit=function(onQ){if(onQ){this.status='hit'
|
|
soundPlay('sndHit')}else{this.status='miss'
|
|
soundPlay('sndMiss')}
|
|
this.draw()}
|
|
Tile.prototype.draw=function(onQ){this.onQ=typeof onQ!=='undefined'?onQ:true
|
|
if(this.onQ){this.div.style.pointerEvents="auto";var fgClr=(this.playerN==0)?'darkblue':'darkred'
|
|
this.drawStatus(this.status,fgClr)}else{var g=this.g
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)
|
|
this.div.style.pointerEvents="none";}}
|
|
Tile.prototype.drawStatus=function(status,fgClr){status=typeof status!=='undefined'?status:this.status
|
|
this.fgClr=typeof fgClr!=='undefined'?fgClr:'black'
|
|
var g=this.g
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)
|
|
g.fillStyle=this.bgClr
|
|
g.beginPath()
|
|
g.rect(0,0,this.wd,this.ht)
|
|
g.fill()
|
|
g.strokeStyle=this.fgClr
|
|
switch(status){case 'over':g.strokeStyle='blue'
|
|
g.lineWidth=2
|
|
g.beginPath()
|
|
g.arc(this.wd/2,this.ht/2,this.wd/3,0,2*Math.PI)
|
|
g.stroke()
|
|
break
|
|
case 'hit':g.strokeStyle='black'
|
|
g.fillStyle='red'
|
|
g.lineWidth=3
|
|
g.beginPath()
|
|
g.arc(this.wd/2,this.ht/2,this.wd/3,0,2*Math.PI)
|
|
g.stroke()
|
|
g.fill()
|
|
break
|
|
case 'miss':g.strokeStyle='rgba(255,255,255,0.3)'
|
|
g.fillStyle='rgba(0,0,255,0.2)'
|
|
g.lineWidth=3
|
|
g.beginPath()
|
|
g.arc(this.wd/2,this.ht/2,this.wd/3,0,2*Math.PI)
|
|
g.stroke()
|
|
g.fill()
|
|
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 Player(name,clr,bgClr,bdName,clrs){this.name=name
|
|
this.clr=clr
|
|
this.clrs=clrs
|
|
this.bgClr=bgClr
|
|
this.bdName=bdName
|
|
this.score=0
|
|
this.ships=[];this.bd=[];}
|
|
Player.prototype.bestMove=function(){var dirs=[[0,-1],[1,0],[0,1],[-1,0]]
|
|
var best={score:-9,xn:0,yn:0}
|
|
for(var i=0;i<my.bdSz;i++){for(var j=0;j<my.bdSz;j++){var scoreTot=0
|
|
scoreTot+=Math.random()
|
|
var t0=tileType(this.bd,i,j)
|
|
if(t0!=0)scoreTot-=99
|
|
for(var dn=0;dn<dirs.length;dn++){var score=0
|
|
var dir=dirs[dn]
|
|
var t1=tileType(this.bd,i+dir[0],j+dir[1])
|
|
var t2=tileType(this.bd,i+2*dir[0],j+2*dir[1])
|
|
switch(t1){case 0:break
|
|
case 1:score+=6
|
|
if(t2==1){score+=6}
|
|
break
|
|
case 2:score-=2
|
|
break
|
|
case 9:score-=2
|
|
break
|
|
default:}
|
|
scoreTot+=score}
|
|
if(scoreTot>best.score)best={score:scoreTot,xn:i,yn:j}}}
|
|
return best}
|
|
function tileType(bd,xn,yn){if(xn<0)return 0
|
|
if(yn<0)return 0
|
|
if(xn>=my.bdSz)return 0
|
|
if(yn>=my.bdSz)return 0
|
|
var tile=bd[xn][yn]
|
|
if(tile.sunkQ)return 9
|
|
if(tile.status=='hit')return 1
|
|
if(tile.status=='miss')return 2
|
|
return 0}
|
|
Player.prototype.autoPlace=function(){this.ships=[];my.zIndex=1;var shipLens=my.shipSets[my.shipSetN];for(var i=0;i<shipLens.length;i++){var len=shipLens[i]
|
|
var ship=new Ship('a',len,this.bgClr,this.bdName)
|
|
var OKQ=false
|
|
var tryN=0
|
|
do{ship.pos.x=randomInt(0,my.bdSz-1)
|
|
ship.pos.y=randomInt(0,my.bdSz-1)
|
|
if(Math.random()<0.5){ship.xn=len
|
|
ship.yn=1}else{ship.xn=1
|
|
ship.yn=len}
|
|
OKQ=ship.validPosQ(this.ships)}while(!OKQ&&tryN++<100)
|
|
ship.setSize()
|
|
this.ships.push(ship)}}
|
|
Player.prototype.bdClear=function(){var div=document.getElementById(this.bdName);while(div.firstChild){div.removeChild(div.firstChild);}}
|
|
Player.prototype.bdShow=function(onQ){var div=document.getElementById(this.bdName)
|
|
if(onQ){div.style.display='block'}else{div.style.display='none'}}
|
|
Player.prototype.hitCheck=function(xn,yn){for(var i=0;i<this.ships.length;i++){var ship=this.ships[i]
|
|
if(ship.hitQ(xn,yn)){console.log('HIT on ship',i)
|
|
ship.hit(this.bd)
|
|
return i}}
|
|
return-1}
|
|
Player.prototype.shipsShow=function(onQ){console.log('shipsShow',this.name,onQ)
|
|
for(var i=0;i<this.ships.length;i++){var ship=this.ships[i]
|
|
ship.show(onQ)}}
|
|
Player.prototype.shipsDrag=function(onQ){for(var i=0;i<this.ships.length;i++){var ship=this.ships[i]
|
|
if(onQ){ship.div.style.pointerEvents="auto";}else{ship.div.style.pointerEvents="none";}}}
|
|
Player.prototype.winCheck=function(){for(var i=0;i<this.ships.length;i++){var ship=this.ships[i]
|
|
console.log('winCheck',ship.hitN,ship.sz)
|
|
if(ship.hitN<ship.sz)return false}
|
|
return true}
|
|
Player.prototype.doAI=function(){var best=this.bestMove()
|
|
console.log('doAI best',best)
|
|
var tile=this.bd[best.xn][best.yn]
|
|
tile.playerN=my.playerN
|
|
tile.draw()
|
|
update(tile)}
|
|
function Ship(name,sz,clr,bdName){this.name=name
|
|
this.sz=sz
|
|
this.clr=clr
|
|
this.hitN=0
|
|
this.sunkQ=false
|
|
this.bdName=bdName
|
|
this.showQ=true
|
|
this.xn=sz
|
|
this.yn=1
|
|
this.pos={x:0,y:0}
|
|
this.pad=0
|
|
this.div=document.createElement("div")
|
|
this.div.style.zIndex=my.zIndex++;this.can=document.createElement('canvas');this.g=this.can.getContext("2d");this.div.appendChild(this.can)
|
|
document.getElementById(bdName).appendChild(this.div);this.setSize()
|
|
var div=this.div
|
|
var me=this
|
|
me.drag={onQ:false,x:0,y:0}
|
|
div.addEventListener('touchstart',function(ev){if(!me.showQ)return
|
|
console.log('touchstart')
|
|
me.drag.onQ=true
|
|
me.drag.x=ev.clientX
|
|
me.drag.y=ev.clientY
|
|
me.div.style.zIndex=my.zIndex++;me.goneOutQ=true
|
|
var touch=ev.targetTouches[0];ev.clientX=touch.clientX;ev.clientY=touch.clientY;ev.touchQ=true;ev.preventDefault();})
|
|
div.addEventListener('touchmove',function(ev){if(!me.showQ)return
|
|
var touch=ev.targetTouches[0];ev.clientX=touch.clientX;ev.clientY=touch.clientY;ev.touchQ=true;me.moveMe(me,ev)})
|
|
div.addEventListener('touchend',function(ev){me.dropMe(me)})
|
|
div.addEventListener('mouseover',function(){if(!me.showQ)return
|
|
document.body.style.cursor="pointer";})
|
|
div.addEventListener('mousedown',function(ev){if(!me.showQ)return
|
|
console.log('mousedown')
|
|
me.drag.onQ=true
|
|
me.drag.x=ev.clientX
|
|
me.drag.y=ev.clientY
|
|
me.div.style.zIndex=my.zIndex++;me.goneOutQ=true})
|
|
div.addEventListener('mouseleave',function(){if(!me.showQ)return
|
|
me.drag.onQ=false
|
|
document.body.style.cursor="default";})
|
|
div.addEventListener('mouseup',function(){if(!me.showQ)return
|
|
me.dropMe(me)})
|
|
div.addEventListener('mousemove',function(ev){if(!me.showQ)return
|
|
me.moveMe(me,ev)})}
|
|
Ship.prototype.dropMe=function(me){me.drag.onQ=false
|
|
me.pos.x=Math.round((parseFloat(me.div.style.left)-my.borderLt)/my.boxWd)
|
|
var lt=me.pos.x*my.boxWd+my.borderLt
|
|
me.div.style.left=lt+'px'
|
|
me.pos.y=Math.round((parseFloat(me.div.style.top)-my.borderTp)/my.boxWd)
|
|
var tp=me.pos.y*my.boxWd+my.borderTp
|
|
me.div.style.top=tp+'px'
|
|
placeCheck()}
|
|
Ship.prototype.moveMe=function(me,ev){if(me.drag.onQ){var lt=parseFloat(me.div.style.left)+ev.clientX-me.drag.x
|
|
me.div.style.left=lt+'px'
|
|
me.drag.x=ev.clientX
|
|
var tp=parseFloat(me.div.style.top)+ev.clientY-me.drag.y
|
|
me.div.style.top=tp+'px'
|
|
me.drag.y=ev.clientY
|
|
var el=document.getElementById(this.bdName)
|
|
var bRect=el.getBoundingClientRect();var gap=5
|
|
var lilRect={lt:bRect.left+gap,tp:bRect.top+gap,rt:bRect.right-gap,bt:bRect.top+my.boxWd*my.bdSz-gap}
|
|
var bigRect={lt:bRect.left-gap,tp:bRect.top-gap,rt:bRect.right+gap,bt:bRect.top+my.boxWd*my.bdSz+gap}
|
|
if(me.goneOutQ){if(insideRect(ev.clientX,ev.clientY,lilRect)){me.goneOutQ=false
|
|
console.log('gone in')}}else{if(!insideRect(ev.clientX,ev.clientY,bigRect)){me.goneOutQ=true
|
|
console.log('gone out 1:',ev.clientX,ev.clientY,lt,tp,bRect.left,bRect.top)
|
|
var temp=me.xn
|
|
me.xn=me.yn
|
|
me.yn=temp
|
|
var toMouseX=ev.clientX-lt-bRect.left+my.borderLt
|
|
var toMouseY=ev.clientY-tp-bRect.top+my.borderTp
|
|
me.pos.x=(lt-my.borderLt+toMouseX-toMouseY)/my.boxWd
|
|
me.pos.y=(tp-my.borderTp-toMouseX+toMouseY)/my.boxWd
|
|
me.setSize()
|
|
me.draw()}}
|
|
ev.preventDefault()}}
|
|
Ship.prototype.bdMoveTo=function(bdName){document.getElementById(this.bdName).removeChild(this.div)
|
|
document.getElementById(bdName).appendChild(this.div)
|
|
this.bdName=bdName}
|
|
Ship.prototype.hitQ=function(xn,yn){var rect={lt:xn,tp:yn,wd:1,ht:1,rt:xn+0.99,bt:yn+0.99}
|
|
if(intersectRect(this.rect(),rect)){console.log('intersects',this.rect(),rect)
|
|
return true}
|
|
return false}
|
|
Ship.prototype.hit=function(bd){this.hitN++
|
|
console.log('ship hit',this.hitN,this.sz)
|
|
if(!this.sunkQ&&this.hitN>=this.sz){this.sunkQ=true
|
|
soundPlay('sndSunk')
|
|
this.show(true)
|
|
console.log('ship just sunk')
|
|
for(var i=0;i<this.xn;i++){for(var j=0;j<this.yn;j++){var xn=this.pos.x+i
|
|
var yn=this.pos.y+j
|
|
bd[xn][yn].sunkQ=true}}}}
|
|
Ship.prototype.setSize=function(){var tp=0
|
|
var lt=0
|
|
var canWd=(this.xn*my.boxWd+this.pad*2);var canHt=(this.yn*my.boxWd+this.pad*2);var div=this.div
|
|
div.style.width=canWd+'px'
|
|
div.style.height=canHt+'px'
|
|
div.style.position='absolute'
|
|
div.style.top=tp+'px'
|
|
div.style.left=lt+'px'
|
|
var can=this.can
|
|
can.style.position="absolute";can.style.top='0px'
|
|
can.style.left='0px'
|
|
var ratio=1
|
|
can.width=canWd*ratio;can.height=canHt*ratio;can.style.width=canWd+"px";can.style.height=canHt+"px";}
|
|
Ship.prototype.rect=function(){return{lt:this.pos.x,tp:this.pos.y,wd:this.xn,ht:this.yn,rt:this.pos.x+this.xn-0.01,bt:this.pos.y+this.yn-0.01}}
|
|
Ship.prototype.validPosQ=function(ships){if(!this.insideQ())return false
|
|
if(this.intersectsQ(ships))return false
|
|
return true}
|
|
Ship.prototype.insideQ=function(){if(this.pos.x<0)return false
|
|
if(this.pos.y<0)return false
|
|
if(this.pos.x+this.xn>my.bdSz)return false
|
|
if(this.pos.y+this.yn>my.bdSz)return false
|
|
return true}
|
|
Ship.prototype.intersectsQ=function(ships){for(var i=0;i<ships.length;i++){var othr=ships[i]
|
|
if(intersectRect(this.rect(),othr.rect())){console.log('intersects',this.rect(),othr.rect())
|
|
return true}}
|
|
return false}
|
|
Ship.prototype.show=function(onQ){console.log('Ship show',onQ)
|
|
if(onQ){this.draw()}else{var g=this.g
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)}}
|
|
Ship.prototype.draw=function(){var g=this.g
|
|
var shipWd=this.xn*my.boxWd
|
|
var shipHt=this.yn*my.boxWd
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)
|
|
g.strokeStyle='black'
|
|
g.lineWidth=2
|
|
g.fillStyle=this.clr
|
|
g.beginPath()
|
|
console.log('ship',this,my.boxWd,shipHt)
|
|
g.roundRect(2,2,shipWd-4,shipHt-4,my.boxWd/2)
|
|
g.fill()
|
|
g.stroke()
|
|
this.div.style.left=boxLeft(this.pos.x)+'px'
|
|
this.div.style.top=boxTop(this.pos.y)+'px'}
|
|
Ship.prototype.setxy=function(lt,tp){this.div.style.left=lt+'px';this.div.style.top=tp+'px';}
|
|
CanvasRenderingContext2D.prototype.roundRect=function(x,y,w,h,r){if(w<2*r)r=w/2;if(h<2*r)r=h/2;this.moveTo(x+r,y);this.arcTo(x+w,y,x+w,y+h,r);this.arcTo(x+w,y+h,x,y+h,r);this.arcTo(x,y+h,x,y,r);this.arcTo(x,y,x+w,y,r);return this;};function insideRect(x,y,r){if(x<r.lt)return false
|
|
if(x>r.rt)return false
|
|
if(y<r.tp)return false
|
|
if(y>r.bt)return false
|
|
return true}
|
|
function intersectRect(r1,r2){return!(r2.lt>r1.rt||r2.rt<r1.lt||r2.tp>r1.bt||r2.bt<r1.tp);}
|
|
function getRandomPts(width,height,ptCount,clrs){var pts=[];for(var i=0;i<ptCount;i++){var ptX=Math.random()*width;var ptY=Math.random()*height;var ptClr=clrs[randomInt(0,clrs.length-1)][1];pts.push([ptX,ptY,ptClr]);}
|
|
return pts;}
|
|
function getClrAt(pts,width,height){var sumClrs=[];var sumFact=0;sumClrs=[0,0,0];for(var i=0;i<pts.length;i++){var d=dist(pts[i][0]-width,pts[i][1]-height);var fact=1/d;var rgb=hex2rgb(pts[i][2]);sumClrs[0]+=rgb[0]*fact;sumClrs[1]+=rgb[1]*fact;sumClrs[2]+=rgb[2]*fact;sumFact+=fact;}
|
|
var clr=rgb2hex([sumClrs[0]/sumFact,sumClrs[1]/sumFact,sumClrs[2]/sumFact]);return(clr);}
|
|
function hex2rgb(hex){hex=hex.replace('#','');var rr=parseInt(hex.substring(0,2),16);var gg=parseInt(hex.substring(2,4),16);var bb=parseInt(hex.substring(4,6),16);return[rr,gg,bb];}
|
|
function rgb2hex(clrs){var hex=[];for(var i=0;i<3;i++){hex.push(((clrs[i])<<0).toString(16));if(hex[i].length<2){hex[i]="0"+hex[i];}}
|
|
return "#"+hex[0]+hex[1]+hex[2];}
|
|
function dist(dx,dy){return(Math.sqrt(dx*dx+dy*dy));} |