zoukankan      html  css  js  c++  java
  • javascript模拟Windows系统下的扫雷游戏

     javascript模拟Windows系统下的扫雷游戏。

    说好的一周一篇随笔的,这才第三周就延迟交作业了,深深的自责中...

    先玩一把 demo

     

    很久以前写的 当时都没写注释的 刚加上了 (好多自己都不认识了 ... )

    不足的敌方就是本来想写个游戏排名的统计的,等有空了再加上(好像每次都这么说 然后就等好久好久...)

    还有就是没有实现:点击第一个格子不能是雷的功能

     

     刚才在手机端 打开了下这篇文章 排版完全乱了...

    <style>
        ul{padding:0;list-style:none;}
        #mine{overflow:hidden;30px;height:30px;border:1px solid #966;}
        #mine li{float:left;30px;height:30px;line-height:30px;text-align:center;font-size:14px;color:#222;}
        #mine .mine_01{background:url(mine.gif) no-repeat;}
        #mine .mine_02{background:url(mine.gif) -30px 0 no-repeat;}
        #mine .mine_03{background:url(mine.gif) -60px 0 no-repeat;}
        #mine .mine_04{background:url(mine.gif) -90px 0 no-repeat;}
        #mine .mine_05{background:url(mine.gif) -120px 0 no-repeat;}
        #mine .mine_06{background:url(mine.gif) -150px 0 no-repeat;}
        #mine .mine_07{background:url(mine.gif) -180px 0 no-repeat;}
    
        #count{font-size:12px;}
        #time{color:#900;font-weight:bold;}
    </style>
     <select id="wh">
      <option value="8*10">8*10</option>
      <option value="10*10">10*10</option>
      <option value="12*12">12*12</option>
     </select>
     <button id='ready'>重新开始</button>
    <div id="count">
      计时: <span id="time">0</span>
    </div>
    
    <ul id="mine">
    
    </ul>
    
    ie6+  ff oprea 谷歌
    opera 早期版本 默认不支持document.oncontextmenu事件 没有找到好的替代方法
    <script>
    var $ = function(id){return document.getElementById(id)};
    window.onload=function ready(){
        var V=$('wh').value.split('*')
        setMineField(Number(V[0]),Number(V[1]));
        
        $('wh').onchange=$('ready').onclick=function(){
            V=$('wh').value.split('*')
            setMineField(Number(V[0]),Number(V[1]))
        }
    }
    //---------------------------------------------------雷区
    var mineField={
        _mineW:30,      //每一个雷的宽度 必须和样式同步
        _mineH:30,
        _mineFieldBlock:$('mine'),
        _mineFieldEle:$('mine').getElementsByTagName('li'),
        _time:$('time'),
        
        status:0,      //雷区状态 0还没开始 1开始了 已经在计时了  2游戏结束了    
        mineNum:0,     //雷数
        clearPlace:0,  //统计扫除的格子;
        x:0,           //
        y:0,           //
        density:0.2,   //雷的密度 雷区密度不宜超过0.5 在有些尺寸的雷区下 过高的设置 无法生成mineMap数组
        mineMap:[],    //雷区的二维图,0 : 不是雷   -1 : 雷
        time:-1,       //计时 s
        debug:false     //调试模式
    }//mineField object end
    
    function timedCount(){
        if(mineField.status!=1){return false}
        mineField.time++;
        mineField._time.innerHTML=mineField.time;
        setTimeout("timedCount()",1000);
    }
    //--------------------------------------对雷的状态设置
    function setThisMine(str,index){
    
        var allMine=mineField._mineFieldEle;
        //设置雷是否插旗
        if(str=='setOn'){
            var thisMine=allMine[index];
            thisMine.on=thisMine.on<2?thisMine.on+1:0;
            if(thisMine.on==1){thisMine.className='mine_03';}//插旗
            else if(thisMine.on==2){thisMine.className='mine_04'}//取消插旗
            else if(thisMine.on==0){thisMine.className='mine_01'}//取消插旗
            return false;
        }
        //显示方格
        if(str=='show'){
            if(Object.prototype.toString.call(index) === '[object Array]'){//显示一大片
                mineField.clearPlace=mineField.clearPlace+index.length;
                for(var i=0;i<index.length;i++){
                    var thisMine=allMine[index[i]];
                    thisMine.innerHTML=mineField.mineMap[thisMine.index];
                    thisMine.className='mine_02';
                    thisMine.on=3;
                }
            }
            else{//显示单个非雷区域
                mineField.clearPlace++;
                allMine[index].on=3;
                allMine[index].innerHTML=mineField.mineMap[index];
                allMine[index].className='mine_02';
            }
            if(mineField.clearPlace==mineField.x*mineField.y-mineField.mineNum){//恭喜你
                alert('恭喜你');
                for(var i=0;i<allMine.length;i++){
                    if(mineField.mineMap[allMine[i].index]==-1){
                        allMine[i].className='mine_07';
                    }
                }
                mineField.status=2;
                return false;
            }
        }
        //显示全部雷
        if(str=='peng'){
                for(var i=0;i<allMine.length;i++){
                    if(mineField.mineMap[allMine[i].index]==-1){
                        allMine[i].className=i==index?'mine_06':'mine_05';
                    }
                }
                mineField.status=2;
        }
    }
    //-----------------------------------------------设置行数 和 列数
    function setMineField(a,b){
            var thisMineFiele=mineField._mineFieldBlock;
            DivBox=document.createElement("div"),
            num=a*b,k=0;
            thisMineFiele.innerHTML='';
            //雷区参数调整
            mineField.x=a;//有几列
            mineField.y=b;//有几行
            mineField.mineNum=Math.floor(a*b*mineField.density);
            mineField.status=0;
            mineField.time=-1;
            mineField.clearPlace=0;
            mineField.mineMap.length=0;
            mineField._time.innerHTML=0;
                    
            //生成雷区地图
            setMineMap();
            //生成雷区(创建li)
            while(k<num){
            var newLi=document.createElement("li");
            if(mineField.debug) newLi.innerHTML=mineField.mineMap[k];//作弊
            newLi.className='mine_01';
            DivBox.appendChild(newLi);
            k++;
            }
            thisMineFiele.style.height=mineField._mineW*b+'px';
            thisMineFiele.style.width=mineField._mineH*a+'px';
            thisMineFiele.innerHTML=DivBox.innerHTML;
            DivBox=null;
            setEvent();//事件
    }
    //-----------------------------------生成雷区地图
    function setMineMap(){
            var num=mineField.x*mineField.y,
                mineNum=mineField.mineNum,
                Interval=Math.floor(num/mineNum);
            for(var i=0;i<num;i++){
                if(i%Interval==0&&i<mineNum*Interval){mineField.mineMap[i]=-1;}else{mineField.mineMap[i]=0;}//雷等距离分布与数组中
            }
            mineField.mineMap.sort(function(){ return 0.5 - Math.random()})//打乱数组
            
            //判断方格周围是否都是雷 如果是的话 要重新生成雷区 从而避免成片雷区的存在
            var br=0,//所在行
                x=mineField.x,
                L_T,T,R_T,L,R,L_B,B,R_B;
            for(var i=0;i<num;i++){
                br=Math.ceil((i+1)/x);
                L_T = i-x-1;
                T   = i-x;
                R_T = i-x+1;
                L   = i-1;
                R   = i+1;
                L_B = i+x-1;
                B   = i+x;
                R_B = i+x+1;
                  //坐上角 如果在雷区 并且是在上一行 并且他不是雷 就进行下一方格检测
                  if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&mineField.mineMap[L_T]==0){continue}
                  if(T  >=0&&Math.ceil((T  +1)/x)==br-1&&mineField.mineMap[T  ]==0){continue}
                  if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&mineField.mineMap[R_T]==0){continue}
                  
                  if(L>=0  &&Math.ceil((L+1)/x)==br&&mineField.mineMap[L]==0){continue}
                  if(R<num&&Math.ceil((R+1)/x)==br&&mineField.mineMap[R]==0){continue}
                  
                  if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&mineField.mineMap[L_B]==0){continue}
                  if(B  <num&&Math.ceil((B  +1)/x)==br+1&&mineField.mineMap[B  ]==0){continue}
                  if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&mineField.mineMap[R_B]==0){continue}
                  
                  setMineMap();
                  return false
            }
            //统计非雷方格周围的雷数
            for(i=0;i<num;i++){
                  if(mineField.mineMap[i]==-1){continue}
                  var thisMineNum=0
                  br=Math.ceil((i+1)/x);
                  L_T = i-x-1;
                  T   = i-x;
                  R_T = i-x+1;
                  L   = i-1;
                  R   = i+1;
                  L_B = i+x-1;
                  B   = i+x;
                  R_B = i+x+1;
                 
                  if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&mineField.mineMap[L_T]==-1){thisMineNum++;}
                  if(T  >=0&&Math.ceil((T  +1)/x)==br-1&&mineField.mineMap[T  ]==-1){thisMineNum++;}
                  if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&mineField.mineMap[R_T]==-1){thisMineNum++;}
                  
                  if(L>=0  &&Math.ceil((L+1)/x)==br&&mineField.mineMap[L]==-1){thisMineNum++;}
                  if(R<num&&Math.ceil((R+1)/x)==br&&mineField.mineMap[R]==-1){thisMineNum++;}
                  
                  if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&mineField.mineMap[L_B]==-1){thisMineNum++;}
                  if(B  <num&&Math.ceil((B  +1)/x)==br+1&&mineField.mineMap[B  ]==-1){thisMineNum++;}
                  if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&mineField.mineMap[R_B]==-1){thisMineNum++;}
                  
                  mineField.mineMap[i]=thisMineNum;
            }
    }
    //----------------------------------雷区事件
    function setEvent(){
            var thisMineFiele=mineField._mineFieldBlock,
                allMine=mineField._mineFieldEle,
                iMax=mineField.x*mineField.y;
            for(var i=0;i<iMax;i++){
                allMine[i].index=i;
                allMine[i].on=0;//0为默认  1为插旗  2为问号  3为显示
            }
            thisMineFiele.onmouseup=function(e){
                if(mineField.status==2){return false;}
                if(mineField.status==0){mineField.status=1;timedCount();}
                var e=e||window.event,
                    thisObj=e.target||e.srcElement;
                if(thisObj.nodeName=='UL'||thisObj.on==3){return false;}
                
                var Btn=getButton(e);
                if(Btn== 0){//左键
                   if(thisObj.on==1){return false;}//插旗子了  就不能点了
    
                   if(mineField.mineMap[thisObj.index]==-1){//点雷了
                       setThisMine('peng',thisObj.index);
                   }else if(mineField.mineMap[thisObj.index]==0){//点到空地了 打开一大片
                       //alert('你运气真好')
                       var allShowMine=minesShow(thisObj.index);
                       setThisMine('show',allShowMine)
                   }else{//显示一个格子
                       setThisMine('show',thisObj.index)
                   }
                }
                if(Btn== 2){//右键
                  setThisMine('setOn',thisObj.index);
                }
            }
    }
    //--------------------------------按到空格时 显示一大片
    function minesShow(I){
                var allMine=mineField._mineFieldEle,
                    allShowMine=[I];//保存要显示的雷的下标
                
                allMine[I].on=3;
                
                see(I);//查询下标为I的周围的方格
                function see(allI){
                    var _allI=[];
                    if(Object.prototype.toString.call(allI) === '[object Array]'){
                        for(var i=0;i<allI.length;i++){f(allI[i])}
                    }
                    else{f(allI)}
                    function f(thisI){
                        var text,
                        x=mineField.x,
                        br,
                        num=x*mineField.y,
                        L_T,T,R_T,L,R,L_B,B,R_B;
                    
                        text='_'+allShowMine.join('_')+'_';//用来判断下标是否已经写入数组
                        br=Math.ceil((thisI+1)/x);
                        L_T = thisI-x-1;
                        T   = thisI-x;
                        R_T = thisI-x+1;
                        L   = thisI-1;
                        R   = thisI+1;
                        L_B = thisI+x-1;
                        B   = thisI+x;
                        R_B = thisI+x+1;
                      //左上角的方格 如果是在雷区 又是在上一行 又是没翻开的格子 又是空格 那么就写如_allI数组 来进行下一次检索
                      if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&allMine[L_T].on==0&&mineField.mineMap[L_T] == 0){_allI.push(L_T);}
                      if(T  >=0&&Math.ceil((T  +1)/x)==br-1&&allMine[T  ].on==0&&mineField.mineMap[T  ] == 0){_allI.push(T);}
                      if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&allMine[R_T].on==0&&mineField.mineMap[R_T] == 0){_allI.push(R_T);}
                  
                      if(L>=0&&Math.ceil((L+1)/x)==br&&allMine[L].on==0&&mineField.mineMap[L] == 0){_allI.push(L);}
                      if(R<num&&Math.ceil((R+1)/x)==br&&allMine[R].on==0&&mineField.mineMap[R] == 0){_allI.push(R);}
                  
                      if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&allMine[L_B].on==0&&mineField.mineMap[L_B] == 0){_allI.push(L_B);}
                      if(B  <num&&Math.ceil((B  +1)/x)==br+1&&allMine[B  ].on==0&&mineField.mineMap[B  ] == 0){_allI.push(B);}
                      if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&allMine[R_B].on==0&&mineField.mineMap[R_B] == 0){_allI.push(R_B);}
                      //------------------------------------------------
                      //左上角的的格子 如果在雷区 又是在上一行 又是没翻开的格子 又是没写入allShowMine数组的 那就写入吧 并提前标记为翻开的格子
                      if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&allMine[L_T].on==0&&text.indexOf('_'+L_T+'_') == -1){allShowMine.push(L_T);allMine[L_T].on=3}
                      if(T  >=0&&Math.ceil((T  +1)/x)==br-1&&allMine[T  ].on==0&&text.indexOf('_'+T+'_') == -1){allShowMine.push(T);allMine[T].on=3}
                      if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&allMine[R_T].on==0&&text.indexOf('_'+R_T+'_') == -1){allShowMine.push(R_T);allMine[R_T].on=3}
                  
                      if(L>=0&&Math.ceil((L+1)/x)==br&&allMine[L].on==0&&text.indexOf('_'+L+'_') == -1){allShowMine.push(L);allMine[L].on=3}
                      if(R<num&&Math.ceil((R+1)/x)==br&&allMine[R].on==0&&text.indexOf('_'+R+'_') == -1){allShowMine.push(R);allMine[R].on=3}
                  
                      if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&allMine[L_B].on==0&&text.indexOf('_'+L_B+'_') == -1){allShowMine.push(L_B);allMine[L_B].on=3}
                      if(B  <num&&Math.ceil((B  +1)/x)==br+1&&allMine[B  ].on==0&&text.indexOf('_'+B+'_') == -1){allShowMine.push(B  );allMine[B ].on=3}
                      if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&allMine[R_B].on==0&&text.indexOf('_'+R_B+'_') == -1){allShowMine.push(R_B);allMine[R_B].on=3}
                      
                      if(_allI.length!=0){see(_allI)}
                    }
                }
                return allShowMine
    }
    //--------------------------------------
    document.oncontextmenu=function(){return false;}//禁止右键菜单
    function getButton(e){
        var Btn;
        if(document.implementation.hasFeature('MouseEvents','2.0')){Btn=e.button;}
        else{        switch(e.button){
                        case 0:
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                          Btn=0;
                          break;
                        case 2:
                        case 6:
                          Btn=2;
                          break;
                        case 4:
                          Btn=9;
                          break;
                    }
        }
        return Btn;
    }
    </script>
  • 相关阅读:
    linux的find命令详解
    在接口中的静态方法来获取model的实例对象
    php函数decbin
    cookie的默认有效目录
    html的base标签
    mysql多位小数字段用decimal类型
    vmware在桥接模式下配置centos7网络
    iis_rewrite3突然无法使用(因为它过期啦)
    LightGBM 调参方法(具体操作)
    沪深股票的复权计算(复权因子的应用)--代码实现
  • 原文地址:https://www.cnblogs.com/chocho/p/4419441.html
Copyright © 2011-2022 走看看