JavaScript制作windows经典扫雷小游戏


Posted in Javascript onMarch 31, 2015

代码其实很简单,这里就不多废话了

<html>
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>扫雷-JavaScript Mine Sweeper</title>
<style type="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:2px solid #F5F5F5; border-right:2px outset #F5F5F5; border-top:2px solid #F5F5F5; border-bottom:2px outset #F5F5F5; font-weight:bold}
.Mine, .Boom, .M0, .M1, .M2, .M3, .M4, .M5, .M6, .M7, .M8{background:#C5C5C5;border-right:1px solid #B4B4B4; border-bottom:1px solid #B4B4B4;}
td.Mine{background: url(http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/mine.gif) no-repeat center}
td.Boom{background:#F00 url(http://sandbox.runjs.cn/uploads/rs/202/xyovf5xj/mine.gif) no-repeat center}
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){return document.getElementById(id)},
  MouseButton=LeftMouse=0,//作为双键单击的计数,mouseup事件置0,mousedown事件+1,当MouseButton=2说明双键同时单击;鼠标左键是否按下,当鼠标左键按下时为1,松开为0
  FlagImg=new Image(),
  HappyImg=new Image(),
  MineImg=new Image(),
  SadImg=new Image(),
  SuccessImg=new Image(),
 
  WhichButton=function(e){
    e=e||window.event;
    var b=getOs();
    if(b!=2){ //非FF
      switch(e.button){
        case 2:
          return 0;
        case 0:
          return b==1?0:1; //b==1,IE
        default:
          return 1;
      }
    }else{ //FF
      return e.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(){
    var T=this,MaxX=T.MaxX,MaxY=T.MaxY,nX,nY=MaxY,MineCount=T.MineCount,
      AStr=['<table bordercolor="#000000" border="0" cellpadding="0" cellspacing="0" height="'+20*MaxY+'px" width="'+20*MaxX+'px" style="border: 10px inset #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]='<td class="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){return this.Mine[Y][X]},
   
  //仅当按重新开始的按钮,不初始化大表格字符
  fRefreshMap:function(){
    var T=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(){
    var T=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(){
    var T=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){
    var T=this;
    switch(MouseButton){
      case 2://双键按下的状态
        var arr=T.fGetAround(X,Y),i=arr.length,TAr;
        while(i--)T.fButtonDown((TAr=arr[i])[0],TAr[1]);
      case 1:
        LeftMouse==1&&T.fButtonDown(X,Y); //左键是按下的
    }
  },
   
  //鼠标移出某格子的时候
  fButtonMouseOut:function(X,Y){
    var T=this;
    switch(MouseButton){
      case 2://双键按下的状态
        var arr=T.fGetAround(X,Y),i=arr.length,TAr;
        while(i--)T.fButtonUp((TAr=arr[i])[0],TAr[1]);
      case 1:
        LeftMouse==1&&T.fButtonUp(X,Y); //左键是按下的
    }
  },
 
  //鼠标按下时没被开启的格子呈现被按下
  fButtonDown:function(X,Y){
    var srcEle=$('Img'+X+'_'+Y);
    srcEle.className=='Normal'&&(srcEle.className='M0');
  },
   
  //让没被开启并且已经呈现被按下的格子回复Normal
  fButtonUp:function(X,Y){
    var srcEle=$('Img'+X+'_'+Y);
    srcEle.className=='M0'&&!this.fGetMine(X,Y).State&&(srcEle.className='Normal');
  },
   
  //获取8个方向的坐标
  fGetAround:function(X,Y){
    var TX,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]);
    }
    return newArr;
  },
   
  //鼠标在格子按下
  fMouseDown:function(X,Y,evt){
    var T=this;
    if(T.GameOver){
      alert('游戏失败,再接再厉!');
      return;
    }
    if(T.Success){
      alert('恭喜游戏成功!再来一局吧?');
      return;
    }
    var srcEle=$('Img'+X+'_'+Y),ObXY=T.fGetMine(X,Y),arr,i,TAr;
    ++MouseButton;
    evt=evt||window.event;
    switch(MouseButton){
      case 2:
        arr=T.fGetAround(X,Y);i=arr.length;
        while(i--)T.fButtonDown((TAr=arr[i])[0],TAr[1]);
        break;
      case 1:
        if(WhichButton(evt)){
          LeftMouse=1;
          T.fButtonDown(X,Y);
        }else{
          switch(ObXY.State){
            case 0:
              ObXY.State=2;
              srcEle.className='Flag';
              --$('txtFlagCount').value;
              ++T.FlagCount;
              break;
            case 2:
              ObXY.State=0;
              srcEle.className='Normal';
              ++$('txtFlagCount').value;
              --T.FlagCount;
          }
        }
      }
  },
   
  //鼠标在格子弹起
  fMouseUp:function(X,Y,evt){
    var T=this;
    evt=evt||window.event;
    var srcEle=$('Img'+X+'_'+Y),ObXY=T.fGetMine(X,Y),arr,i,TAr;
    switch(MouseButton){
      case 2: //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;
      case 1: //当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(){
    var T=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(){
    var T=this;
    if(T.aClear.length==0){return}
    ++T.OpenedCount;
    var aXY=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){
    var T=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){
        case 0: //未开启未标记
          !ObTXTY.Mine&&aTmpClear.push([TX,TY]); //没雷也没旗子的时候加入到被辅助开启的数组}
          break;
        case 2: //标记了旗子
          ++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(){
    var T=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){
          case 0:
            TArX.State==2&&($('Img'+X+'_'+Y).className='ErrFlag');
            break;
          case 1:
            $('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){
  var O=OMine;
  switch(Map){
    case 1:
      O.MaxX=O.MaxY=9;
      O.MineCount=10;
      break;
    case 2:
      O.MaxX=O.MaxY=16;
      O.MineCount=40;
      break;
    case 3:
      O.MaxX=30;
      O.MaxY=16;
      O.MineCount=99;
  }
  O.fInit();
},
 
getOs=function(){
  if(navigator.userAgent.indexOf("MSIE")>0)return 1;
  if(isFirefox=navigator.userAgent.indexOf("Firefox")>0)return 2;
  if(isSafari=navigator.userAgent.indexOf("Safari")>0)return 3;  
  if(isCamino=navigator.userAgent.indexOf("Camino")>0)return 4;
  if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0)return 5;
  return 0;
};
 
 
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>
<body topmargin="0" oncontextmenu="return false" ondragstart="return false" onselectstart="return false" onload="OMine.fInit()" bgcolor="#808080">
<center>
<div id="dTop" align="center" style="border-style: inset; border-width: 10;width:400">
<table cellpadding="0" cellspacing="0" style="border-collapse: collapse;" width="380" height="44">
 <tr>
  <td style="width: 102; height:50px">
  <input type="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>
  <td style="width: 136; height:50px">
  <input onclick="OMine.fRefreshMap()" type="image" id="btnRefreshMap" src="happy.gif"><input onclick="OMine.fShowMine();" type="button" name="B3" value="显雷"style="display:none"></td>
  <td style="width: 142; height:50px">
  <input type="radio" value="V1" checked name="R1" id="R1" onclick="ChangeMap(1)">初级<input type="radio" value="V1" name="R1" id="R2" onclick="ChangeMap(2)">中级<input type="radio" value="V1" name="R1" id="R3" onclick="ChangeMap(3)">高级</td>
 </tr>
 
</table>
</div>
<div id="dMap" align="center"></div>
</center>
</body>
</html>

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
基于jquery的滚动新闻列表
Jun 19 Javascript
jQuery Autocomplete自动完成插件
Jul 17 Javascript
深入理解Javascript闭包 新手版
Dec 28 Javascript
多个datatable共存造成多个表格的checkbox都被选中
Jul 11 Javascript
AngularJS基础 ng-class-odd 指令示例
Aug 01 Javascript
利用Javascript实现BMI计算器
Aug 16 Javascript
JS实现获取当前URL和来源URL的方法
Aug 24 Javascript
浅谈js中StringBuffer类的实现方法及使用
Sep 02 Javascript
javascript中Number的方法小结
Nov 21 Javascript
基于JavaScript实现的顺序查找算法示例
Apr 14 Javascript
nvm、nrm、npm 安装和使用详解(小结)
Jan 17 Javascript
jQuery实现的解析本地 XML 文档操作示例
Apr 30 jQuery
jQuery选择器源码解读(四):tokenize方法的Expr.preFilter
Mar 31 #Javascript
JavaScript制作简易的微信打飞机
Mar 31 #Javascript
JS获取表格内指定单元格html内容的方法
Mar 31 #Javascript
JS实现为表格动态添加标题的方法
Mar 31 #Javascript
JS实现从表格中动态删除指定行的方法
Mar 31 #Javascript
jQuery选择器源码解读(三):tokenize方法
Mar 31 #Javascript
javascript制作游戏开发碰撞检测的封装代码
Mar 31 #Javascript
You might like
PHP4在Windows2000下的安装
2006/10/09 PHP
PHP 处理图片的类实现代码
2009/10/23 PHP
yii使用bootstrap分页样式的实例
2017/01/17 PHP
php中文乱码问题的终极解决方案汇总
2017/08/01 PHP
使用jquery给input和textarea设定ie中的focus
2008/05/29 Javascript
js 创建书签小工具之理论
2011/02/25 Javascript
Javascript操作cookie的函数代码
2012/10/03 Javascript
jquery滚动组件(vticker.js)实现页面动态数据的滚动效果
2013/07/03 Javascript
点击弹出层外区域关闭弹出层jquery特效示例
2013/08/25 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
js表头排序实现方法
2015/01/16 Javascript
浅析BootStrap Treeview的简单使用
2016/10/12 Javascript
JS中作用域和变量提升(hoisting)的深入理解
2016/10/31 Javascript
knockoutjs模板实现树形结构列表
2017/07/31 Javascript
帝国cms首页列表页实现点赞功能
2017/10/30 Javascript
js使用xml数据载体实现城市省份二级联动效果
2017/11/08 Javascript
vue 添加vux的代码讲解
2017/11/30 Javascript
微信小程序onLaunch异步,首页onLoad先执行?
2018/09/20 Javascript
Python 时间操作例子和时间格式化参数小结
2014/04/24 Python
python模拟鼠标拖动操作的方法
2015/03/11 Python
Python用 KNN 进行验证码识别的实现方法
2018/02/06 Python
20行python代码的入门级小游戏的详解
2019/05/05 Python
Python:二维列表下标互换方式(矩阵转置)
2019/12/02 Python
Python实现搜索算法的实例代码
2020/01/02 Python
Mixbook加拿大:照片书,照片卡,剪贴簿,年历和日历
2017/02/21 全球购物
来自圣地亚哥的实惠太阳镜:Knockaround
2018/08/27 全球购物
荷兰睡眠专家:Beter Bed
2020/11/23 全球购物
缴纳养老保险的证明
2014/01/10 职场文书
数控技术专业毕业自荐书范文
2014/02/05 职场文书
幼儿园元旦亲子活动方案
2014/02/17 职场文书
大学中国梦演讲稿
2014/04/23 职场文书
音乐之声音乐广播稿
2014/09/10 职场文书
大学生实习证明范文(5篇)
2014/09/18 职场文书
安全第一课观后感
2015/06/18 职场文书
党员转正大会主持词
2015/07/02 职场文书
证婚人婚礼致辞
2015/07/28 职场文书