下面先上效果图

上图为最终效果,界面没美化,有点丑将就将就,,,,哈哈
不多说,上代码看注释已经注释好多,扫雷主要难度在于计算但前点击周围你的安全区域,我的想法是:递归循环计算当前点击的上、下、左、右4个格子,如果遇到空白则继续,如果遇到周围有雷则停止。
由中心点往外扩散,在扩散中肯定回遇到已经处理过的格子,则跳过continue。。。。
html代码
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>扫雷游戏</title>
<style>
*{padding:0;margin:0;}
.main{
margin: 10px 0 0 10px;
}
.head{
}
.body{
margin: 10px;
}
.minefield,
.minefield tr,
.minefield td{border:1px solid #000;}
.minefield td{
color:#00f;
width: 20px;
height: 20px;
text-align: center;
cursor: pointer;
}
/*.minefield td:hover{background-color:#ccc;}*/
/*初始化颜色*/
.init-color{background-color: #ddd;}
/*打开颜色*/
.oper-color{background-color: #fff;}
/*标志颜色*/
.flag-color{background-color: #00FF00;}
/*雷颜色*/
.mine-color{background-color: #f00;}
fieldset{
padding: 5px;
width: 800px;
font-size: 14px;
}
legend{
font-size: 12px;
color: #00f;;
}
.info{
font-size: 12px;
color: #00f;
}
</style>
</head>
<body>
<div class="main">
<div class="head">
<fieldset>
<legend>难度</legend>
<fieldset>
<legend><input type="radio" name="define" checked="checked" value="1"/>系统定义</legend>
<label title="9x9,10"><input type="radio" name="diff" checked="checked" value="1"/>初级</label>
<label title="16x16,40"><input type="radio" name="diff" value="2"/>中级</label>
<label title="16x30,99"><input type="radio" name="diff" value="3"/>高级</label>
</fieldset>
<fieldset>
<legend><input type="radio" name="define" value="0"/>自定义</legend>
<label>行数(9~24):<input type="text" id="rowNum" value="9"/></label>
<label>列数(9~30):<input type="text" id="colNum" value="9"/></label>
<label>雷数(10~668):<input type="text" id="mineNum" value="10"/></label>
</fieldset>
<button type="button" id="start">走你</button>
<div class="body" id="minefield"></div>
<div class="info">
<label>用时:<span id="useTime">0</span>秒</label> <span id="gameEnd"></span>
</div>
</fieldset>
</div>
</div>
<script src="jquery-1.9.1.min.js"></script>
<script src="minefield.jquery.js"></script>
<script>
$(function(){
$(‘#start‘).bind(‘click‘, function(){
var data = {},
define = $(‘input[name="define"]:checked‘).val(),
diff = $(‘input[name="diff"]:checked‘).val(),
rowNum = $.trim($(‘#rowNum‘).val()),
colNum = $.trim($(‘#colNum‘).val()),
mineNum = $.trim($(‘#mineNum‘).val());
// 选择系统定义
if(define == ‘1‘){
switch(diff){
case ‘1‘:
data = {
rowNum: 9,
colNum: 9,
mineNum: 10
}
break;
case ‘2‘:
data = {
rowNum: 16,
colNum: 16,
mineNum: 40
}
break;
case ‘3‘:
data = {
rowNum: 16,
colNum: 30,
mineNum: 99
}
break;
}
}else{
// 选择自定义
if(9 > rowNum || rowNum > 24){
alert(‘o no~~最多只能是24行,9~24!!‘);
return ;
}
if(9 > colNum || colNum > 30){
alert(‘擦最多只能是30列,9~30!!‘);
return ;
}
// 这里根据列、行计算最多雷数怎么计算?希望高手指点一二~~
if(9 > mineNum || mineNum > 668 || mineNum > (rowNum*colNum-1) ){
alert(‘干,这是要死的节奏啊,弄这么多雷!!‘);
return ;
}
if(rowNum && !isNaN(rowNum)){
data.rowNum = parseInt(rowNum);
}
if(colNum && !isNaN(colNum)){
data.colNum = parseInt(colNum);
}
if(mineNum && !isNaN(mineNum)){
data.mineNum = parseInt(mineNum);
}
}
// 清除下面计时器
clearTimeout(timeFlag);
$(‘#gameEnd‘).empty();
// 游戏启动时调用
data.gameStart = function(){
useTime(1);
$(‘#gameEnd‘).html(‘进行中....加油~使劲~‘);
}
data.gameEnd = function(flag){
clearTimeout(timeFlag);
var time = $(‘#useTime‘).text();
var str = ‘‘;
if(flag){
// 游戏通过后可以根据条件给玩家定义一些级别
if(time <= 20){
str = ‘你雷逼‘;
}
if(20 < time < 50){
str = ‘你牛逼!‘;
}
if(50<=time<100){
str = ‘恭喜你过关!‘;
}
if(time >= 100){
str = ‘终于过了,不容易啊~~~‘;
}
$(‘#gameEnd‘).html(‘<span style="color:#0f0;">‘+str+‘</span>‘);
}else{
$(‘#gameEnd‘).html(‘<span style="color:#f00;">真是彩笔~~</span>‘);
}
}
// 启动游戏
$(‘#minefield‘).minefield(data);
});
// 初始化
$(‘#start‘).click();
});
// 计时器
var timeFlag;
function useTime(time){
$(‘#useTime‘).text(time);
timeFlag = setTimeout(function(){
useTime(time+1);
},1000);
}
</script>
</body>
</html>
minefield.jquery.js 脚本代码
/**
* minefield.jquery.js
* 扫雷插件
* CBQ 343330602@qq.com
*/
(function(window, $){
//扩展array indexOf方法
if(!Array.prototype.indexOf){
Array.prototype.indexOf = function(v){
var i , len;
for(i=0,len=this.length;i<len;i++){
if(this[i] == v){
return i;
}
}
return -1;
}
}
function Minefield( options, dom ){
this._default = {
init: true, // 是否初始化
rowNum: 9, // 多少行
colNum: 9, // 多少列
mineNum: 10, // 累的个数
gameStart: function(){},
gameEnd: function(){}
};
this.settings = $.extend(true, this._default, options); // 用户配置
this.$dom = $(dom); // 当前插入扫雷dom对象
this.$table = $(‘<table class="minefield" border="1" cellpadding="1" cellspacing="1"><tbody></tbody></table>‘); // 扫雷对象
this.mineData = []; // 雷分布数组(包括所有对象)
this.minePosition = []; // 存储雷区位置(只有雷区)
this.mineNumData = []; // 每个格子的雷数
this.gameStart = false;
this.gameOver = false;
this.tempSafeArea = [];
this._init(); // 初始化
}
// 扩展prototype对象
$.extend(Minefield.prototype,{
// 初始化函数
_init: function(){
var me = this;
// 创建地雷分布区域
me._createMineData();
// 创建用户交互界面
me._createGame();
// 创建事件监听
me._addEvent();
},
// 创建雷的分布区域
_createMineData: function(){
var me=this,
i=0, j=0,
rowNum = me.settings.rowNum,
colNum = me.settings.colNum,
max = rowNum * colNum,
mineNum = me.settings.mineNum,
mineData = me.mineData,
minePosition = me.minePosition,
mine;
for(i=0; i<max; i++){
mineData.push(0);
}
// 生成雷
for(j=0;j<mineNum;){
mine = Math.floor(Math.random()*(max-1));
//如果生成的雷已经存在,则重新生成
if(minePosition.indexOf(mine) == -1){
minePosition.push(mine);
mineData[mine] = 1;
j++;
}
}
},
// 创建用户交互界面
_createGame: function(){
var me=this,
i=0, j=0,index = 0,
rowNum = me.settings.rowNum,
colNum = me.settings.colNum,
mineData = me.mineData,
mineNumData = me.mineNumData,
trs=[], tds=[],
isMine = 0
;
for(i=0; i<rowNum; i++){
tds.splice(0, colNum);
for(j=0; j<colNum; j++){
isMine = mineData[index];
// 获取每个格子的旁边的地雷数量,如果格子本身就是地雷则为 -1
if(isMine == 1){
mineNumData[index] = -1;
}else{
mineNumData[index] = me.getMineNumber(j, i);
}
// tds.push(‘<td class="init-color"> ‘+index+‘,‘+isMine+‘,‘+mineNumData[index]+‘</td>‘);
// tds.push(‘<td class="init-color"> ‘+isMine+‘,‘+mineNumData[index]+‘</td>‘);
tds.push(‘<td class="init-color"> </td>‘);
index++;
}
trs.push(‘<tr>‘ + tds.join(‘‘) + ‘</tr>‘);
}
me.$table.find(‘tbody‘).append(trs.join(‘‘));
me.$dom.empty().append(me.$table);
},
// 绑定事件
_addEvent: function(){
var me = this;
// 只为table添加事件,这样可以减少多余不必要的事件,如果给每个格子添加点击事件那要污染多少
me.$table
.bind(‘click‘, function(e){
var target = e.target, $currTr,
currIndex,mineNum,
name = target.nodeName.toLowerCase(),
allSafeArea;
var $currTd;
if(name == ‘td‘){
// 如果游戏已经结束则无需继续往下走
if(!me.gameStart){
me.gameStart = true;
me.settings.gameStart ? me.settings.gameStart():‘‘;
}
$currTd = $(target); // 当前点击格子
$currTr = $currTd.parent(); // 当前点击行
// 如果格子已经被点击过,则无需再做操作
if($currTd.hasClass(‘open-color‘) || $currTd.hasClass(‘flag-color‘) || me.gameOver){
return ;
}
// 计算当前点击位置 currIndex = (当前行 * 列数) + 当前位置 ,因为使用table布局所以点击没行格子都会从0开始
currIndex = ($currTr.index() * me.settings.colNum) + $currTd.index();
mineNum = me.mineNumData[currIndex];
switch(mineNum){
case 0 : // 安全区
// 清空安全区,重新计算
me.tempSafeArea.splice(0,me.tempSafeArea.length);
// 计算当前点击格子旁边的安全格子
me._getLRUDSafeArea($currTd.index(), $currTr.index());
// 修改安全格子背景颜色
me._setSafeBgColor( me.tempSafeArea );
if(me._isWin()){
// 获胜事件
me.settings.gameEnd ? me.settings.gameEnd(true):‘‘;
}
break;
case -1 : // 雷区
$currTd.addClass(‘mine-color‘);
me.gameOver = true;
me._showMine();
// 失败事件
me.settings.gameEnd ? me.settings.gameEnd(false):‘‘;
break;
default: // 其他
$currTd.removeClass(‘init-color‘).addClass(‘open-color‘).text(mineNum);
if(me._isWin()){
// 获胜事件
me.settings.gameEnd ? me.settings.gameEnd(true):‘‘;
}
break;
}
}
})
.bind(‘contextmenu‘, function(e){ // 右击事件,用于标识自己认为的雷区,或解除
e.stopPropagation();
var target = e.target,
name = target.nodeName.toLowerCase();
var $currTd;
if(name == ‘td‘ && !me.gameOver){
$currTd = $(target);
if( $currTd.hasClass(‘init-color‘) ){
$currTd.removeClass(‘init-color‘).addClass(‘flag-color‘);
return false;
}
if( $currTd.hasClass(‘flag-color‘) ){
$currTd.removeClass(‘flag-color‘).addClass(‘init-color‘);
return false;
}
}
return false;
})
;
},
// 获取每个单元的上、下、左、右、左上、右上、左下、右下八个位置的雷分布
getMineNumber: function( x, y ){
var me = this,
mineData = me.mineData,
rowNum = me.settings.rowNum,
colNum = me.settings.colNum,
index = y * colNum + x,
upNum = parseInt(index)-parseInt(colNum),
downNum = parseInt(index)+parseInt(colNum),
mineNum = 0;
// 获取左值,如果是第一个值则不计算
if(x > 0 && mineData[index - 1] == 1){
mineNum += 1;
}
// 获取右值,如果是每行的最后一个值则不计算
if(x<(colNum-1) && mineData[index + 1] == 1){
mineNum += 1;
}
// 获取上方值,如果是第一行则不计算
if(y>0 && mineData[upNum] == 1){
mineNum += 1;
}
// 获取下方值,如果是第一行则不计算
if(y<(rowNum-1) && mineData[downNum] == 1){
mineNum += 1;
}
// 获取左上角一个值,如果是第一个值则不计算
if(x>0 && y>0 && mineData[upNum-1] == 1){
mineNum += 1;
}
// 获取右上角一个值,如果是第一个值则不计算
if(x<(colNum-1) && y>0 && mineData[upNum+1] == 1){
mineNum += 1;
}
// 获取左下角一个值,如果是第一个值则不计算
if(x>0 && y<(rowNum-1) && mineData[downNum-1] == 1){
mineNum += 1;
}
// 获取右下角一个值,如果是第一个值则不计算
if(x<(colNum-1) && y<(rowNum-1) && mineData[downNum+1] == 1){
mineNum += 1;
}
return mineNum;
},
// 获取当前格子的上(Up)、下(Down)、左(Left)、右(Right)安全区
_getLRUDSafeArea: function(x, y){
var me = this,
mineNumData = me.mineNumData,
rowNum = parseInt(me.settings.rowNum),
colNum = parseInt(me.settings.colNum),
index = y * colNum + x,
mineNum;
// 如果已经登记过的安全区,则不再查看
if(me.tempSafeArea.indexOf(index) != -1){
return ;
}
mineNum = mineNumData[index];
// 记录安全区
me.tempSafeArea.push(index);
// 如果但前安全区周边没有任何危险,则查看上下左右区域是否安全
if(mineNum == 0 ){
// 左边
if(x>0){
me._getLRUDSafeArea(x-1, y);
}
// 右边
if(x<(colNum-1)){
me._getLRUDSafeArea(x+1, y);
}
// 上边
if(y>0){
me._getLRUDSafeArea(x, y-1);
}
// 下边
if(y<(rowNum-1)){
me._getLRUDSafeArea(x, y+1);
}
}
},
_setSafeBgColor: function( allSafeArea ){
var me = this,
mineNumData = me.mineNumData,
i, len,
$tds = me.$table.find(‘td‘),
$td;
for(i=0,len=allSafeArea.length; i<len; i++){
$td = $($tds.get(allSafeArea[i]));
if($td.hasClass(‘init-color‘)){
$td.removeClass(‘init-color‘).addClass(‘open-color‘).html(mineNumData[allSafeArea[i]] || ‘ ‘);
}
}
},
// 每次点击判断是否赢了
_isWin: function(){
var me = this;
if(me.$table.find(‘.init-color,.flag-color‘).size() == me.settings.mineNum){
return true;
}
return false;
},
// 显示所有雷区
_showMine: function(){
var me = this,
i, len,
minePosition = me.minePosition,
$tds = me.$table.find(‘td‘);
for(i=0,len=minePosition.length; i<len; i++){
$($tds[minePosition[i]]).addClass(‘mine-color‘);
}
}
});
// jquery插件
$.fn.minefield = function( options ){
return this.each(function(index, dom){
new Minefield( options, dom );
});
};
})(window, jQuery);
原文:http://www.cnblogs.com/chenbinqun/p/4192467.html