js 游戏编程:扫雷

news/发布时间2024/5/18 13:41:26

全程无参考代码,完全自己设计和编写的代码哦~

<meta charset="UTF-8">
<style>
.unit, .active, .bomb, .white, .flag {text-align: center;width: 2.5rem;height: 2.5rem;background-color: rgb(129, 169, 245);color: white;font-weight: bolder;
}
.active {background-color: rgb(61, 105, 187) !important;
}
.bomb {background-color: rgb(227, 40, 40) !important;
}
.white {background-color: rgb(73, 94, 133) !important;
}
.flag {background-color: rgb(247, 169, 86) !important;
}
</style>
<div id="main"></div>
<script>
// 数学工具
const random = () => Math.random();
const floor = (v) => Math.floor(v);
// main 区域
let main = document.getElementById('main');
///// 地板 mtx - 地板单位元素 box
// 1 - 创建 地板 mtx 的容器
let mtx;
let rn = 10;
let cn = 10;
let crtMtx = (rnn, cnn) => {// 创建行容器if(rnn !== undefined) rn = rnn;if(cnn !== undefined) cn = cnn;mtx = new Array(rn);for(var i = 0; i < rn; i++){// 创建当前行 每一列 box 的容器mtx[i] = new Array(cn + 1);// 每一行的第一列 为 当前行每一列 box 的父容器(行) secmtx[i][0] = document.createElement('section');// 将每一行对应的 sec 容器 渲染到 main 容器上main.appendChild(mtx[i][0]);}
}
// 2 - 创建 地板元素 box(包括 这个地砖 的相关数据)
let geneBoxAndData = (x, y) => {var box = document.createElement('button');box.className = 'unit';box.innerHTML = '&nbsp;';// 记录 box 的坐标box.setAttribute("x", x);box.setAttribute("y", y);// var val = 0; // 是雷:-1,不是雷-周围雷的个数:0-8,被打开 +8return {"e":box, "v":0};
}
// 3 - 整个地板,生成每个地砖,并渲染到页面
let geneMtxData = () => {for(var r = 0; r < mtx.length; r++){var colSec = mtx[r][0];for(var c = 1; c < mtx[0].length; c++){// 生成数据var data = geneBoxAndData(r, c);// 加入dom和数据colSec.appendChild(data.e);mtx[r][c] = data;}}
}
//// 1 - 整个地板,地雷生成(在mtx上生成num个雷)
//// 2 - 必须管理每个地雷 --- 地雷列表
////  2.1 - 列表的元素 是地雷的坐标(r, c)
let bombs = [];
//    2.2 - 第一次点击之后的位置 不能是地雷
let first = [5, 5];
let geneBombs = (num) => {if(num > (rn * cn) >> 2) {alert('雷的数量不能超过当前地砖的25%');initGlobal();return;}var rdmRow = floor(random() * (mtx.length - 1));var rdmCol = floor(random() * (mtx[0].length - 1)) + 1;for(var i = 0; i < num; i++){while(mtx[rdmRow][rdmCol].v === -1 || (rdmRow < first[0] + 2 && rdmRow > first[0] - 2 && rdmCol < first[1] + 2 && rdmCol > first[1] - 2)){rdmRow = floor(random() * (mtx.length - 1));rdmCol = floor(random() * (mtx[0].length - 1)) + 1;} mtx[rdmRow][rdmCol].v = -1;// 管理这个雷的位置bombs.push([rdmRow, rdmCol]);}
}
//// 确定 整个地板-每个地砖 的地雷数据
// 1 - 确定 一个雷对周围地砖的影响
let oneBombData = (r, c) => {for(var i = -1; i < 2; i++){var row = r + i;// 行存在if(row < 0 || row >= mtx.length) continue;for(var j = -1; j < 2; j++){var col = c + j;// 列存在if(col < 1 || col >= mtx[0].length) continue;// 当前行列位置 不是雷if(mtx[row][col].v != -1) mtx[row][col].v++;}}
}
// 2 - 确定 所有地雷对整个地砖的影响
let allBombsData = () => {for(var i = 0; i < bombs.length; i++){oneBombData(bombs[i][0], bombs[i][1]);}
}
//// 渲染一个地砖 并访问
let renderVisitOne = (r, c)=>{var data = mtx[r][c];// 访问vst.set(`${r},${c}`, "");vstnum++;// 渲染if(data.v < 1) data.e.innerHTML = data.v == -1 ? '#' : '&nbsp;';else data.e.innerHTML = data.v;if(data.v == -1) data.e.className = "bomb";else if(data.v == 0) data.e.className = "white";else data.e.className = "active";
}
//let renderBombsData = () => {
//    for(var r = 0; r < mtx.length; r++){
//        for(var c = 1; c < mtx[0].length; c++)
//            renderVisitOne(r, c);
//    }
//}
// 求单次点击最大扩大范围
//  - 防止重复遍历,记录已访问位置
let vst = new Map();
let dfs = (r, c) => {renderVisitOne(r, c);if(mtx[r][c].v == -1) {isFail = true;return;}for(var i = -1; i < 2; i++){var row = r + i;// 行存在if(row < 0 || row >= mtx.length) continue;for(var j = -1; j < 2; j++){var col = c + j;// 列存在if(col < 1 || col >= mtx[0].length) continue;// 当前行列位置 是0if(!vst.has(`${row},${col}`)){if(mtx[row][col].v == 0) dfs(row, col);else if(mtx[r][c].v == 0 && mtx[row][col].v > 0 ) renderVisitOne(row, col);}}}
}
// main
// 长按逻辑 - 是否插旗了
let flags = new Map();
// 长按逻辑 - 时间点之差
let downTime;
let ltOrC = (ev, flt = nextLongTouch, fc = nextClick, t = 200) => {if(ev.timeStamp - downTime > t) flt(ev);else fc(ev);
}
let getDownNow = (ev) => downTime = ev.timeStamp;
// LongTouchEv
let addLTEv = (e, flt, fc, t) => {e.addEventListener('mousedown', getDownNow);e.addEventListener('touchstart', getDownNow);downTime = new Date().getTime(); // 初始化时间戳e.addEventListener('mouseup', ltOrC);e.addEventListener('touchend', ltOrC);
}
let removeLTEv = (e) => {e.removeEventListener('mousedown', getDownNow);e.removeEventListener('touchstart', getDownNow);e.removeEventListener('mouseup', ltOrC);e.removeEventListener('touchend', ltOrC);
}
// 第二次及以后的点击事件
let nextClick = (ev) => {var btn = ev.target;if(!btn.hasAttribute("x")) return;var x = floor(btn.getAttribute("x"));var y = floor(btn.getAttribute("y"));// 点击逻辑 - dfsif(flags.has(`${x},${y}`)) return;// 没有插旗,就去dfs回溯访问所有能访问/无雷的地砖dfs(x, y); // vst = new Map();if(isFail) {var remd = cntRemindNum();alert('你已经失败了!\n' + '   剩余雷数:' + (remindBombs - remd) + " 个没有扫出来!");initGlobal();}if(vstnum == sum){if(cntRemindNum() == targetBombs){alert('恭喜您已通关!');initGlobal();}}
}
let nextLongTouch = (ev) => {var btn = ev.target;if(!btn.hasAttribute("x")) return;var x = floor(btn.getAttribute("x"));var y = floor(btn.getAttribute("y"));// 长按逻辑 - 插旗 / 拔旗var key = `${x},${y}`;if(flags.has(key)) {flags.delete(key);mtx[x][y].e.className = 'unit';vstnum--;} else {flags.set(key, "");mtx[x][y].e.className = 'flag';vstnum++;}if(vstnum == sum){alert('恭喜您已通关!');initGlobal();}
}
// 第一次的点击事件
let firstClick = (ev) => {// 事件委托var btn = ev.target;first[0] = floor(btn.getAttribute("x"));first[1] = floor(btn.getAttribute("y"));// 生成地雷geneBombs(targetBombs);allBombsData();dfs(first[0], first[1]);// renderBombsData();main.removeEventListener('mousedown', firstClick);main.removeEventListener('touchstart', firstClick);// 添加之后的每次点击事件addLTEv(main, nextLongTouch, nextClick, 1000);
}
let initBombs = () => {// 添加 第一次点击的事件监听main.addEventListener('mousedown', firstClick);main.addEventListener('touchstart', firstClick);
}
// 游戏相关数据
let isFail = false;
let targetBombs = 60;
let remindBombs = targetBombs;
// 当前访问了多少个
//  - 虽然记录了访问数组,但是还要维护访问个数
let vstnum = -1;
// 总数
let sum = 0;
let initGlobal = () => {main.removeEventListener('mousedown', firstClick);main.removeEventListener('touchstart', firstClick);removeLTEv(main);main.innerHTML = '';mtx = null;first = [];bombs = [];vst = new Map();flags = new Map();isFail = false;targetBombs = 5;remindBombs = targetBombs;vstnum = -1;sum = 0;// 开始执行主函数_main_func();
}
// 计算剩余雷数
let cntRemindNum = () => {var remd = 0;flags.forEach((v, k, m) => {var strs = k.split(",");if(mtx[floor(strs[0])][floor(strs[1])].v == -1) remd++;});return remd;
}
let _main_func = (rn, cn) => {crtMtx(rn, cn);sum = rn * cn;geneMtxData();initBombs();
}
_main_func(15, 20);
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/50675051.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

python文件操作

在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件 open(文件路径,访问模式)f = open(test.txt, w)读文件:f1 = open(test1.txt,r)content = f1.read()print(content)readLines返回一个列表,可以遍历 f1 = open(test1.txt,r)content = f1.readlines(…

Java实现自动生成小学四则运算题目的命令行程序

项目Github仓库链接这个作业属于哪个课程 软件工程这个作业要求在哪里 个人项目这个作业的目标 实现一个自动生成简单四则运算题目并进行计算的程序,同时提供核对答案是否正确的功能一、PSP表格PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)Pla…

Learning Auxiliary Monocular Contexts Helps Monocular 3D Object Detection (3)

损失函数分为3种类型: (1) 对于热力图,用以下的Focal Loss计算:(2) 对于深度,采用Laplacian aleatoric uncertainty loss function for depth计算:(3) 对于尺寸采用L1 Loss计算:

在 SDXL 上用 T2I-Adapter 实现高效可控的文生图

T2I-Adapter 是一种高效的即插即用模型,其能对冻结的预训练大型文生图模型提供额外引导。T2I-Adapter 将 T2I 模型中的内部知识与外部控制信号结合起来。我们可以根据不同的情况训练各种适配器,实现丰富的控制和编辑效果。 同期的 ControlNet 也有类似的功能且已有广泛的应用…

Tomcat 8部署war包

安装 首先在Tomcat官网下载对应版本的压缩包解压文件后配置环境变量在系统变量下新建: 变量名为CATALINA_HOME, 变量值为安装路径在Path后添加%CATALINA_HOME%\bin;%CATALINA_HOME%\lib之后进入安装目录的bin目录下, 双击打开start.bat, 等出现start Server startup in xxx ms后…

[CF762D] Maximum path 题解

观察性质,优化 DP[CF762D] Maximum path 题解 想法 首先考虑问题的弱化版,如果不能往左走,能取到的最大值是多少。 这个问题可以用一个显然的 DP 解决,\(f_{i,j}\) 表示走到第 \(i\) 列,第 \(j\) 行,并且不会再访问这一列其它的方格,能取到的最大值。 转移可以从三个方向…