运行效果

操作方法
- 单击绿色环形按钮即可开局,用任何工具首次点击雷区不会出现游戏失败情况;
- 点击左侧图标选择工具,选择不同工具点击雷区效果不同;
- 红旗图标为windows扫雷右击,普通箭头图标为windows扫雷左击,金色箭头图标为windows扫雷左右同时;
- 点击右侧太阳或月亮可切换显示模式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
html, body {
width: 100%;
height: 100%;
}
#form {
display: inline-block;
}
#form table {
border-spacing: 2px;
}
#form td {
width: 2vw;
height: 2vw;
text-align: center;
vertical-align: middle;
position: relative;
}
#form td svg {
position: absolute;
top: 0;
left: 0;
}
.visited {
background-color: transparent;
}
tr {
width: 100%;
}
tr svg {
display: table-cell;
}
*[name='btn'] {
width: 100%;
}
.big {
transform: scale(1.5);
}
.btn-box {
width: 100px;
}
#tools td {
background-color: transparent;
}
#tools td div {
margin: 2vw;
width: 6vw;
height: 6vw;
position: relative;
overflow: show;
}
#tools td div svg {
position: absolute;
margin: auto;
}
.light {
background-color: white;
}
.light * {
color: black;
}
.dark {
background-color: #040404;
}
.dark * {
color: white;
}
.unclc {
background-color: #4444;
transition: all 3s;
}
.dark .unclc {
background-color: #4444;
transition: all 3s;
}
.unclc:hover {
background-color: #4448;
transition: all 0s;
}
.dark .unclc:hover {
background-color: #4448;
transition: all 0s;
}
table {
text-align: center;
}
.mine {
fill: #fff;
}
.dark .mine {
fill: #c33;
}
.died {
background-color: #f009;
}
.dark .died {
background-color: #fff8;
}
.clock {
fill: #000;
}
.dark .clock {
fill: #f44;
}
.restart:hover * {
animation: rot 1.25s linear infinite;
-ms-animation: rot 1.25s linear infinite;
-webkit-animation: rot 1.25s linear infinite;
-moz-animation: rot 1.25s linear infinite;
-o-animation: rot 1.25s linear infinite;
}
.restart:active * {
animation: rot 1.25s linear infinite;
-ms-animation: rot 1.25s linear infinite;
-webkit-animation: rot 1.25s linear infinite;
-moz-animation: rot 1.25s linear infinite;
-o-animation: rot 1.25s linear infinite;
}
@keyframes rot {
from {
transform-origin: 50% 50%;
}
to {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}
@-ms-keyframes rot {
from {
transform-origin: 50% 50%;
}
to {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}
@-webkit-keyframes rot {
from {
transform-origin: 50% 50%;
}
to {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}
@-moz-keyframes rot {
from {
transform-origin: 50% 50%;
}
to {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}
@-o-keyframes rot {
from {
transform-origin: 50% 50%;
}
to {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}
</style>
</head>
<body class="light">
<table class="win">
<tr>
<td id="timer">
</td>
</tr>
<tr>
<td id="box">
<table id="tools">
<tr>
<td class="btn-box">
<div data-id="1" name="btn" ontap="setMode(1)" onclick="setMode(1)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M50,13A37,37,0,1,1,13,50,37.04192,37.04192,0,0,1,50,13M50,0a50,50,0,1,0,50,50A50,50,0,0,0,50,0Z" fill="#888" opacity="0.5" />
<polygon points="50 99.037 40.926 100 15.411 4.777 24.118 2.444 50 99.037" fill="gray" />
<polygon points="61.14 42.93 40.68 64.24 24.12 2.44 50.29 2.44 61.14 42.93" fill="#b22" />
<polygon points="75.9 21.31 56.18 41.86 45.33 1.37 70.56 1.37 75.9 21.31" fill="#d33" />
<polygon points="61.14 42.93 56.182 41.86 59.834 38.055 61.14 42.93" fill="#c22" />
<polygon points="93.3 0 74.16 19.94 68.82 0 93.3 0" fill="#f44" />
<polygon points="75.234 18.822 75.9 21.31 74.16 19.94 75.234 18.822" fill="#e33" />
</svg>
</div>
</td>
</tr>
<tr>
<td class="btn-box">
<div data-id="0" name="btn" ontap="setMode(0)" onclick="setMode(0)">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
<defs>
<linearGradient id="a" x1="50" y1="6.42815" x2="50" y2="93.57185" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#f6e9b4" />
<stop offset="1" stop-color="#ad8a50" />
</linearGradient>
</defs>
<path d="M50,13A37,37,0,1,1,13,50,37.04192,37.04192,0,0,1,50,13M50,0a50,50,0,1,0,50,50A50,50,0,0,0,50,0Z" fill="#888" opacity="0.5" />
<polygon points="93.572 36.591 6.428 6.428 36.591 93.572 51.237 61.812 82.997 93.572 93.572 82.997 61.812 51.237 93.572 36.591" stroke="#4b4239"
stroke-miterlimit="10" stroke-width="4" fill="url(#a)" />
<polygon
points="81.838 28.644 70.614 34.545 72.758 22.047 63.677 13.195 76.226 11.372 81.838 0 87.451 11.372 100 13.195 90.919 22.047 93.063 34.545 81.838 28.644"
fill="#fbb03b" />
</svg>
</div>
</td>
</tr>
<tr>
<td class="btn-box">
<div data-id="-1" name="btn" ontap="setMode(-1)" onclick="setMode(-1)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M50,13A37,37,0,1,1,13,50,37.04192,37.04192,0,0,1,50,13M50,0a50,50,0,1,0,50,50A50,50,0,0,0,50,0Z" fill="#888" opacity="0.5" />
<polygon points="93.572 36.591 6.428 6.428 36.591 93.572 51.237 61.812 82.997 93.572 93.572 82.997 61.812 51.237 93.572 36.591" fill="#fff"
stroke="#000" stroke-miterlimit="10" stroke-width="4" />
</svg>
</div>
</td>
</tr>
</table>
</td>
<td id="form"></td>
<td>
<table id="tools">
<tr>
<td class="btn-box">
<div name="btn" ontap="setColor()" onclick="setColor()">
<span id="moon" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M72.851,80.4575a39.3,39.3,0,1,1,0-60.915,30.89293,30.89293,0,1,0,0,60.915Z" fill="#fff" />
</svg>
</span>
<span id="sun">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="30.9" fill="#f7931e" />
<path d="M50,83.45a33.54854,33.54854,0,0,0,11.48-2.02L50,100,38.52,81.43A33.54854,33.54854,0,0,0,50,83.45Z" fill="#f7931e" />
<path d="M50,16.55a33.5471,33.5471,0,0,0-11.48,2.02L50,0,61.48,18.57A33.5471,33.5471,0,0,0,50,16.55Z" fill="#f7931e" />
<path d="M14.64,14.64,35.9,19.66A33.55962,33.55962,0,0,0,19.66,35.9Z" fill="#f7931e" />
<path d="M85.36,85.36,64.1,80.34A33.55937,33.55937,0,0,0,80.34,64.1Z" fill="#f7931e" />
<path d="M18.57,38.52a33.63113,33.63113,0,0,0,0,22.96L0,50Z" fill="#f7931e" />
<path d="M81.43,61.48a33.63113,33.63113,0,0,0,0-22.96L100,50Z" fill="#f7931e" />
<path d="M35.9,80.34,14.64,85.36,19.66,64.1A33.55937,33.55937,0,0,0,35.9,80.34Z" fill="#f7931e" />
<path d="M85.36,14.64,80.34,35.9A33.55962,33.55962,0,0,0,64.1,19.66Z" fill="#f7931e" />
</svg>
</span>
</div>
</td>
</tr>
<tr>
<td class="btn-box">
<div name="btn" onclick="restart()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="restart">
<path d="M100,50a50.00249,50.00249,0,1,1-1.42-11.81H61.81L76.16,23.84A36.99578,36.99578,0,1,0,87,50Z" fill="#5a5" opacity="0.7" />
</svg>
</div>
</td>
</tr>
<tr>
<td class="btn-box">
<div name="btn" onclick="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M50,13A37,37,0,1,1,13,50,37.04192,37.04192,0,0,1,50,13M50,0a50,50,0,1,0,50,50A50,50,0,0,0,50,0Z" fill="#888" opacity="0" />
</svg>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
<script>
const NUM = 0b0001111;
const MINE = 0b0010000;
const FLAG = 0b0100000;
const HIDE = 0b1000000;
var mode = 0;
function setColor() {
let body = document.getElementsByTagName('body')[0];
if (body.getAttribute('class') == 'light') {
body.setAttribute('class', 'dark');
document.getElementById('sun').setAttribute('style', 'display:none;');
document.getElementById('moon').setAttribute('style', '');
} else {
body.setAttribute('class', 'light');
document.getElementById('moon').setAttribute('style', 'display:none;');
document.getElementById('sun').setAttribute('style', '');
}
}
function setMode(v) {
if (mode != v) {
mode = v;
let children = document.getElementsByName('btn');
for (let i = 0, len = children.length; i < len; i++)
children[i].setAttribute('class', children[i].getAttribute('data-id') == mode ? 'big' : '');
}
}
setMode(-1);
var root = document.getElementById('form');
var settings = new Object();
function init(width = 30, height = 16, mine = 99) {
settings.h = Math.min(Math.max(height, 9), 36);
settings.w = Math.min(Math.max(width, 9), 60);
settings.m = Math.min(settings.w * settings.h * 0.2, Math.max(settings.w * settings.h * 0.12, mine));
settings.map = [];
for (let y = 0; y < settings.h; y++) {
settings.map[y] = [];
for (let x = 0; x < settings.w; x++)
settings.map[y][x] = HIDE;
}
settings.playing = false;
settings.living = true;
}
function getNeighbours(x, y) {
let map = [
{
x: x, y: y + 1 }, {
x: x, y: y - 1 }, {
x: x + 1, y: y }, {
x: x + 1, y: y + 1 }, {
x: x + 1, y: y - 1 }, {
x: x - 1, y: y }, {
x: x - 1, y: y + 1 }, {
x: x - 1, y: y - 1 }
];
return map;
}
function ranMines(x, y) {
let map = getNeighbours(x, y);
map.push({
x: x, y: y });
for (let i = 0; i < settings.m;) {
let x1 = parseInt(Math.random() * settings.w);
let y1 = parseInt(Math.random() * settings.h);
let check = settings.map[y1][x1] & MINE;
if (!check) {
let fill = true;
for (let i1 = 0; i1 < 9; i1++)
if (map[i1].x == x1 && map[i1].y == y1) {
fill = false;
break;
}
if (fill) {
settings.map[y1][x1] += MINE;
i++;
}
}
}
for (let y = 0; y < settings.h; y++)
for (let x = 0; x < settings.w; x++) {
let val = 0;
let tmp = [settings.map[y][x + 1], settings.map[y][x - 1]];
if (settings.map[y + 1]) tmp.push(settings.map[y + 1][x + 1], settings.map[y + 1][x], settings.map[y + 1][x - 1])
if (settings.map[y - 1]) tmp.push(settings.map[y - 1][x + 1], settings.map[y - 1][x], settings.map[y - 1][x - 1])
for (let i = 0, len = tmp.length; i < len; i++)
if (tmp[i]) {
let t = tmp[i] & MINE;
if (t) val++;
}
settings.map[y][x] += val;
}
}
function showMine(ele) {
var svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">' +
'<circle cx="50" cy="50" r="30.9" class="mine"/>' +
'<polygon points="89.3 50 80.032 42.707 57.293 19.968 50 10.7 42.707 19.968 ' +
'19.969 42.707 10.7 50 19.969 57.293 42.707 80.032 50 89.3 57.293 80.031 80.032 57.293 89.3 50" class="mine"/>' +
'<polygon points="77.789 22.211 66.079 23.607 33.922 23.607 22.211 22.211 23.607 33.921 ' +
'23.608 66.078 22.211 77.789 33.922 76.392 66.079 76.393 77.789 77.789 76.392 66.078 76.393 33.921 77.789 22.211" class="mine"/>' +
'</svg>';
ele.innerHTML = svg;
}
function showAllMines() {
let lines = root.getElementsByTagName("tr");
for (let linei = 0, l = lines.length; linei < l; linei++) {
for (let y = 0; y < settings.h; y++) {
let line = root.querySelector("tr[data-y='" + y + "']");
for (let x = 0; x < settings.w; x++) {
let mine = settings.map[y][x] & MINE;
if (mine)
showMine(line.querySelector("td[data-x='" + x + "']"));
}
}
}
}
function leftClc(ele, x, y) {
let b = mode;
mode = -1;
let hide = settings.map[y][x] & HIDE;
let flag = settings.map[y][x] & FLAG;
if (hide && !flag) {
let mine = settings.map[y][x] & MINE;
if (mine) {
settings.living = false;
showAllMines(ele);
ele.setAttribute('class', 'died');
} else {
let num = settings.map[y][x] & NUM;
settings.map[y][x] -= HIDE;
ele.setAttribute('class', 'visited');
if (num > 0) ele.innerHTML = num;
else {
let map = getNeighbours(x, y);
for (let i1 = 0; i1 < 8; i1++) {
let m1 = map[i1] & MINE;
let n1 = map[i1] & NUM;
if (map[i1].y >= 0 && map[i1].y < settings.h && map[i1].x >= 0 && map[i1].x < settings.w && !(n1 || m1))
blockClick(undefined, map[i1].x, map[i1].y);
}
}
}
}
mode = b;
}
function setFlag(ele, x, y) {
var svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 120 120">' +
'<polygon points="45.935 72.421 27.155 2.333 35.862 0 55.498 73.282 45.935 72.421" fill="#aaa"/>' +
'<polygon points="35.862 0 100 0 52.421 61.8 35.862 0" fill="#f44" opacity="0.75"/>' +
'<polygon points="0 100 45.935 72.421 55.498 73.282 100 100 0 100" fill="#fff" opacity="0.75"/>' +
'</svg>';
ele.innerHTML = svg;
if (!(settings.map[y][x] & FLAG))
settings.map[y][x] += FLAG;
}
function rightClc(ele, x, y) {
let hide = settings.map[y][x] & HIDE;
let flag = settings.map[y][x] & FLAG;
if (hide) {
if (flag) {
ele.innerHTML = '';
settings.map[y][x] -= FLAG;
}
else
setFlag(ele, x, y);
}
}
function blockClick(element, x, y) {
if (!settings.playing) {
setMode(-1);
ranMines(x, y)
settings.playing = true;
}
if (settings.living && x >= 0 && x < settings.w && y >= 0 && y < settings.h) {
let ele = element ? element : root.querySelector("tr[data-y='" + y + "']").querySelector("td[data-x='" + x + "']");
if (mode < 0) {
leftClc(ele, x, y);
} else if (mode > 0) {
rightClc(ele, x, y);
} else {
blockDoubleClick(ele, x, y);
}
}
}
function blockDoubleClick(ele, x, y) {
let hide = settings.map[y][x] & HIDE; let num = settings.map[y][x] & NUM;
if (!hide) {
let sel = getNeighbours(x, y);
let flagBlock = 0;
for (let i = 0; i < 8; i++) {
if (sel[i].x >= 0 && sel[i].x < settings.w && sel[i].y >= 0 && sel[i].y < settings.h) {
let flag = settings.map[sel[i].y][sel[i].x] & FLAG;
if (flag) flagBlock++;
}
} if (flagBlock >= num) {
for (let i = 0; i < 8; i++)
if (sel[i].x >= 0 && sel[i].x < settings.w && sel[i].y >= 0 && sel[i].y < settings.h)
leftClc(root.querySelector("tr[data-y='" + sel[i].y + "']").querySelector("td[data-x='" + sel[i].x + "']"), sel[i].x, sel[i].y);
return;
}
}
}
function createGameTable(width = 30, height = 16, mine = 99) {
init(30, 16, 99);
let ret = document.createElement('table');
for (let y = 0; y < settings.h; y++) {
let line = document.createElement('tr');
line.setAttribute('data-y', y);
for (let x = 0; x < settings.w; x++) {
let box = document.createElement('td');
box.setAttribute('class', 'unclc');
box.setAttribute('data-x', x);
box.addEventListener('click', function () {
blockClick(box, x, y); }, false);
box.addEventListener('tap', function () {
blockClick(box, x, y); }, false);
line.appendChild(box);
}
ret.appendChild(line);
}
return ret;
}
function restart() {
root.innerHTML = '';
root.appendChild(createGameTable());
}
restart();
</script>