版权声明:转载时请以超链接形式标明文章原始出处 http://blog.lonelystar.org/post/18.html

    08年底初学JS的第一个练手作品
     
    翻出来稍作修改
     
    算法神马的没动
     
    另外在搜狗等浏览器上双键点击还有点问题
     
    网址是
     
     
    HTML语言:
    <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(mine.gif) no-repeat center}
    td.Boom{background:#F00 url(mine.gif) no-repeat center}
    td.Flag, td.ErrFlag{background-image: url(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='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='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='success.gif';
        },
       
        //游戏失败结束
        fFail:function(){
            this.GameOver=true;
            $('btnRefreshMap').src='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='flag.gif';
    HappyImg.src='happy.gif';
    MineImg.src='mine.gif';
    SadImg.src='sad.gif';
    SuccessImg.src='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>

    Tag:javascript  经典  扫雷  

      本文现有3 条评论

    • 1  不错,,支持ixa

    • 2  高手啊

    • 3  好好玩的 游戏 我喜欢
      www.oustudy.com

    欢迎您发表评论:

     
    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。