JavaScript制作windows经典扫雷小游戏
代码其实很简单,这里就不多废话了
<html> <head> <metahttp-equiv="Content-Language"content="zh-cn"> <metahttp-equiv="Content-Type"content="text/html;charset=utf-8"> <title>扫雷-JavaScriptMineSweeper</title> <styletype="text/css"> table{TABLE-LAYOUT:fixed;cursor:pointer} td{width:20px;height:20px;font-size:12px;font-family:Verdana;font-weight:bold;text-align:center;background:#CECECE;} td.Normal,.Flag{border-left:2pxsolid#F5F5F5;border-right:2pxoutset#F5F5F5;border-top:2pxsolid#F5F5F5;border-bottom:2pxoutset#F5F5F5;font-weight:bold} .Mine,.Boom,.M0,.M1,.M2,.M3,.M4,.M5,.M6,.M7,.M8{background:#C5C5C5;border-right:1pxsolid#B4B4B4;border-bottom:1pxsolid#B4B4B4;} td.Mine{background:url(http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/mine.gif)no-repeatcenter} td.Boom{background:#F00url(http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/mine.gif)no-repeatcenter} td.Flag,td.ErrFlag{background-image:url(http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/flag.gif);background-repeat:no-repeat;background-position:center;} td.ErrFlag{background:#0F0} td.M1{color:#00f} td.M2{color:#008000} td.M3{color:#f00} td.M4{color:#000080} td.M5{color:#800000} td.M6{color:#008080} td.M7{color:#000} td.M8{color:#808080} </style> <script> var$=function(id){returndocument.getElementById(id)}, MouseButton=LeftMouse=0,//作为双键单击的计数,mouseup事件置0,mousedown事件+1,当MouseButton=2说明双键同时单击;鼠标左键是否按下,当鼠标左键按下时为1,松开为0 FlagImg=newImage(), HappyImg=newImage(), MineImg=newImage(), SadImg=newImage(), SuccessImg=newImage(), WhichButton=function(e){ e=e||window.event; varb=getOs(); if(b!=2){//非FF switch(e.button){ case2: return0; case0: returnb==1?0:1;//b==1,IE default: return1; } }else{//FF returne.which==3?0:1; } }, OMine={ MaxX:9,MaxY:9,//最大的坐标 MineCount:10,//定义雷的个数,可改 FlagCount:0,//已经标记的旗子的数量 OpenedCount:0,//已经打开的地区的数量 MaxOpenCount:0,//应该要打开的最大地区数量 //当OpenedCount=MaxOpenCount&&FlagCount=MineCount的时候,判断游戏成功结束 Mine:[], GameOver:false,//true代表游戏失败结束 Success:false,//true代表游戏成功结束 aClear:[],//临时开雷的数组 //刷新网页的时候初始化 fInit:function(){ varT=this,MaxX=T.MaxX,MaxY=T.MaxY,nX,nY=MaxY,MineCount=T.MineCount, AStr=['<tablebordercolor="#000000"border="0"cellpadding="0"cellspacing="0"height="'+20*MaxY+'px"width="'+20*MaxX+'px"style="border:10pxinset#a0a0a0">'], i=0,TAr,TMine=T.Mine; T.MaxOpenCount=MaxX*MaxY-MineCount; while(nY--){ AStr[++i]='<tr>'; TAr=TMine[nY]=[]; nX=MaxX; while(nX--){ AStr[++i]='<tdclass="Normal"onmousedown="OMine.fMouseDown('+nX+','+nY+',event);"onmouseup="OMine.fMouseUp('+nX+','+nY+',event);"onmouseover="OMine.fButtonMouseOver('+nX+','+nY+')"onmouseout="OMine.fButtonMouseOut('+nX+','+nY+')"id="Img'+nX+'_'+nY+'"></td>'; TAr[nX]={ Mine:0,//0表示没有雷,1表示有雷 State:0,//0表示未开启,1表示左键开启,2表示右键标记 MineCount:0//周围有几个雷 } } AStr[++i]='</tr>'; } AStr[++i]='</table>'; $('dMap').innerHTML=T.InitStr=AStr.join(''); $('txtFlagCount').value=MineCount; T.fInitMine(); $('btnRefreshMap').src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/happy.gif'; T.GameOver=T.Success=false; T.OpenedCount=T.FlagCount=T.aClear.lenght=0; }, //为了方便循环赋值,给表格数组赋值的时候是XY倒过来循环的,所以调用的时候要倒回去 //比如要获得该格子是否有雷,用OMine.fGetMine(x,y).Mine; fGetMine:function(X,Y){returnthis.Mine[Y][X]}, //仅当按重新开始的按钮,不初始化大表格字符 fRefreshMap:function(){ varT=this; $('dMap').innerHTML=T.InitStr; T.fResetOMine();//必须先重置OMine,再重置99个雷 T.fInitMine(); T.GameOver=T.Success=false; $('btnRefreshMap').src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/happy.gif'; $('txtFlagCount').value=T.MineCount; T.OpenedCount=T.FlagCount=T.aClear.lenght=0; }, //重置OMine.Mine数组 fResetOMine:function(){ varT=this,MaxY=T.MaxY,MaxX=T.MaxX,X,Y=MaxY,M,Mine=T.Mine,TAr; while(Y--){ X=MaxX; TAr=Mine[Y]; while(X--)(M=TAr[X]).Mine=M.State=M.MineCount=0; } }, //初始化雷的数组 fInitMine:function(){ varT=this,MaxX=T.MaxX,MaxY=T.MaxY,a,fGetMine=T.fGetMine, aOld=[],x,y=MaxY,n=0,l=T.MineCount,xRand;//一个随机数字 while(y--){ x=MaxX; while(x--)aOld[n++]=[x,y]; } while(l--){ a=aOld[xRand=Math.floor(Math.random()*(n-1))]; T.fGetMine(a[0],a[1]).Mine=1; aOld.splice(xRand,1); --n; } }, //鼠标移动到某格子的时候 fButtonMouseOver:function(X,Y){ varT=this; switch(MouseButton){ case2://双键按下的状态 vararr=T.fGetAround(X,Y),i=arr.length,TAr; while(i--)T.fButtonDown((TAr=arr[i])[0],TAr[1]); case1: LeftMouse==1&&T.fButtonDown(X,Y);//左键是按下的 } }, //鼠标移出某格子的时候 fButtonMouseOut:function(X,Y){ varT=this; switch(MouseButton){ case2://双键按下的状态 vararr=T.fGetAround(X,Y),i=arr.length,TAr; while(i--)T.fButtonUp((TAr=arr[i])[0],TAr[1]); case1: LeftMouse==1&&T.fButtonUp(X,Y);//左键是按下的 } }, //鼠标按下时没被开启的格子呈现被按下 fButtonDown:function(X,Y){ varsrcEle=$('Img'+X+'_'+Y); srcEle.className=='Normal'&&(srcEle.className='M0'); }, //让没被开启并且已经呈现被按下的格子回复Normal fButtonUp:function(X,Y){ varsrcEle=$('Img'+X+'_'+Y); srcEle.className=='M0'&&!this.fGetMine(X,Y).State&&(srcEle.className='Normal'); }, //获取8个方向的坐标 fGetAround:function(X,Y){ varTX,TY,i=8,MX=this.MaxX-1,MY=this.MaxY-1, Arr=[[-1,0],[-1,-1],[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1]], newArr=[],TAr; while(i--){ TX=X+(TAr=Arr[i])[0]; TY=Y+TAr[1]; !(TX<0||TX>MX||TY<0||TY>MY)&&newArr.push([TX,TY]); } returnnewArr; }, //鼠标在格子按下 fMouseDown:function(X,Y,evt){ varT=this; if(T.GameOver){ alert('游戏失败,再接再厉!'); return; } if(T.Success){ alert('恭喜游戏成功!再来一局吧?'); return; } varsrcEle=$('Img'+X+'_'+Y),ObXY=T.fGetMine(X,Y),arr,i,TAr; ++MouseButton; evt=evt||window.event; switch(MouseButton){ case2: arr=T.fGetAround(X,Y);i=arr.length; while(i--)T.fButtonDown((TAr=arr[i])[0],TAr[1]); break; case1: if(WhichButton(evt)){ LeftMouse=1; T.fButtonDown(X,Y); }else{ switch(ObXY.State){ case0: ObXY.State=2; srcEle.className='Flag'; --$('txtFlagCount').value; ++T.FlagCount; break; case2: ObXY.State=0; srcEle.className='Normal'; ++$('txtFlagCount').value; --T.FlagCount; } } } }, //鼠标在格子弹起 fMouseUp:function(X,Y,evt){ varT=this; evt=evt||window.event; varsrcEle=$('Img'+X+'_'+Y),ObXY=T.fGetMine(X,Y),arr,i,TAr; switch(MouseButton){ case2://MouseDown为两个键都单击按下,任意一个键弹起都判断为双键弹起 LeftMouse=0; //鼠标弹起,把呈现被按下状态的格子恢复 arr=T.fGetAround(X,Y);i=arr.length; while(i--)T.fButtonUp((TAr=arr[i])[0],TAr[1]); !ObXY.State&&T.fButtonUp(X,Y); ObXY.State==1&&ObXY.MineCount&&T.fOpenFlagMine(X,Y); break; case1://当MouseDown为一个键单击时,MouseUp才判断为一个键弹起 if(WhichButton(evt)){ //只有在State=0才起作用,跟是否有雷没关系 LeftMouse=0; if(ObXY.State){break;} ObXY.Mine?( //触雷,结束该局 T.fFail(), srcEle.className='Boom' ):( ObXY.State=1,//压栈之前就要设置为已经开启 T.aClear.push([X,Y]), T.fClearMine() ) } } MouseButton=0; if(T.OpenedCount==T.MaxOpenCount&&T.FlagCount==T.MineCount){ T.fSuccess(); alert('恭喜游戏成功!再来一局吧?'); return; } //当剩余未开启的格子数=剩余的旗子数,自动完成 T.MaxOpenCount+T.MineCount-T.OpenedCount-T.FlagCount==$('txtFlagCount').value&&( T.fSuccess(), T.fAutoFlag(), alert('恭喜游戏成功!再来一局吧?') ) }, //自动填充未开启的地区的雷 fAutoFlag:function(){ varT=this,nX,nY=T.MaxY,MaxX=T.MaxX,Mine=T.Mine,TAr; while(nY--){ nX=MaxX; TAr=Mine[nY]; while(nX--)!TAr[nX].State&&($('Img'+nX+'_'+nY).className='Flag'); } $('txtFlagCount').value=0; }, //递归开雷 fClearMine:function(){ varT=this; if(T.aClear.length==0){return} ++T.OpenedCount; varaXY=T.aClear.pop(),X=aXY[0],Y=aXY[1],TX,TY, aTmpClear=[],//一个临时数组 srcEle=$('Img'+X+'_'+Y), ObXY,ObTXTY, countMine=0,//获取周围雷的个数 //从正左开始的8个方向 arr=T.fGetAround(X,Y),i=arr.length,TAr; while(i--){ //TX,TY获得本格周围的坐标 (ObTXTY=T.fGetMine(TX=(TAr=arr[i])[0],TY=TAr[1])).Mine==1&&++countMine; !ObTXTY.State&&aTmpClear.push([TX,TY]); } ObXY=T.fGetMine(X,Y); ObXY.MineCount=countMine; srcEle.className='M'+countMine; if(!countMine){ Array.prototype.push.apply(T.aClear,aTmpClear); i=aTmpClear.length; while(i--)T.fGetMine((TAr=aTmpClear[i])[0],TAr[1]).State=1; }else{ getOs()==2? srcEle.textContent=countMine :srcEle.innerText=countMine } T.fClearMine(); }, //获得双键辅助开启 fOpenFlagMine:function(X,Y){ varT=this,FlagCount=0,TX,TY,ObXY,ObTXTY,aTmpClear=[],FlagErr=false, arr=T.fGetAround(X,Y),i=arr.length,TAr; while(i--){ //TX,TY获得本格周围的坐标 ObTXTY=T.fGetMine(TX=(TAr=arr[i])[0],TY=TAr[1]); switch(ObTXTY.State){ case0://未开启未标记 !ObTXTY.Mine&&aTmpClear.push([TX,TY]);//没雷也没旗子的时候加入到被辅助开启的数组} break; case2://标记了旗子 ++FlagCount;//只要标记了旗子,无论对错,都记录标记数+1 !ObTXTY.Mine&&(FlagErr=true);//没有雷但是标记了旗子,标记错误 } } if(FlagCount<T.fGetMine(X,Y).MineCount||aTmpClear.length==0)return; //旗子比实际雷少,无论标记对错,不开启 //没有可以提供开启的空格 if(FlagErr){//有错误则进行结束游戏处理 T.fFail(); return; } Array.prototype.push.apply(T.aClear,aTmpClear); i=aTmpClear.length; while(i--)T.fGetMine((TAr=aTmpClear[i])[0],TAr[1]).State=1; T.fClearMine(); }, //显示所有的雷 fShowMine:function(){ varT=this,X=0,Y=T.MaxY,MaxX=T.MaxX,Mine=T.Mine,TAr,TArX; while(Y--){ X=MaxX; TAr=Mine[Y]; while(X--){ TArX=TAr[X]; switch(TArX.Mine){ case0: TArX.State==2&&($('Img'+X+'_'+Y).className='ErrFlag'); break; case1: $('Img'+X+'_'+Y).className='Mine'; } } } }, //游戏成功结束 fSuccess:function(){ this.Success=true; $('btnRefreshMap').src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/success.gif'; }, //游戏失败结束 fFail:function(){ this.GameOver=true; $('btnRefreshMap').src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/sad.gif'; this.fShowMine(); } }, //换地图 ChangeMap=function(Map){ varO=OMine; switch(Map){ case1: O.MaxX=O.MaxY=9; O.MineCount=10; break; case2: O.MaxX=O.MaxY=16; O.MineCount=40; break; case3: O.MaxX=30; O.MaxY=16; O.MineCount=99; } O.fInit(); }, getOs=function(){ if(navigator.userAgent.indexOf("MSIE")>0)return1; if(isFirefox=navigator.userAgent.indexOf("Firefox")>0)return2; if(isSafari=navigator.userAgent.indexOf("Safari")>0)return3; if(isCamino=navigator.userAgent.indexOf("Camino")>0)return4; if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0)return5; return0; }; FlagImg.src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/flag.gif'; HappyImg.src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/happy.gif'; MineImg.src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/mine.gif'; SadImg.src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/sad.gif'; SuccessImg.src='http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/success.gif'; </script> </head> <bodytopmargin="0"oncontextmenu="returnfalse"ondragstart="returnfalse"onselectstart="returnfalse"onload="OMine.fInit()"bgcolor="#808080"> <center> <divid="dTop"align="center"style="border-style:inset;border-width:10;width:400"> <tablecellpadding="0"cellspacing="0"style="border-collapse:collapse;"width="380"height="44"> <tr> <tdstyle="width:102;height:50px"> <inputtype="text"id="txtFlagCount"size="20"style="width:60;height:30;color:#FF0000;text-align:center;font-family:Verdana;font-weight:bold;background-color:#000000;font-size:13pt"value=""></td> <tdstyle="width:136;height:50px"> <inputonclick="OMine.fRefreshMap()"type="image"id="btnRefreshMap"src="happy.gif"><inputonclick="OMine.fShowMine();"type="button"name="B3"value="显雷"style="display:none"></td> <tdstyle="width:142;height:50px"> <inputtype="radio"value="V1"checkedname="R1"id="R1"onclick="ChangeMap(1)">初级<inputtype="radio"value="V1"name="R1"id="R2"onclick="ChangeMap(2)">中级<inputtype="radio"value="V1"name="R1"id="R3"onclick="ChangeMap(3)">高级</td> </tr> </table> </div> <divid="dMap"align="center"></div> </center> </body> </html>
以上所述就是本文的全部内容了,希望大家能够喜欢。