刚刚入驻CSDN,想找人带我认识一下CSDN,不强求,有意者评论一下,谢谢!

无聊做了一个扫雷,代码如下:

main.html

<head><title>扫雷V1.0版</title>
</head>
<div id="options"><div id="title">更改设置</div><div class="option"><label><input id="board-size-x" type="number" value="16" min="2" max="20" /><div class="title">行</div></label></div><div class="option"><label><input id="board-size-y" type="number" value="16" min="2" max="20" /><div class="title">列</div></label></div><div class="option"><label><input id="mine-count" type="number" value="40" min="1" max="100" /><div class="title">地雷数</div></label></div><div class="option"><label><input id="setup-game" type="button" value="开始游戏" /></label></div><div class="option"><label><input id="smoothed-mouse-tracking" type="checkbox" checked="checked" /><div class="title">鼠标跟踪</div></label></div>
</div>
<script>window.canvasOptions = {autoClear: true,autoCompensate: false,autoPushPop: true,canvas: true,centered: true,width: null,height: null};
</script>
<script type="text/javascript" src="/mains.js"></script>
<link rel="stylesheet" type="text/css" href="/game.css">

mains.js

const {E, LN10, LN2, LOG10E, LOG2E, PI, SQRT1_2, SQRT2,abs, acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, ceil, clz32,cosh, exp, expm1, floor, fround, hypot, imul, log, log10, log1p, log2, max,min, pow, /* random, */ round, sign, sinh, sqrt, tan, tanh, trunc
} =
Math;// consts
const ZERO = 0.0;
const ONE = 1.0;
const TWO = 2.0;
const THREE = 3.0;
const FOUR = 4.0;
const FIVE = 5.0;
const SIX = 6.0;
const SEVEN = 7.0;
const EIGHT = 8.0;
const NINE = 9.0;
const TEN = 10.0;
const ELEVEN = 11.0;
const TWELVE = 12.0;
const SIXTEEN = 16.0;
const THIRTY = 30.0;
const THIRTY_TWO = 32.0;
const SIXTY = 60.0;
const HUNDRED = 100.0;
const THOUSAND = 1000.0;const HALF = ONE / TWO;
const THIRD = ONE / THREE;
const TWO_THIRDS = THIRD * TWO;
const QUARTER = ONE / FOUR;
const THREE_QUARTER = QUARTER * THREE;
const FIFTH = ONE / FIVE;
const SIXTH = ONE / SIX;
const SEVENTH = ONE / SEVEN;
const EIGHTH = ONE / EIGHT;
const TWELFTH = ONE / TWELVE;
const SIXTEENTH = ONE / SIXTEEN;
const ONE_THIRTIETH = ONE / THIRTY;
const THIRTY_SECONDTH = ONE / THIRTY_TWO;
const SIXTIETH = ONE / SIXTY;const TENTH = 1e-1;
const HUNDREDTH = 1e-2;
const THOUSANDTH = 1e-3;
const TEN_THOUSANDTH = 1e-4;
const HUNDRED_THOUSANDTH = 1e-5;
const MILLIONTH = 1e-6;
const TEN_MILLIONTH = 1e-7;
const HUNDRED_MILLIONTH = 1e-8;
const BILLIONTH = 1e-9;
const TEN_BILLIONTH = 1e-10;
const HUNDRED_BILLIONTH = 1e-11;const HALF_PI = PI * HALF;
const THREE_QUARTER_PI = PI * THREE_QUARTER;
const THIRD_PI = PI * THIRD;
const QUARTER_PI = PI * QUARTER;
const FIFTH_PI = PI * FIFTH;
const SIXTH_PI = PI * SIXTH;
const SEVENTH_PI = PI * SEVENTH;
const EIGHTH_PI = PI * EIGHTH;
const TWELFTH_PI = PI * TWELFTH;
const SIXTEENTH_PI = PI * SIXTEENTH;
const THIRTY_SECONDTH_PI = PI * THIRTY_SECONDTH;
const TAU = PI * TWO;
const TWO_TAU = TAU * TWO;
const THREE_QUARTER_TAU = TAU * THREE_QUARTER;
const HALF_TAU = PI;
const THIRD_TAU = TAU * THIRD;
const QUARTER_TAU = HALF_PI;
const FIFTH_TAU = TAU * FIFTH;
const SIXTH_TAU = THIRD_PI;
const EIGHTH_TAU = QUARTER_PI;
const TWELFTH_TAU = SIXTH_PI;
const SIXTEENTH_TAU = EIGHTH_PI;
const THIRTY_SECONDTH_TAU = SIXTEENTH_PI;const SQRT_3 = sqrt(THREE);
const SQRT_4 = sqrt(FOUR);
const SQRT_5 = sqrt(FIVE);const PHI = (1 + sqrt(5)) * 0.5;
const GOLDEN_ANGLE = 1 / (PHI * PHI);const COLOR_BLACK = hsl(0, 0, 0);
const COLOR_WHITE = hsl(0, 0, 100);
const COLOR_RED = hsl(0, 100, 50);
const COLOR_ORANGE = hsl(30, 100, 50);
const COLOR_YELLOW = hsl(60, 100, 50);
const COLOR_GREEN = hsl(120, 100, 50);
const COLOR_CYAN = hsl(180, 100, 50);
const COLOR_BLUE = hsl(240, 100, 50);
const COLOR_PURPLE = hsl(280, 100, 50);
const COLOR_MAGENTA = hsl(300, 100, 50);const TEXTALIGN_LEFT = 'left';
const TEXTALIGN_CENTER = 'center';
const TEXTALIGN_RIGHT = 'right';
const TEXTBASELINE_TOP = 'top';
const TEXTBASELINE_MIDDLE = 'middle';
const TEXTBASELINE_BOTTOM = 'bottom';let _defaulCanvasOptions = {autoClear: false,autoCompensate: true,autoPushPop: false,canvas: true,centered: false,desynchronized: false,drawAndStop: false,width: null,height: null
};let _canvasOptions = {};
let canvas = document.getElementById('canvas');
if (canvas === null) {canvas = document.createElement('canvas');canvas.id = 'canvas';document.body.appendChild(canvas);
}
let ctx = canvas.getContext('2d', {desynchronized: window.canvasOptions && window.canvasOptions.desynchronized !== undefined ?window.canvasOptions.desynchronized : _defaulCanvasOptions.desynchronized// preserveDrawingBuffer: true // WebGL
});
const _originalCtx = ctx;
let _anim, _lastCanvasTime, canvasFrameRate, frameCount, width, height, width_half, height_half, width_quarter, height_quarter;
let _canvasCurrentlyCentered = false;
let _logMouseEvents = false;
let _mouseUpdateTimeThreshold = 12;
let mouseUpdate = -Infinity,mouseIn = false,mouseDown = false,mouseButton = -1,mouseMove = null,mousePos = null,mousePosPrev = null,mouseDownTime = -Infinity,mouseDownPos = null,mouseUpTime = -Infinity,mouseUpPos = null,mouseEnterTime = -Infinity,mouseExitTime = -Infinity;function updateMouse(e, eventName) { // Modified from p5.jsif (_logMouseEvents) {console.log('Mouse event', eventName, e);}if (e && !e.clientX) {e = e.touches && e.touches.length ? e.touches[0] : e.changedTouches ? e.changedTouches[0] : e;}if (!e) {if (_logMouseEvents) {console.log('Missing event data');}return;}const _mouseUpdate = e.timeStamp === undefined ? performance.now() : e.timeStamp;if (mouseUpdate > 0 && _mouseUpdate - mouseUpdate < _mouseUpdateTimeThreshold) {if (_logMouseEvents) {// https://nolanlawson.com/2019/08/11/high-performance-input-handling-on-the-web/// https://bugs.chromium.org/p/chromium/issues/detail?id=992954// http://event-timing.glitch.me/console.log('跳过鼠标事件,开发工具打开了吗?');}return;}mouseUpdate = _mouseUpdate;let rect = canvas.getBoundingClientRect();let sx = canvas.scrollWidth / width;let sy = canvas.scrollHeight / height;let x = (e.clientX - rect.left) / sx;let y = (e.clientY - rect.top) / sy;if (x < 0) x = 0;elseif (x > width) x = width;if (y < 0) y = 0;elseif (y > height) y = height;if (mousePos) {mousePosPrev.set(mousePos);mousePos.set(x, y);}// return { x, y, winX: e.clientX, winY: e.clientY, id: e.identifier };
}canvas.addEventListener('mouseenter', e => {updateMouse(e, 'mouseenter');mouseIn = true;mouseEnterTime = e.timeStamp;// mouseExitTime = -Infinity;
});
canvas.addEventListener('mouseleave', e => {updateMouse(e, 'mouseleave');mouseIn = mouseDown = false;// mouseEnterTime = -Infinity;mouseExitTime = e.timeStamp;
});
canvas.addEventListener('mousemove', e => {updateMouse(e, 'mousemove');mouseIn = true;mouseMove = e.timeStamp;
});
canvas.addEventListener('mousedown', e => {updateMouse(e, 'mousedown');mouseIn = mouseDown = true;mouseButton = e.button;mouseDownTime = e.timeStamp;mouseDownPos = mousePos.copy();
});
canvas.addEventListener('mouseup', e => {updateMouse(e, 'mouseup');mouseDown = false;mouseButton = e.button;mouseUpTime = e.timeStamp;mouseUpPos = mousePos.copy();
});
canvas.addEventListener('touchstart', e => (updateMouse(e, 'touchstart'), mouseIn = true));
canvas.addEventListener('touchend', e => (updateMouse(e, 'touchend'), mouseIn = mouseDown = false));
canvas.addEventListener('touchcancel', e => (updateMouse(e, 'touchcancel'), mouseIn = mouseDown = false));
canvas.addEventListener('touchmove', e => (updateMouse(e, 'touchmove'), mouseIn = true));
window.addEventListener('resize', _resizeCanvas);
window.addEventListener('load', () => {mousePos = new Vector();mousePosPrev = new Vector();mouseUpPos = new Vector();mouseDownPos = new Vector();mouseEnterPos = new Vector();mouseExitPos = new Vector();Object.assign(_canvasOptions,_defaulCanvasOptions,'canvasOptions' in window ? window.canvasOptions : {});if (_canvasOptions.canvas === false) {document.body.removeChild(canvas);}_resizeCanvas();if ('setup' in window) {window.setup();}frameCount = 0;_anim = requestAnimationFrame(_draw);
});function _draw(timestamp) {frameCount++;canvasFrameRate = 1000.0 / (timestamp - _lastCanvasTime);if (!_lastCanvasTime) {_lastCanvasTime = timestamp;}// _lastCanvasTime = timestamp;ctx = _originalCtx;_canvasOptions.autoClear && clear(null);if (_canvasOptions.autoPushPop) {push();_canvasOptions.centered && (_canvasCurrentlyCentered = true) && translateCenter();_canvasOptions.autoCompensate && compensateCanvas();}'draw' in window && window.draw(timestamp);_canvasOptions.autoPushPop && pop();_canvasCurrentlyCentered = false;_lastCanvasTime = timestamp;if (_canvasOptions.drawAndStop) {return;}// beginPath();// rect(width_half - 20, height_half - 20, 120, 30);// fill(hsl(0, 0, 0));// fillStyle(hsl(0, 0, 100));// font('24px monospace');// fillText(canvasFrameRate.toFixed(2), width_half, height_half);_anim = requestAnimationFrame(_draw);
}function _resizeCanvas(specificCanvas) {width = canvas.width = _canvasOptions.width !== null ? _canvasOptions.width : window.innerWidth;height = canvas.height = _canvasOptions.height !== null ? _canvasOptions.height : window.innerHeight;width_quarter = (width_half = width * HALF) * HALF;height_quarter = (height_half = height * HALF) * HALF;ctx.fillStyle = 'hsl(0, 0%, 100%)';ctx.strokeStyle = 'hsl(0, 0%, 100%)';if ('onResize' in window) {window.onResize();}
}function clear(x, y, w, h) {if (x !== undefined && typeof x === 'number') {ctx.clearRect(x, y, w, h);} elseif (_canvasOptions.centered && _canvasCurrentlyCentered /*  && x !== null */ ) {ctx.clearRect(-width_half, -height_half, width, height);} else {ctx.clearRect(0, 0, width, height);}
}function background(a) {push();if (typeof a !== 'number') {fillStyle(a);}if (_canvasOptions.centered && _canvasCurrentlyCentered) {ctx.fillRect(-width_half, -height_half, width, height);} else {ctx.fillRect(0, 0, width, height);}pop();
}function globalAlpha(alpha = ctx.globalAlpha) {return ctx.globalAlpha = alpha;
}function fillStyle(...args) {if (args.length === 1) {let a = args[0];if (typeof a === 'string' || a instanceof CanvasGradient || a instanceof CanvasPattern) {ctx.fillStyle = args[0];}}return ctx.fillStyle;
}function lineWidth(w) {if (typeof w === 'number') {ctx.lineWidth = w;}return ctx.lineWidth;
}// "butt" || "round" || "square";
function lineCap(style = 'butt') {ctx.lineCap = style;
}// "bevel" || "round" || "miter"
function lineJoin(style) {ctx.lineJoin = style;
}function miterLimit(value = 10) {ctx.miterLimit = value;
}function strokeStyle(...args) {if (args.length === 1) {let [a] = args;if (typeof a === 'string' || a instanceof CanvasGradient) {ctx.strokeStyle = a;}} elseif (args.length === 2) {strokeStyle(args[0]);lineWidth(args[1]);}return ctx.strokeStyle;
}function lerpRGB(...args) {let r1 = 255;let b1 = 255;let g1 = 255;let a1 = 1;let r2 = 0;let g2 = 0;let b2 = 0;let a2 = 1;let t = 0.5;if (args.length === 3) {if (Array.isArray(args[0]) && Array.isArray(args[1])) {return lerpRGB(...args[0], ...args[1], args[2]);}[{r: r1 = 255,b: b1 = 255,g: g1 = 255,a: a1 = 1}, {r: r2 = 0,b: b2 = 0,g: g2 = 0,a: a2 = 1},t] =args;} elseif (args.length === 7) {[r1, g1, b1,r2, g2, b2,t] =args;} elseif (args.length === 9) {[r1, g1, b1, a1,r2, g2, b2, a2,t] =args;} elseif (args.length === 2 && Array.isArray(args[0])) {if (args[0].length === 2) {return lerpRGB(...args[0], args[1]);}// TODO: Allow (possibly weighted) lerping between n-count RGBs at specified positions} else {return {r: 127.5,g: 127.5,b: 127.5,a: 1};}let r = lerp(r1, r2, t);let g = lerp(g1, g2, t);let b = lerp(b1, b2, t);let a = lerp(a1, a2, t);return {r, g, b, a};
}function hsl(hue, sat, light, alpha = 1) {if (typeof hue !== 'number') {if (Array.isArray(hue)) {[hue, sat, light, alpha = alpha] = hue;} elseif ('h' in hue) {({h: hue,s: sat,l: light,a: alpha = alpha} = hue);}}hue = hue % 360;if (hue < 0) {hue += 360;}return `hsl(${hue} ${sat}% ${light}% / ${alpha})`;
}function parseHSL(input) {if (typeof input !== 'string') {return input;}let result = input.match(/hsla?\(([\d.]+)\s*,?\s*([\d.]+)%\s*,?\s*([\d.]+)%\s*[/,]?\s*([\d.]*)?\)/);if (result) {let [i, h, s, l, a] = result;return {input, h, s, l, a};}return null;
}function setHueHSL(input, val) {if (val === undefined) return input;let p = parseHSL(input);p.h = val;return hsl(p);
}function rotateHSL(input, amt = 90) {if (amt === 0) return input;let p = parseHSL(input);p.h += amt;return hsl(p);
}function saturateHSL(input, amt = 0.1) {if (amt === 0) return input;let p = parseHSL(input);p.s *= 1 + amt;return hsl(p);
}function lightenHSL(input, amt = 0.1) {if (amt === 0) return input;let p = parseHSL(input);p.l *= 1 + amt;return hsl(p);
}function rgb(r = 255, g = 255, b = 255, a = 1) {if (typeof r !== 'number' && 'r' in r) {({r = 255, g = 255, b = 255, a = 1} = r);} elseif (isVectorish(r)) {({x: r = 255,y: g = 255,z: b = 255,a = 1} = r);}return `rgba(${r}, ${g}, ${b}, ${a})`;
}function fill(...args) {let path;if (args.length) {if (args[0] instanceof Path2D) {path = args.shift();}fillStyle(...args);}// Must branch the fill/stroke call as it// recognizes the undefined argumentpath ? ctx.fill(path) : ctx.fill();
}function stroke(...args) {let path;if (args.length) {if (args[0] instanceof Path2D) {path = args.shift();}strokeStyle(...args);}// Must branch the fill/stroke call as it// recognizes the undefined argumentpath ? ctx.stroke(path) : ctx.stroke();
}function clip(...args) {ctx.clip(...args);
}function createLinearGradient(x1 = -100, y1 = -100, x2 = 100, y2 = 100, stops = []) {// Vector, Vector [stops]if (typeof x1 !== 'number' && typeof y1 !== 'number') {stops = x2;({x: x2,y: y2} = y1);({x: x1,y: y1} = x1);}// Vector, number, number, [stops]else if (typeof x1 !== 'number' && typeof y1 === 'number' && typeof x2 === 'number') {stops = y2;[x2, y2] = [y1, x2];({x: x1,y: y1} = x1);}// Number, number, Vector, [stops]else if (typeof x1 === 'number' && typeof y1 === 'number' && typeof x2 !== 'number') {stops = y2;({x: x2,y: y2} = x2);}const grad = ctx.createLinearGradient(x1, y1, x2, y2);if (stops && Array.isArray(stops) && stops.length) {stops.forEach(stop => {// offset: number, color: stringif (Array.isArray(stop)) {grad.addColorStop(stop[0], stop[1]);}// { offset: number, color: string }else if (stop.offset && stop.color) {grad.addColorStop(stop.offset, stop.color);}});}return grad;
}function createRadialGradient(x1 = 0, y1 = 0, r1 = 0, x2 = 0, y2 = 0, r2 = 200) {return ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
}function createPattern(image, repetition = null) {return ctx.createPattern(image, repetition);
}function drawImage(img, x = 0, y = 0, ...args) {ctx.drawImage(img, x, y, ...args);
}function strokeText(str = 'Hello world', x = 0, y = 0) {ctx.strokeText(str, x, y);
}function fillText(str = 'Hello world', x = 0, y = 0) {ctx.fillText(str, x, y);
}function strokeFillText(str = 'Hello world', x = 0, y = 0) {strokeText(str, x, y);fillText(str, x, y);
}function fillStrokeText(str = 'Hello world', x = 0, y = 0) {fillText(str, x, y);strokeText(str, x, y);
}function measureText(...args) {return ctx.measureText(...args);
}// ctx.textAlign = "left" || "right" || "center" || "start" || "end";
function textAlign(str = 'left') {ctx.textAlign = str;
}// ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";
function textBaseline(str = 'left') {if (str === 'center') str = 'middle';ctx.textBaseline = str;
}function push() {ctx.save();
}function pop() {ctx.restore();
}function resetTransform() {ctx.resetTransform();
}function translate(x = 0, y = 0) {if (typeof x === 'number') {ctx.translate(x, y);} elseif ('x' in x) {ctx.translate(x.x, x.y);}
}function translateCenter(x = 0, y = 0) {ctx.translate(width_half + x, height_half + y);
}function rotate(rot, offsetX, offsetY) {rot = rot % TAU;if (offsetX === undefined) {ctx.rotate(rot);} elseif (typeof offsetX !== 'number') {if ('x' in offsetX) {ctx.translate(offsetX.x, offsetX.y);ctx.rotate(rot);ctx.translate(-offsetX.x, -offsetX.y);}} else {ctx.translate(offsetX, offsetY);ctx.rotate(rot);ctx.translate(-offsetX, -offsetY);}
}function scale(x = 1, y = x) {ctx.scale(x, y);
}function shearX(rad) {ctx.transform(1, 0, tan(rad), 1, 0, 0);
}function shearY(rad) {ctx.transform(1, tan(rad), 0, 1, 0, 0);
}function compensateCanvas() {let offX = 0;let offY = 0;if (width % 2) offX += 0.5;if (height % 2) offY += 0.5;if (offX || offY) {translate(offX, offY);}
}const compOper = {default: 'source-over',sourceOver: 'source-over',sourceIn: 'source-in',sourceOut: 'source-out',sourceAtop: 'source-atop',destinationOver: 'destination-over',destinationIn: 'destination-in',destinationOut: 'destination-out',destinationAtop: 'destination-atop',lighter: 'lighter',copy: 'copy',xor: 'xor',multiply: 'multiply',screen: 'screen',overlay: 'overlay',darken: 'darken',lighten: 'lighten',colorDodge: 'color-dodge',colorBurn: 'color-burn',hardLight: 'hard-light',softLight: 'soft-light',difference: 'difference',exclusion: 'exclusion',hue: 'hue',saturation: 'saturation',color: 'color',luminosity: 'luminosity',source: {over: 'source-over',in : 'source-in',out: 'source-out',atop: 'source-atop'},destination: {over: 'destination-over',in : 'destination-in',out: 'destination-out',atop: 'destination-atop'},light: {hard: 'hard-light',soft: 'soft-light'}
};function compositeOperation(type = compOper.default) { // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperationctx.globalCompositeOperation = type;
}// const filters = [
//      [ 'url', [ 'url' ] ],
//      [ 'blur', [ 'length' ] ],
//      [ 'brightness', [ 'percentage' ] ],
//      [ 'contrast', [ 'percentage' ] ]
//  ];function filter(filterFuncs = 'none') {ctx.filter = filterFuncs;
}function beginPath() {ctx.beginPath();
}function isVectorish(n) {return n instanceof Vector || typeof n === 'object' && 'x' in n && 'y' in n;
}function moveTo(x, y) {if (typeof x === 'number') {ctx.moveTo(x, y);} elseif (isVectorish(x)) {ctx.moveTo(x.x, x.y);}
}function lineTo(x, y) {if (typeof x === 'number') {ctx.lineTo(x, y);} elseif (isVectorish(x)) {ctx.lineTo(x.x, x.y);}
}function quadraticCurveTo(cpX, cpY, x, y) {// ctx.quadraticCurveTo(cpX, cpY, x, y);let a = [];let b = [];if (typeof cpX === 'number') {a = [cpX, cpY];if (typeof x === 'number') {b = [x, y];} elseif ('x' in x) {b = x.xy;}} elseif ('x' in cpX) {a = cpX.xy;if (typeof cpY === 'number') {b = [cpY, x];} elseif ('x' in cpY) {b = cpY.xy;}}ctx.quadraticCurveTo(a[0], a[1], b[0], b[1]);
}function bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y) {let a = [];let b = [];let c = [];if (typeof cp1X === 'number') {a = [cp1X, cp1Y];if (typeof cp2X === 'number') {b = [cp2X, cp2Y];if (typeof x === 'number') {c = [x, y];} elseif ('x' in x) {c = x.xy;}} elseif ('x' in cp2X) {b = cp2X.xy;if (typeof cp2Y === 'number') {c = [cp2Y, x];} elseif ('x' in cp2Y) {c = cp2Y.xy;}}} elseif ('x' in cp1X) {a = cp1X.xy;if (typeof cp1Y === 'number') {b = [cp1Y, cp2X];if (typeof cp2Y === 'number') {c = [cp2Y, x];} elseif ('x' in cp2Y) {c = cp2Y.xy;}} elseif ('x' in cp1Y) {b = cp1Y.xy;if (typeof cp2X === 'number') {c = [cp2X, cp2Y];} elseif ('x' in cp2X) {c = cp2X.xy;}}}ctx.bezierCurveTo(a[0], a[1], b[0], b[1], c[0], c[1]);
}function closePath() {ctx.closePath();
}function point(x = 0, y = 0, r = 0, g = 0, b = 0, a = 255, doPut_ = true) {// let imgData = ctx.createImageData(1, 1);// imgData.data[0] = r;// imgData.data[1] = g;// imgData.data[2] = b;// imgData.data[3] = a;// if(doPut_) {//    ctx.putImageData(imgData, x, y);// }// return imgData;
}function line(x = 0, y = 0, x_ = 0, y_ = 0) {if (typeof x === 'number') {moveTo(x, y);lineTo(x_, y_);} elseif (isVectorish(x)) {moveTo(x);lineTo(y, x_);}
}function vertices(...verts) {let shouldMoveFirst = false;if (verts.length === 0) return;elseif (verts.length === 1 && Array.isArray(verts[0])) {verts = verts[0];} elseif (verts.length === 2 && Array.isArray(verts[0]) && typeof verts[1] === 'boolean') {shouldMoveFirst = verts[1];verts = verts[0];}for (let i = 0; i < verts.length; i++) {let n = verts[i];let x = 0;let y = 0;if (Array.isArray(n)) {[x, y] = n;} elseif (isVectorish(n)) {({x, y} = n);}if (!shouldMoveFirst || i !== 0) {lineTo(x, y);} else {moveTo(x, y);}}
}function rect(x, y, w, h, r) {var _x2, _y2, _w, _h, _r;if (isVectorish(x)) {// Shift args down 1[w, h, r] = [y, w, h];({x, y} = x);}if (isVectorish(w)) {r = h;({x: w,y: h} = w);}// x = 0, y = 0, w = 10, h = w, r = 0x = (_x2 = x) !== null && _x2 !== void 0 ? _x2 : 0;y = (_y2 = y) !== null && _y2 !== void 0 ? _y2 : 0;w = (_w = w) !== null && _w !== void 0 ? _w : 10;h = (_h = h) !== null && _h !== void 0 ? _h : w;r = (_r = r) !== null && _r !== void 0 ? _r : 0;if (r > 0) {moveTo(x + r, y);arcTo(x + w, y, x + w, y + h, r);arcTo(x + w, y + h, x, y + h, r);arcTo(x, y + h, x, y, r);arcTo(x, y, x + w, y, r);closePath();} else {ctx.rect(x, y, w, h);}
}function arc(x, y, radius, startAngle, endAngle, anticlockwise) {var _x3, _y3, _radius, _startAngle, _endAngle, _anticlockwise;if (isVectorish(x)) {// Shift args down 1[radius, startAngle, endAngle, anticlockwise] = [y, radius, startAngle, endAngle];({x, y} = x);}// x = 0, y = 0, radius = 50, startAngle = 0, endAngle = Math.PI * 2, anticlockwise = falsex = (_x3 = x) !== null && _x3 !== void 0 ? _x3 : 0;y = (_y3 = y) !== null && _y3 !== void 0 ? _y3 : 0;radius = (_radius = radius) !== null && _radius !== void 0 ? _radius : 50;startAngle = (_startAngle = startAngle) !== null && _startAngle !== void 0 ? _startAngle : 0;endAngle = (_endAngle = endAngle) !== null && _endAngle !== void 0 ? _endAngle : TAU;anticlockwise = (_anticlockwise = anticlockwise) !== null && _anticlockwise !== void 0 ? _anticlockwise : false;if (radius < 0) radius = 0;ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
}function arcTo(x1 = 0, y1 = 0, x2 = 0, y2 = 0, radius = 50) {ctx.arcTo(x1, y1, x2, y2, radius);
}// function circle(x = 0, y = undefined, rX = 20, rY = undefined) {
function circle(x, y, rX, rY) {var _x4, _y4, _rX;// if(typeof x !== 'number' && 'x' in x) {//     if(y !== undefined) {//       rX = y;//  }//     y = x.y;//     x = x.x;// }// else if(y === undefined) {//     y = 0;// }// if(typeof rX !== 'number' && 'x' in rX) {//     rY = rX.y;//   rX = rX.x;// }if (isVectorish(x)) {[rX, rY] = [y, rX];({x, y} = x);}if (isVectorish(rX)) {({x: rX,y: rY} = rX);}x = (_x4 = x) !== null && _x4 !== void 0 ? _x4 : 0;y = (_y4 = y) !== null && _y4 !== void 0 ? _y4 : 0;rX = (_rX = rX) !== null && _rX !== void 0 ? _rX : 20;ctx.moveTo(x + rX, y);if (rY !== undefined) {ellipse(x, y, rX, rY);} else {if (rX < 0) rX = 0;ctx.arc(x, y, rX, 0, TAU);}
}// function ellipse(x = 0, y = 0, rX = 50, rY = 50, rot = 0, angStart = 0, angEnd = Math.PI * 2, antiCw = false) {
function ellipse(x, y, rX, rY, rot, angStart, angEnd, antiCw) {var _x5, _y5, _rX2, _rY, _rot, _angStart, _angEnd, _antiCw;if (isVectorish(x)) {[rX, rY, rot, angStart, angEnd, antiCw] = [y, rX, rY, rot, angStart, angEnd];({x, y} = x);}if (isVectorish(rX)) {[rot, angStart, angEnd, antiCw] = [rY, rot, angStart, angEnd];({x: rX,y: rY} = rX);}x = (_x5 = x) !== null && _x5 !== void 0 ? _x5 : 0;y = (_y5 = y) !== null && _y5 !== void 0 ? _y5 : 0;rX = (_rX2 = rX) !== null && _rX2 !== void 0 ? _rX2 : 50;rY = (_rY = rY) !== null && _rY !== void 0 ? _rY : rX;rot = (_rot = rot) !== null && _rot !== void 0 ? _rot : 0;angStart = (_angStart = angStart) !== null && _angStart !== void 0 ? _angStart : 0;angEnd = (_angEnd = angEnd) !== null && _angEnd !== void 0 ? _angEnd : TAU;antiCw = (_antiCw = antiCw) !== null && _antiCw !== void 0 ? _antiCw : false;if (rX < 0) rX = 0;if (rY < 0) rY = 0;ctx.ellipse(x, y, rX, rY, rot, angStart, angEnd, antiCw);
}function regularPolygon(sides, radius = 50, rotation = 0) {let circumference = TAU * radius;let count = min(sides, circumference);for (let i = 0; i < count; i++) {let t = i / count * TAU + rotation;let x = cos(t) * radius;let y = sin(t) * radius;if (i === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}}ctx.closePath();
}function genRegularPolygon(sides = 3, radius = 50, rotation = 0) {let iSizes = 1 / sides * TAU;let data = {sides,radius,rotation,points: []};for (let i = 0; i < sides; i++) {let t = i * iSizes + rotation;let x = cos(t) * radius;let y = sin(t) * radius;let point = new Vector(x, y);Object.assign(point, {i, t});data.points.push(point);}return data;
}function getImageData(img, ...args) {if (img instanceof Image) {let canvas = document.createElement('canvas');let ctx = canvas.getContext('2d');Object.assign(canvas, {width: img.width,height: img.height});ctx.drawImage(img, 0, 0);let data;if (args.length) {data = ctx.getImageData(...args);} else {data = ctx.getImageData(0, 0, img.width, img.height);}return Object.assign(data, {canvas, ctx});} else {return ctx.getImageData(img, ...args);}
}function xyToI(x, y, w, h) {if (isVectorish(x)) {[w, h] = [y, w];({x, y} = x);}if (w === undefined) w = 1;// if(h === undefined) h = Infinity;return x + w * y;
}function iToXY(i, w, h) {return new Vector(i % w, floor(i / w));
}function mapObject(obj, cb) {return Object.entries(obj).reduce((p, [key, value]) => {p[key] = cb(value, key);return p;}, {});
}function random(low = 1, high = null) {if (Array.isArray(low)) {return low[floor(Math.random() * low.length)];}if (high === null) {return Math.random() * low;}return Math.random() * (high - low) + low;
}let _randomGaussianPrevious = false;
let _randomGaussianY2 = 0;// https://github.com/processing/p5.js/blob/5a46133fdc3e8c42fda1c1888864cf499940d86d/src/math/random.js#L166
// Offset, deviation
function randomGaussian(mean = 0, sd = 1) {let y1, x1, x2, w;if (_randomGaussianPrevious) {y1 = _randomGaussianY2;_randomGaussianPrevious = false;} else {do {x1 = random(2) - 1;x2 = random(2) - 1;w = x1 * x1 + x2 * x2;} while (w >= 1);w = sqrt(-2 * log(w) / w);y1 = x1 * w;_randomGaussianY2 = x2 * w;_randomGaussianPrevious = true;}return y1 * (sd || 1) + mean;
}function map(n, a, b, c, d) {return (n - a) * (d - c) / (b - a) + c;
}function constrain(n, mn, mx) {return max(mn, min(mx, n));
}function lerp(start, stop, amt = 0.5) {if (typeof start !== 'number') {return Vector.lerp(start, stop, amt);}return amt * (stop - start) + start;
}function _distSq(x1, y1, x2, y2) {let _x = x2 - x1;let _y = y2 - y1;return _x * _x + _y * _y;
}function distSq(x1, y1, x2, y2) {if (x1 === undefined || y1 === undefined || x2 === undefined || y2 === undefined) {return 0;} elseif (typeof x1 === 'number') {if (x1 === x1) {return _distSq(x1, y1, x2, y2);}return 0;} elseif ('x' in x1) {return _distSq(x1.x, x1.y, y1.x, y1.y);}return 0;
}function dist(x1, y1, x2, y2) {let d = distSq(x1, y1, x2, y2);if (d === 0) {return 0;}return sqrt(d);
}function cos(input, mult = 1, add = 0) {return Math.cos(input % TAU) * mult;
}function sin(input, mult = 1, add = 0) {return Math.sin(input % TAU) * mult + add;
}let _warning_createVector = false;function createVector(x, y, z) {if (!_warning_createVector) {_warning_createVector = true;console.warn('[Canvas Warning] Hey, stop using createVector');}return new Vector(x, y, z);
}class Vector {constructor(x = 0, y = 0, z = 0) {this.x = x;this.y = y;this.z = z;}toString() {let {x, y, z} = this;return `{ x: ${x}, y: ${y}, z: ${z} }`;}static center() {return new Vector(width_half, height_half);}static from(v, ...args) {if (v === undefined) {return new Vector();} elseif (Array.isArray(v)) {return new Vector(...v);} elseif (typeof v === 'object') {return new Vector(v.x, v.y, v.z);} elseif (typeof v === 'number') {return new Vector(v, ...args);}}static fromAngle(angle, mult = 1) {return new Vector(cos(angle), sin(angle)).mult(mult);}static fa(...args) {return Vector.fromAngle(...args);}static random2D(angle = true, mult = 1) {let v;if (angle === true) {v = Vector.fromAngle(random(TAU));} else {v = new Vector(random(-1, 1), random(-1, 1));}if (typeof angle === 'number') {v.mult(angle);} elseif (mult !== 1) {v.mult(mult);}return v;}static lerp(start, stop, amt = 0.5, apply = false) {let amtX = amt;let amtY = amt;let amtZ = amt;if (isVectorish(amt))({x: amtX,y: amtY,z: amtZ} = amt);const x = start.x === stop.x ? start.x : lerp(start.x, stop.x, amtX);const y = start.y === stop.y ? start.y : lerp(start.y, stop.y, amtY);const z = start.z === undefined ? stop.z === undefined ? 0 : stop.z : start.z === stop.z ? start.z : lerp(start.z, stop.z, amtZ);if (apply) {return start.set(x, y, z);}return new Vector(x, y, z);}static average(vectors, ...rest) {if (rest.length) {vectors = [vectors, ...rest];}return vectors.reduce((p, n) => p.add(n), new Vector()).div(vectors.length);}// Swizzlersget xy() {return [this.x, this.y];}get yx() {return [this.y, this.x];}get xz() {return [this.x, this.z];}get zx() {return [this.z, this.x];}get yz() {return [this.y, this.z];}get zy() {return [this.z, this.y];}get xyz() {return [this.x, this.y, this.z];}get xzy() {return [this.x, this.z, this.y];}get yxz() {return [this.y, this.x, this.z];}get yzx() {return [this.y, this.z, this.x];}get zyx() {return [this.z, this.y, this.x];}get zxy() {return [this.z, this.x, this.y];}get xyObject() {return {x: this.x,y: this.y};}get xzObject() {return {x: this.x,z: this.z};}get yzObject() {return {y: this.y,z: this.z};}get xyzObject() {return {x: this.x,y: this.y,z: this.z};}copy() {return new Vector(this.x, this.y, this.z);}get _() {return this.copy();}swap(a, b) {const temp = this[a];this[a] = this[b];this[b] = temp;return this;}swapXY() {return this.swap('x', 'y');}swapYZ() {return this.swap('y', 'z');}swapZX() {return this.swap('z', 'x');}swapYX() {return this.swapXY();}swapZY() {return this.swapYZ();}swapXZ() {return this.swapZX();}// Copy [a] to [b]copyWithin(a, b) {this[b] = a;return this;}copyXY() {return this.copyWithin('x', 'y');}copyYX() {return this.copyWithin('y', 'x');}copyYZ() {return this.copyWithin('y', 'z');}copyZY() {return this.copyWithin('z', 'y');}copyZX() {return this.copyWithin('z', 'x');}copyXZ() {return this.copyWithin('x', 'z');}equals(vec) {return this.x === vec.x && this.y === vec.y;}equals3D(vec = {}) {return this.x === vec.x && this.y === vec.y && this.z === vec.z;}draw() {point(this.x, this.y);}set(x = this.x, y = this.y, z = this.z) {if (x instanceof Vector) {this.x = x.x;this.y = x.y;this.z = x.z;return this;}this.x = x;this.y = y;this.z = z;return this;}setX(x = this.x) {if (x instanceof Vector) {this.x = x.x;return this;}this.x = x;return this;}setY(y = this.y) {if (y instanceof Vector) {this.y = y.y;return this;}this.y = y;return this;}setZ(z = this.z) {if (z instanceof Vector) {this.z = z.z;return this;}this.z = z;return this;}setXY(x = this.x, y = this.y) {if (x instanceof Vector) {this.x = x.x;this.y = x.y;return this;}this.x = x;this.y = y;return this;}setYX(...args) {return this.setXY(...args);}setYZ(y = this.y, z = this.z) {if (y instanceof Vector) {this.y = y.y;this.z = y.z;return this;}this.y = y;this.z = z;return this;}setZY(...args) {return this.setYZ(...args);}setXZ(x = this.x, z = this.y) {if (x instanceof Vector) {this.x = x.x;this.z = x.z;return this;}this.x = x;this.z = z;return this;}setZX(...args) {return this.setXZ(...args);}add(x = 0, y = undefined, z = undefined) {if (y === undefined) {y = x;z = x;} elseif (z === undefined) {z = 0;}if (x instanceof Vector) {this.x += x.x;this.y += x.y;this.z += x.z;return this;}this.x += x;this.y += y;this.z += z;return this;}addX(n = 0) {if (n instanceof Vector) {this.x += n.x;return this;}this.x += n;return this;}addY(n = 0) {if (n instanceof Vector) {this.y += n.y;return this;}this.y += n;return this;}addZ(n = 0) {if (n instanceof Vector) {this.z += n.z;return this;}this.z += n;return this;}addXY(x, y = x) {return this.addX(x).addY(y);}addYX(y, x = y) {return this.addXY(x, y);}addYZ(y, z = y) {return this.addY(y).addZ(z);}addZY(z, y = z) {return this.addYZ(y, z);}addZX(z, x = z) {return this.addZ(z).addX(x);}addXZ(x, z = x) {return this.addZX(x, z);}addXYZ(...args) {return this.add(...args);}sub(x = 0, y = undefined, z = undefined) {if (y === undefined) {y = x;z = x;} elseif (z === undefined) {z = 0;}if (x instanceof Vector) {this.x -= x.x;this.y -= x.y;this.z -= x.z;return this;}this.x -= x;this.y -= y;this.z -= z;return this;}subX(n = 0) {if (n instanceof Vector) {this.x -= n.x;return this;}this.x -= n;return this;}subY(n = 0) {if (n instanceof Vector) {this.y -= n.y;return this;}this.y -= n;return this;}subZ(n = 0) {if (n instanceof Vector) {this.z -= n.z;return this;}this.z -= n;return this;}subXY(x, y = x) {return this.subX(x).subY(y);}subYX(y, x = y) {return this.subXY(x, y);}subYZ(y, z = y) {return this.subY(y).subZ(z);}subZY(z, y = z) {return this.subYZ(y, z);}subZX(z, x = z) {return this.subZ(z).subX(x);}subXZ(x, z = x) {return this.subZX(x, z);}subXYZ(...args) {return this.sub(...args);}mult(x = 1, y = x, z = x) {if (x instanceof Vector) {this.x *= x.x;this.y *= x.y;this.z *= x.z;return this;}this.x *= x;this.y *= y;this.z *= z;return this;}multX(n = 1) {if (n instanceof Vector) {this.x *= n.x;return this;}this.x *= n;return this;}multY(n = 1) {if (n instanceof Vector) {this.y *= n.y;return this;}this.y *= n;return this;}multZ(n = 1) {if (n instanceof Vector) {this.z *= n.z;return this;}this.z *= n;return this;}multXY(x, y = x) {return this.multX(x).multY(y);}multYX(y, x = y) {return this.multXY(x, y);}multYZ(y, z = y) {return this.multY(y).multZ(z);}multZY(z, y = z) {return this.multYZ(y, z);}multZX(z, x = z) {return this.multZ(z).multX(x);}multXZ(x, z = x) {return this.multZX(x, z);}multXYZ(...args) {return this.mult(...args);}div(x = 1, y = x, z = x) {if (x instanceof Vector) {this.x /= x.x;this.y /= x.y;this.z /= x.z;return this;}this.x /= x;this.y /= y;this.z /= z;return this;}divX(n = 1) {if (n instanceof Vector) {this.x /= n.x;return this;}this.x /= n;return this;}divY(n = 1) {if (n instanceof Vector) {this.y /= n.y;return this;}this.y /= n;return this;}divZ(n = 1) {if (n instanceof Vector) {this.z /= n.z;return this;}this.z /= n;return this;}divXY(x, y = x) {return this.divX(x).divY(y);}divYX(y, x = y) {return this.divXY(x, y);}divYZ(y, z = y) {return this.divY(y).divZ(z);}divZY(z, y = z) {return this.divYZ(y, z);}divZX(z, x = z) {return this.divZ(z).divX(x);}divXZ(x, z = x) {return this.divZX(x, z);}divXYZ(...args) {return this.div(...args);}mod(x, y, z) {if (x === undefined) return this;elseif (x instanceof Vector) {this.x %= x.x;this.y %= x.y;this.z %= x.z;return this;}this.x %= x;this.y %= y === undefined ? x : y;this.z %= z === undefined ? x : y;return this;}// TODO: modX, modY, modZmin(mX = this.x, mY = this.y, mZ = this.z) {if (mX instanceof Vector) {this.x = min(this.x, mX.x);this.y = min(this.y, mX.y);this.z = min(this.z, mX.z);return this;}this.x = min(this.x, mX);this.y = min(this.y, mY);this.z = min(this.z, mZ);return this;}max(mX = this.x, mY = this.y, mZ = this.z) {if (mX instanceof Vector) {this.x = max(this.x, mX.x);this.y = max(this.y, mX.y);this.z = max(this.z, mX.z);return this;}this.x = max(this.x, mX);this.y = max(this.y, mY);this.z = max(this.z, mZ);return this;}minX(n) {this.x = min(this.x, n instanceof Vector ? n.x : n);return this;}minY(n) {this.y = min(this.y, n instanceof Vector ? n.y : n);return this;}minZ(n) {this.z = min(this.z, n instanceof Vector ? n.z : n);return this;}maxX(n) {this.x = max(this.x, n instanceof Vector ? n.x : n);return this;}maxY(n) {this.y = max(this.y, n instanceof Vector ? n.y : n);return this;}maxZ(n) {this.z = max(this.z, n instanceof Vector ? n.z : n);return this;}heading() {return atan2(this.y, this.x);}rotate(a = 0) {// if(a === 0) {//    return this;// }// let newHeading = this.heading() + a;// let mag = this.mag();// return this.set(cos(newHeading), sin(newHeading)).mult(mag);if (!a) {return this;}const c = cos(a);const s = sin(a);const {x, y} = this;this.x = x * c - y * s;this.y = x * s + y * c;return this;}rotateXY(a) {let v = new Vector(this.x, this.y).rotate(a);this.x = v.x;this.y = v.y;return this;}rotateYZ(a) {let v = new Vector(this.y, this.z).rotate(a);this.y = v.x;this.z = v.y;return this;}rotateZX(a) {let v = new Vector(this.z, this.x).rotate(a);this.z = v.x;this.x = v.y;return this;}rotateYX(a) {return this.rotateXY(a);}rotateZY(a) {return this.rotateYZ(a);}rotateXZ(a) {return this.rotateZX(a);}magSq() {return this.x * this.x + this.y * this.y;}magSq3D() {return this.x * this.x + this.y * this.y + this.z * this.z;}mag() {return Math.sqrt(this.magSq());// return hypot(this.x, this.y);}mag3D() {return Math.sqrt(this.magSq3D());// return hypot(this.x, this.y);}normalize(mag = this.mag()) {return mag === 0 ? this : this.div(mag);}normalize3D(mag = this.mag3D()) {return mag === 0 ? this : this.div(mag);}setMag(mag) {return this.normalize().mult(mag);}setMag3D(mag) {return this.normalize3D().mult(mag);}limit(max) {const magSq = this.magSq();if (magSq > max * max) {this.div(sqrt(magSq));this.mult(max);}return this;}limit3D(max) {const magSq = this.magSq3D();if (magSq > max * max) {this.div(sqrt(magSq));this.mult(max);}return this;}dot(x = 0, y = 0) {if (x instanceof Vector) {return this.dot(x.x, x.y);}return this.x * x + this.y * y;}dot3D(x = 0, y = 0, z = 0) {if (x instanceof Vector) {return this.dot(x.x, x.y, x.z);}return this.x * x + this.y * y + this.z * z;}cross(v) {return new Vector(this.y * v.z - this.z * v.y,this.z * v.x - this.x * v.z,this.x * v.y - this.y * v.x);}dist(x, y) {if (x instanceof Vector) {return x.copy().sub(this).mag();} elseif (typeof x === 'object' && 'x' in x) {({x, y} = x);}return dist(this.x, this.y, x, y);}dist3D(v) {return v.copy().sub(this).mag3D();}lerp(stop, amt) {return Vector.lerp(this, stop, amt, true);}_lerpPart(stop, amt, part) {stop = isVectorish(stop) ? stop[part] : stop;amt = isVectorish(amt) ? amt[part] : amt;this[part] = lerp(this[part], stop, amt);return this;}lerpX(stop, amt) {return this._lerpPart(stop, amt, 'x');}lerpY(stop, amt) {return this._lerpPart(stop, amt, 'y');}lerpZ(stop, amt) {return this._lerpPart(stop, amt, 'z');}lerpXY(stop, amt) {return this.lerpX(stop, amt).lerpY(stop, amt);}lerpYX(stop, amt) {return this.lerpXY(stop, amt);}lerpYZ(stop, amt) {return this.lerpY(stop, amt).lerpZ(stop, amt);}lerpZY(stop, amt) {return this.lerpYZ(stop, amt);}lerpZX(stop, amt) {return this.lerpZ(stop, amt).lerpX(stop, amt);}lerpXZ(stop, amt) {return this.lerpZX(stop, amt);}round() {this.x = round(this.x);this.y = round(this.y);this.z = round(this.z);return this;}floor() {this.x = floor(this.x);this.y = floor(this.y);this.z = floor(this.z);return this;}fastFloor() {this.x = ~~this.x;this.y = ~~this.y;this.z = ~~this.z;return this;}ceil() {this.x = ceil(this.x);this.y = ceil(this.y);this.z = ceil(this.z);return this;}
}// Robert Penner - http://gizma.com/easing/
// t: Current time
// b: Start value
// c: Change in value
// d: Durationfunction linearTween /* simple linear tweening    */ (t = 0.5, b = 0, c = 1, d = 1) {return c * t / d + b;
}function easeInQuad /* quadratic   easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return c * t * t + b;
}function easeOutQuad /* quadratic   easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return -c * t * (t - 2) + b;
}function easeInOutQuad /* quadratic   easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return c * 0.5 * t * t + b;t--;return -c * 0.5 * (t * (t - 2) - 1) + b;
}function easeInCubic /* cubic       easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return c * t * t * t + b;
}function easeOutCubic /* cubic       easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;t--;return c * (t * t * t + 1) + b;
}function easeInOutCubic /* cubic       easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return c * 0.5 * t * t * t + b;t -= 2;return c * 0.5 * (t * t * t + 2) + b;
}function easeInQuart /* quartic     easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return c * t * t * t * t + b;
}function easeOutQuart /* quartic     easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;t--;return -c * (t * t * t * t - 1) + b;
}function easeInOutQuart /* quartic     easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return c * 0.5 * t * t * t * t + b;t -= 2;return -c * 0.5 * (t * t * t * t - 2) + b;
}function easeInQuint /* quintic     easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return c * t * t * t * t * t + b;
}function easeOutQuint /* quintic     easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;t--;return c * (t * t * t * t * t + 1) + b;
}function easeInOutQuint /* quintic     easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return c * 0.5 * t * t * t * t * t + b;t -= 2;return c * 0.5 * (t * t * t * t * t + 2) + b;
}function easeInSine /* sinusoidal  easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {return -c * cos(t / d * HALF_PI) + c + b;
}function easeOutSine /* sinusoidal  easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {return c * sin(t / d * HALF_PI) + b;
}function easeInOutSine /* sinusoidal  easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {return -c * 0.5 * (cos(PI * t / d) - 1) + b;
}function easeInExpo /* exponential easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {return c * pow(2, 10 * (t / d - 1)) + b;
}function easeOutExpo /* exponential easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {return c * (-pow(2, -10 * t / d) + 1) + b;
}function easeInOutExpo /* exponential easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return c * 0.5 * pow(2, 10 * (t - 1)) + b;t--;return c * 0.5 * (-pow(2, -10 * t) + 2) + b;
}function easeInCirc /* circular    easing in     */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;return -c * (sqrt(1 - t * t) - 1) + b;
}function easeOutCirc /* circular    easing out    */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d;t--;return c * sqrt(1 - t * t) + b;
}function easeInOutCirc /* circular    easing in/out */ (t = 0.5, b = 0, c = 1, d = 1) {t /= d * 0.5;if (t < 1) return -c * 0.5 * (sqrt(1 - t * t) - 1) + b;t -= 2;return c * 0.5 * (sqrt(1 - t * t) + 1) + b;
}const ease = {linearTween,easeInQuad, easeOutQuad, easeInOutQuad,easeInCubic, easeOutCubic, easeInOutCubic,easeInQuart, easeOutQuart, easeInOutQuart,easeInQuint, easeOutQuint, easeInOutQuint,easeInSine, easeOutSine, easeInOutSine,easeInExpo, easeOutExpo, easeInOutExpo,easeInCirc, easeOutCirc, easeInOutCirc, in : {linear: linearTween,quad: easeInQuad,cubic: easeInCubic,quart: easeInQuart,quint: easeInQuint,sine: easeInSine,expo: easeInExpo,circ: easeInCirc},out: {linear: linearTween,quad: easeOutQuad,cubic: easeOutCubic,quart: easeOutQuart,quint: easeOutQuint,sine: easeOutSine,expo: easeOutExpo,circ: easeOutCirc},inOut: {linear: linearTween,quad: easeInOutQuad,cubic: easeInOutCubic,quart: easeInOutQuart,quint: easeInOutQuint,sine: easeInOutSine,expo: easeInOutExpo,circ: easeInOutCirc},linear: Object.assign(linearTween, { in : linearTween, out: linearTween, inOut: linearTween}),quad: { in : easeInQuad, out: easeOutQuad, inOut: easeInOutQuad},cubic: { in : easeInCubic, out: easeOutCubic, inOut: easeInOutCubic},quart: { in : easeInQuart, out: easeOutQuart, inOut: easeInOutQuart},quint: { in : easeInQuint, out: easeOutQuint, inOut: easeInOutQuint},sine: { in : easeInSine, out: easeOutSine, inOut: easeInOutSine},expo: { in : easeInExpo, out: easeOutExpo, inOut: easeInOutExpo},circ: { in : easeInCirc, out: easeOutCirc, inOut: easeInOutCirc}
};function getTimeArray(timestamp = null) {if (timestamp === null) {timestamp = new Date();} elseif (typeof timestamp === 'string' || typeof timestamp === 'number') {let parsedTimestamp = Date.parse(timestamp);if (!isNaN(parsedTimestamp)) {timestamp = new Date(parsedTimestamp);} else {throw new RangeError('Invalid Date');}} elseif (!(timestamp instanceof Date)) {throw new TypeError('Unsupported timestamp');}let arr = [timestamp.getHours(),timestamp.getMinutes(),timestamp.getSeconds(),timestamp.getMilliseconds()];return arr;
}function getTimeArrayPadded(...opts) {return getTimeArray(...opts).map(n => `0${n}`.slice(-2));
}function getTimeArraySmooth(...opts) {let arr = getTimeArray(...opts);let milliseconds = arr[3] / 1000;let seconds = (arr[2] + milliseconds) / 60;let minutes = (arr[1] + seconds) / 60;let hours = ((arr[0] % 12 || 12) + minutes) / 12;return [hours, minutes, seconds, milliseconds];
}function loadWebFont(fontName) {if ('WebFont' in window === false) {return Promise.reject('WebFont not available. Load using this script: https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.28/webfontloader.js');}if (fontName === '') {return Promise.resolve();}return new Promise((resolve, reject) => {let options = {fontactive: resolve};let providers = {};if (typeof fontName === 'string') {providers = {google: {families: [fontName]}};} elseif (Array.isArray(fontName)) {providers = {google: {families: fontName}};} else {providers = fontName;}Object.assign(options, providers);WebFont.load(options);});
}function isFontDefault() {return ctx.font === '10px sans-serif';
}function font(fontStr, fallbackIfDefault) {if (fontStr !== undefined) {ctx.font = fontStr;if (fallbackIfDefault !== undefined && isFontDefault()) {ctx.font = fallbackIfDefault;}}return ctx.font;
}// https://stackoverflow.com/a/40200710/1703756
function isPrime(num) {for (let i = 2, s = Math.sqrt(num); i <= s; i++) {if (num % i === 0) {return false;}}return num > 1;} // Where the game will be
let game;let options = {smoothedMouseTracking: document.getElementById('smoothed-mouse-tracking'),boardSizeX: document.getElementById('board-size-x'),boardSizeY: document.getElementById('board-size-y'),mineCount: document.getElementById('mine-count'),setupGame: document.getElementById('setup-game')
};function zoom(e) {let zoomDir = -sign(e.deltaY);if (e.demo) {zoomDir *= 0.1;}game.zoomLevel = constrain(game.zoomLevel + zoomDir, 1, game.maxZoomLevels);
}// Drawing init function
function setup() {options.setupGame.addEventListener('click', () => {if (!game) {return;}let bX = constrain(parseInt(options.boardSizeX.value), 2, 128);let bY = constrain(parseInt(options.boardSizeY.value), 2, 128);let mC = constrain(parseInt(options.mineCount.value), 1, game.boardSize.x * game.boardSize.y - 2);console.log(mC);if (bX === bX) {game.boardSize.x = bX;}if (bY === bY) {game.boardSize.y = bY;}if (mC === mC) {game.mineCount = mC;}game.setup();});// Create a game instancegame = new Game();// Setup the mouse event listenerswindow.addEventListener('click', e => {if (e.button !== 0) return;elseif (e.target.id === 'canvas') {game.click(e);} elseif (e.target.id === 'options' || e.target.id === 'title') {document.getElementById('options').classList.toggle('open');}});window.addEventListener('contextmenu', e => {if (e.target.id === 'canvas') {// Prevent the context menu from coming up for flagging cellse.preventDefault();// Tell the game we clickedgame.click(e);}});// Setup the keyboard event listenerwindow.addEventListener('keypress', e => {// Reset the game on space bar pressedif (e.key === ' ') {game.reset();}});// Setup the mouse wheel eventwindow.addEventListener('wheel', zoom);
}// The draw function, called with requestAnimationFrame
// Number e = performance.now()
function draw(e) {// Call the game's update and draw functiongame.update().draw(e);
}// The Game class
class Game {// Game initconstructor() {// The current state of the game.// 0 = waiting for first input, this decides when the game calls pickMines// 1 = now playing the game// 2 = mine exploded// 3 = no non-mine cells leftthis.state = 0;// Cells in rowsthis.board = [];// All cellsthis.cells = [];// The x/y size of the boardif ('gameBoardSize' in window) {this.boardSize = createVector(window.gameBoardSize.x, window.gameBoardSize.y);} else {this.boardSize = createVector(16, 16);}// The px location of the top left-hand corner of the boardthis.drawOffset = createVector(0, 0);// The amount of mines to pickif ('gameMineCount' in window) {this.mineCount = window.gameMineCount;} else {this.mineCount = this.boardSize.x * this.boardSize.y * 0.15625;}// The px size of each cellthis.cellSize = 10;// Has it picked the mines yet?this.pickedMines = false;// The amount of covered cells minus the mine count (set in reset)this.tilesLeft = 0;// The amount of cells with flagsthis.flaggedCount = 0;// The timestamp when the game entered state 1 (first click)this.startedAt = null;// The timestamp when the game ended (win or lose)this.finishedAt = null;// Global zoom level, scroll up to zoom inthis.zoomLevel = 1;this._zoomLevelLerp = 1;this.maxZoomLevels = 8;this.currentScale = 1;this.viewOffset = createVector();this._viewOffsetLerp = createVector();// Call the setup function to initialize the board/cellsthis.setup();}// Used to initialize the game, also whenever setings are changed (in the future)setup() {// Clear these valuesthis.board = [];this.cells = [];// Calculate the mine countthis.boardSize.max(2, 2);// this.mineCount = max(1, floor((this.boardSize.x * this.boardSize.y) * 0.15625));this.mineCount = constrain(this.mineCount, 1, this.boardSize.x * this.boardSize.y - 2);// Generate cellsfor (let y = 0; y < this.boardSize.y; y++) {// Keep them in a 2D arraylet row = [];this.board.push(row);for (let x = 0; x < this.boardSize.x; x++) {let cell = new Cell({x, y}, this);// Also keep them in a flat listthis.cells.push(cell);row.push(cell);}}// Jump to resetthis.reset();}// Set the game values for a new gamereset() {this.state = 0;this.pickedMines = false;this.tilesLeft = this.boardSize.x * this.boardSize.y - this.mineCount;this.flaggedCount = 0;this.finishedAt = null;this.zoomLevel = 1;this.startedAt = null;// Call reset within each cellthis.cells.forEach(c => c.reset());}// Pick the board's minespickMines() {// Don't re-pick the mines until the game is resetif (this.pickedMines) {return;}this.pickedMines = true;// Get a new array of only covered cells so that they can be removed as it pickslet cells = this.cells.filter(c => c.covered);// For each mine to setfor (let i = 0; i < this.mineCount; i++) {// Get a random index from the cells arraylet index = floor(random(cells.length));// Remove that cell from cellslet cell = cells.splice(index, 1)[0];// Set that cell as a minecell.mine = true;}// For all non-mines, set the mineCount propertythis.cells.filter(c => !c.mine).forEach(c => {// Get neighbors, filter for minesc.mineCount = this.getCellNeighbors(c).filter(n => n.mine).length;});}// Update px values for drawing and mouse eventsupdate(e = performance.now()) {let {boardSize: {x, y}} = this;// Fit to 90% of the width/heightlet max = 0.9;// Fit to 80% of the width/heightlet min = 0.8;// If you're still playing, stay zoomed inlet time = game.state < 2 ? 0 : constrain((e - game.finishedAt) * 0.001, 0, 1);// When you win or lose, zoom out to give the top text roomlet scl = lerp(max, min, time);let w = width * scl;let h = height * scl;// Calculate the square cellSize that fits within the w/h// This will also determine the size when there's more or less x/y in whichever orientation// The naive size of x/ylet w_ = w / x;let h_ = h / y;// If w is greater than hthis.cellSize = w > h ?// true: If there's more x than y in the boardSize// true: Use h_ if w_ times the y count is greater than the total h, else use w_// false: Use h_x > y ? w_ * y > h ? h_ : w_ : h_ :// false: If there's more y than x in the boardSize// true: Use w_ if h_ times the x count is greater than the total w, else use h_// false: Use w_y > x ? h_ * x > w ? w_ : h_ : w_;// Multiply the boardSize by half of the negative cellSizethis.cellSize = Math.min(this.cellSize, 80);this.drawOffset.set(x, y).mult(this.cellSize * -0.5)// Offset up when still playing.sub(0, lerp(this.cellSize * 0.5, 0, time));// Allow chainingreturn this;}draw(e) {let zoomLevel = this._zoomLevelLerp = lerp(this._zoomLevelLerp, this.zoomLevel, 0.1);scale(this.currentScale = sqrt(zoomLevel));this._viewOffsetLerp.set(mousePos.copy().sub(Vector.center())).mult(-map(this.currentScale, 1, sqrt(this.maxZoomLevels), 0, 1));translate(this.viewOffset.lerp(this._viewOffsetLerp, options.smoothedMouseTracking.checked ? 0.3 / (this.currentScale * 0.5) : 1));let {cellSize, boardSize} = this;// Save the current context statepush();// Translate by the drawOffset in pxtranslate(this.drawOffset);// Set the text x alignment to centertextAlign(TEXTALIGN_CENTER);// Set the text y alignment to middletextBaseline(TEXTBASELINE_MIDDLE);// Set the font size and familyfont(`${cellSize * 0.5}px sans-serif`);// Set the miter limit to cut down on spikes from textmiterLimit(2);// Determine if currently in playlet playing = this.state < 2;// Get the mouse over cell positionlet cellPos = this.mouseToCellPos();// The cell that is moused overlet mouseCell = playing ? this.getCell(cellPos) : null;canvas.style.cursor = !mouseCell || !mouseCell.covered ? 'default' : mouseCell.flagged ? 'cell' : 'pointer';// Loop over each cellthis.cells.forEach(c => {// Get the actual x/y of the celllet {x, y} = c.pos.copy().mult(cellSize);// If this cell is being moused overlet mousedOver = mouseCell && mouseCell === c;// Draw the cell's rectanglebeginPath();rect(x, y, cellSize, cellSize);// If the cell is not coveredif (!c.covered) {// The current time through the uncovered animationlet t = e - c.uncoveredAt;// The alpha value of the cell, 0 by defaultlet a = 0;// If the cell is not a mineif (!c.mine) {// If the uncovered animation hasn't started, alpha is 1if (t < 0) {a = 1;}// If the current time is within the animation time, ease from 1 to 0else if (t < 300) {a = ease.quad.inOut(t, 1, -1, 300);}// If the cell has mine neighborsif (c.mineCount) {// Fill the mine count text// Orange if 5 or moreif (c.mineCount >= 5) {fillStyle(hsl(25, 80, 50));} else {fillStyle(hsl(0, 0, 100));}fillText(c.mineCount, x + cellSize * 0.5, y + cellSize * 0.5);}// Fill the cell over the text if there's any alphaif (a > 0) {fill(hsl(0, 0, 24, a));}}// Definitely is a mineelse {// If the flag animation hasn't started, time is 0if (t < 0) {t = 0;}// If the current time is within the animation time, ease from 0 to 1else if (t < 300) {t = ease.quad.inOut(t, 0, 1, 300);}// If it's flagged, lerp the color from flagged green to bomb redif (c.flagged) {fill(rgb(lerpRGB(0, 0xFF, 0, 0xFF, 0, 0, t)));}// Not flagged, lerp from normal grey to bomb redelse {fill(rgb(lerpRGB(0x3D, 0x3D, 0x3D, 0xFF, 0, 0, t)));}}}// If the cell is covered and flagged// Then fill with a lightness based on if the mouse is over this cellelse if (c.flagged) {fill(hsl(120, 100, mousedOver ? 65 : 50));} else {fill(hsl(0, 0, mousedOver ? 36 : 24));}// Stroke the cellstroke();});// Get the center of the board on the x-axislet centerX = cellSize * boardSize.x * 0.5;// If the game is still playingif (playing) {// The amount of mines left: `24/40 mines left` -- can be negativelet message = `${(this.mineCount - this.flaggedCount).toLocaleString()}/${this.mineCount.toLocaleString()} mines left`;// Display the amount of mines at the bottom of the screenlet y = (boardSize.y + 0.75) * cellSize;// White text with a black stroke of 20% of the cellSizefillStyle(hsl(0, 0, 100));strokeStyle(hsl(0, 0, 0));lineWidth(cellSize * 0.2);// Only half of the stroke is seen because the text is filled over the strokestrokeText(message, centerX, y);fillText(message, centerX, y);}// Not playing anymoreelse {// Determine game win/lose textlet message = this.state === 2 ? '你输了...' : '你赢了!';// Text above the boardlet y = -cellSize;// The current time through the text animationlet t = e - this.finishedAt;// The alpha value of the text, 1 by defaultlet a = 1;// If the animation hasn't started, alpha is 0if (t < 0) {a = 0;}// If the current time is within the animation time, ease from 0 to 1else if (t < 800) {a = ease.quad.inOut(t, 0, 1, 800);}// Set the main text font weight, font size, and font familyfont(`800 ${cellSize * 1.6 * a}px sans-serif`);// White text with a black stroke of 30% of the cellSizefillStyle(hsl(0, 0, 100, a));strokeStyle(hsl(0, 0, 0, a));lineWidth(cellSize * 0.3);// Stroke and fill the main textstrokeText(message, centerX, y);fillText(message, centerX, y);// The lower text messagemessage = '按空格键重新开始';// Set the lower text font weight, font size, and font familyfont(`800 ${cellSize * 0.8 * a}px sans-serif`);lineWidth(cellSize * 0.3 * 0.8);// Flip the y offset by 80 percent and then add the total board heighty = y * -0.8 + cellSize * boardSize.y;// Stroke and fill the lower textstrokeText(message, centerX, y);fillText(message, centerX, y);}// Undo the context changespop();}// Get a cell (or null) from the board at x/ygetCell(x, y) {// x can be an object with x/y propertiesif (x instanceof Vector || typeof x !== 'number' && 'x' in x) {y = x.y;x = x.x;}// x can be an arrayelse if (Array.isArray(x)) {y = x[1];x = x[0];}// Get the cell or null if it's not therereturn this.board[y] ? this.board[y][x] : null;}// Get the 3x3 neighbors around a cellgetCellNeighbors(cell) {let {pos} = cell;return [[pos.x - 1, pos.y - 1],[pos.x, pos.y - 1],[pos.x + 1, pos.y - 1],[pos.x - 1, pos.y],[pos.x + 1, pos.y],[pos.x - 1, pos.y + 1],[pos.x, pos.y + 1],[pos.x + 1, pos.y + 1]]// Get the cells at those positions.map(this.getCell, this)// Identity filter (remove nulls).filter(n => n);}// Get the mouse position and transform it into a cell positionmouseToCellPos() {// Make a copy to not change the original Vectorreturn mousePos.copy()// Subtract the center of the screen since it's being drawn from the center.sub(Vector.center())// Account for zoom.mult(1 / this.currentScale).sub(this.viewOffset)// Subtract the draw offset.sub(this.drawOffset)// Divide by the cell size.div(this.cellSize)// Round down.floor();}cellToMousePos(cell) {return cell.pos.copy().mult(this.cellSize).add(this.drawOffset).add(this.viewOffset).div(1 / this.currentScale).add(Vector.center());}// When clicked, left or rightclick(e) {// If it's not playing, skip the interactionif (this.state >= 2) {return;}// If the event (as e) is passed, update the mouse position using the library functionif (e) {updateMouse(e);}// Get the cell position at the mouselet cellPos = this.mouseToCellPos();let cell = this.getCell(cellPos);// If no cell was found or not covered, skip the interactionif (!cell || cell.covered === false) {return;}// If there's an event (as e), check if it's a right-click and if the game is playing in normal modeelse if (e && e.button === 2 && this.state === 1) {// Toggle the flag state using a bitwise XOR opcell.flagged ^= 1;// Set the current flagged cell countthis.flaggedCount = this.cells.filter(c => c.flagged).length;// Stop herereturn;}// If the cell is not flaggedelse if (!cell.flagged) {// Set the cell as uncoveredcell.covered = null;// Make sure the game is now in full play modethis.state = 1;this.startedAt = e;// The game can call pickMines in this casethis.pickMines();}// Skip the interaction, nothing happenedelse {return;}// Get all cells that are the same mine state, covered, and either not flagged or flagged AND a minelet cells = this.cells.filter(c => c.mine === cell.mine && c.covered && (!c.flagged || c.flagged && c.mine));// Get the current timestamplet now = e && e.timeStamp || performance.now();// If the cell if not a mineif (!cell.mine) {// If the cell and its neighbors are openif (!cell.mineCount) {// The immediately neighbords around the clicked cell that aren't coveredcells = cell.click();} else {// There's only 1 cell to uncovercells = [cell];}}// Clicked on a mineelse {// Set the losing statethis.state = 2;// Reset game zoom levelthis.zoomLevel = 1;// Set the current timestamp for the animationthis.finishedAt = now;// Get the final flagged, non-mine countthis.flaggedCount = this.cells.filter(c => c.flagged && !c.mine).length;}// For each selected cellscells.forEach(c => {// Remove the coverc.covered = false;// Set the timestamp to start the animation for this cellc.uncoveredAt = now + c.pos.dist(cellPos) / SQRT2 * 100;});// The count of remaining tiles to uncover minus the mine countthis.tilesLeft = this.cells.filter(c => c.covered).length - this.mineCount;// If there's no tiles leftif (this.tilesLeft === 0) {// Set the winning statethis.state = 3;this.zoomLevel = 1;// Set the current timestamp for the animationthis.finishedAt = now;}}
}// The Cell class
class Cell {// Cell init// Takes an object with x/y properties// Takes the current game that the cell is attached toconstructor({x, y}, game) {// Sets the position as a vectorthis.pos = createVector(x, y);// The current game instancethis.game = game;// Jump to resetthis.reset();}// Set the cell values for a new gamereset() {// No mine neighbors are determinable yetthis.mineCount = 0;// Not a minethis.mine = false;// Coveredthis.covered = true;// Not flaggedthis.flagged = false;// Having been uncovered yetthis.uncoveredAt = null;}getNeighbors() {return this.game.getCellNeighbors(this);}click() {// If the cell is coveredif (this.covered !== false && !this.flagged && !this.mine) {this.covered = false;if (this.mineCount === 0) {let neighbors = this.getNeighbors();return neighbors.filter(n => n.covered).reduce((p, n) => p.concat(n.click()), []).concat(this);}return [this];}return [];}
}

game.css

body {margin: 0;overflow: hidden;background-color: #141414;
}
.overlay {position: fixed;top: 20;left: 0;right: 0;bottom: 0;z-index: 100;
}
body {color: white;
}
#options {position: fixed;top: 5px;left: 5px;padding-left: 2em;background: rgba(0, 0, 0, 2);cursor: pointer;-webkit-transform: scale(2);transform: scale(1);-webkit-transform-origin: top left;transform-origin: top left;-webkit-transition: 100ms -webkit-transform;transition: 100ms -webkit-transform;transition: 100ms transform;transition: 100ms transform, 100ms -webkit-transform;border-radius: 10px;overflow: hidden;
}
#options:before {display: block;content: '';cursor: pointer;width: 0;height: 0;border-style: solid;border-width: 0.35em 0 0.35em 0.7em;border-color: transparent transparent transparent white;position: absolute;top: 0.85em;left: 0.85em;margin-left: -0.35em;margin-top: -0.35em;
}
#options:not(.open):hover {-webkit-transform: scale(1.25);transform: scale(1.25);
}
#options.open {background: black;-webkit-transform: scale(1);transform: scale(1);
}
#options.open:before {-webkit-transform: rotate(90deg);transform: rotate(90deg);
}
#options.open #title {cursor: default;
}
#options.open .option {display: block;
}
#options #title {background: rgba(255, 255, 255, 0.5);padding: 0.25em 0.5em;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;
}
#options .option {display: none;padding: 0.5em 0.5em;
}
#options .option:not(:last-child) {border-bottom: 1px solid #333333;
}
#options .option label {cursor: pointer;display: -webkit-box;display: flex;
}
#options .option label input {margin-right: 0.5em;flex-shrink: 1;color: white;
}
#options .option label input[type="button"],
#options .option label input[type="number"],
#options .option label input[type="text"] {background: #242424;border: 1px solid #2e2e2e;padding: 0.15em 0.6em;border-radius: 2px;
}
#options .option label input[type="button"] {border-radius: 4px;cursor: pointer;
}
#options .option label input[type="number"] {width: 100px;
}
#options .option label input[type="checkbox"] {-webkit-transform: scale(1.25);transform: scale(1.25);cursor: pointer;
}

有什么意见请在下方评论,谢谢!

扫雷源代码(HTML)相关推荐

  1. html扫雷源码原理,js实现扫雷源代码

    经过一段时间学习,对javascript有了一个初步的了解自己制作了一个扫雷,源代码+详细注释放在后面,先看下效果图. 初始化界面: 游戏界面: 难易程度切换: 游戏结束: 思路 采用构造函数的形式进 ...

  2. c语言扫雷源代码简单版,C语言扫雷游戏源代码

    C语言扫雷游戏源代码 /* 模拟扫雷游戏 */ #include #include #include #include #include #include #include union REGS re ...

  3. java扫雷源代码思路_java实现扫雷游戏

    初学Java,写了一个扫雷代码来锻炼一下自己的代码能力. 一.代码思路 代码思路很重要,如果事先就想好了代码思路,那么写这一个代码肯定是事半功倍,比在哪里瞎打要强不知道多少. 经过思考,觉得可以创建一 ...

  4. VB小游戏设计(一):扫雷

    感谢VB吧@yjtx256,我的程序根据他公开的源代码改编而来 工程文件下载链接:         文件分享 提醒:         文章写得很烂,新手没必要按照博文里的描述来自己写,建议直接下载原工 ...

  5. c语言 扫雷 试题,c语言课程设计经典例题扫雷346.doc

    扫雷源代码,完美运行 /* 模拟扫雷游戏 */ #include #include #include #include #include #include #include union REGS re ...

  6. C4droid:安卓手机最强C/C++编译器

    C4droid:安卓手机最强C/C++编译器 C4droid 功能简介 C4droid 安装步骤 C4droid 调试.图形化设置 C4droid 图形化编程 C4doird 导出程序为手机应用 C4 ...

  7. 用C语言实现扫雷小游戏(附上思路+项目展示+源代码)

    文章目录 前言 一.扫雷小游戏整体思路讲解. 二.game.c各游戏功能函数的讲解 1.InitBoard 初始化数组函数讲解 2.DisplayBoard 打印格子函数讲解 3.Setmine 电脑 ...

  8. VC系统扫雷游戏外挂源代码程序下载(转帖

    VC系统扫雷游戏外挂源代码程序下载(转帖) 2008-03-04 10:25 经过了多次测试写出了历史上第一个有点意义的MFC程序.效果差强人意.^_^ CODE: // CrackWinmineDl ...

  9. Python扫雷游戏源代码及图片素材

    Python扫雷游戏源代码.源程序共有两个文件及一个资源包:main.py及mineblock.py,资源包请前往百度网盘下载, https://pan.baidu.com/s/1u-qsJhAaCJ ...

  10. JS实现扫雷游戏(源代码带注释)

    运行结果: 超级简单,下面直接下面贴上源代码,一共两个文件  扫雷.html 和 saolei.js 扫雷.html  <!DOCTYPE html> <html lang=&quo ...

最新文章

  1. echarts 饼图每块颜色_读者提问,如何让 tooltip 提示框内显示饼图
  2. 服务没有报告任何错误。 请键入 NET HELPMSG 3534 以获得更多的帮助。
  3. 老赵谈IL(3):IL可以看到的东西,其实大都也可以用C#来发现
  4. OAuth2基本概念和运作流程
  5. UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】
  6. [小木虫]推荐几个机器学习算法及应用领域相关的中国大牛
  7. 在udp聊天器里如何给飞秋发消息
  8. centos7安装中文字体
  9. 步进电机怎么选型?步进电机驱动器选型要怎么选?
  10. ppt放映显示备注 投影不显示
  11. 行程单批量打印软件(eTerm航空电子客票行程单打印软件)
  12. 基于opencv的重叠图像的凹点分割(C++)
  13. 魔兽世界8.0哪个服务器稳定,魔兽世界活得最安逸的BOSS!8.0版本才拿到7.0服务器首杀!...
  14. 《软件工程之美》打卡第六周,春招我借这份PDF的复习思路
  15. h5页面跳转关注公众号
  16. 共享充电宝再涨价达每小时6元 客服:市场需求决定的
  17. 【IXDC 2014】小米、BroadLink对垒智能Wi-Fi模块
  18. 下载Android App的历史版本
  19. 安全漏洞SCAP规范标准
  20. 阿里云ECS服务器的wordpress博客域名购买、认证、备案、解析以及绑定

热门文章

  1. framework层Service的基础知识和常见问题
  2. python做社会网络分析_利用GooSeeker分词、Ucient和NetDraw进行社会网络分析
  3. java调用tuxedo中间件_初探TUXEDO中间件
  4. 《普林斯顿微积分读本》笔记-第1章函数、图像和直线
  5. 图形学基础--深入浅出的微积分书籍 《普林斯顿微积分读本》和《托马斯微积分》
  6. Unity 工具之 UniWebView 内嵌网页/浏览器到应用中,并且根据UGUI大小放置(简单适配UGUI)
  7. 需求分析报告模板(免费)
  8. java ee jsp程序_JavaEE程序设计及项目开发教程(JSP篇)
  9. 蓝桥杯代码测评使用指南
  10. 二、列表(java)