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>
以上所述就是本文的全部内容了,希望大家能够喜欢。