Simplify some calls

This commit is contained in:
Florine W. Dekker 2020-07-25 22:00:33 +02:00
parent 7dd4af8787
commit 08b707d017
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
2 changed files with 55 additions and 31 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "minesweeper", "name": "minesweeper",
"version": "0.0.4", "version": "0.0.5",
"description": "Just Minesweeper!", "description": "Just Minesweeper!",
"author": "Felix W. Dekker", "author": "Felix W. Dekker",
"browser": "dist/bundle.js", "browser": "dist/bundle.js",

View File

@ -2,7 +2,7 @@ import {$, doAfterLoad, footer, header, nav} from "@fwdekker/template";
import {MersenneTwister19937, Random} from "random-js"; import {MersenneTwister19937, Random} from "random-js";
const logArea = document.getElementById("logArea"); const logArea = $("#logArea");
const log = (message) => { const log = (message) => {
logArea.value += `${message}\n`; logArea.value += `${message}\n`;
logArea.scrollTop = logArea.scrollHeight; logArea.scrollTop = logArea.scrollHeight;
@ -17,12 +17,12 @@ class Game {
* Constructs and starts a new game of Minesweeper. * Constructs and starts a new game of Minesweeper.
*/ */
constructor() { constructor() {
this.canvas = document.getElementById("canvas"); this.canvas = $("#canvas");
this.settingsForm = document.getElementById("settingsForm"); this.settingsForm = $("#settingsForm");
this.widthInput = document.getElementById("settingsWidth"); this.widthInput = $("#settingsWidth");
this.heightInput = document.getElementById("settingsHeight"); this.heightInput = $("#settingsHeight");
this.minesInput = document.getElementById("settingsMines"); this.minesInput = $("#settingsMines");
this.seedInput = document.getElementById("settingsSeed"); this.seedInput = $("#settingsSeed");
this.reset(); this.reset();
this.display = new Display(this.canvas, this.field); this.display = new Display(this.canvas, this.field);
@ -116,7 +116,7 @@ class Display {
constructor(canvas, field) { constructor(canvas, field) {
// TODO Remove this \/ // TODO Remove this \/
this.frameNumber = 0; this.frameNumber = 0;
this.counter = document.getElementById("counter"); this.counter = $("#counter");
window.setInterval(() => { window.setInterval(() => {
this.counter.innerText = "" + (this.frameNumber * 4); this.counter.innerText = "" + (this.frameNumber * 4);
this.frameNumber = 0; this.frameNumber = 0;
@ -198,7 +198,7 @@ class Display {
ctx.textBaseline = "middle"; ctx.textBaseline = "middle";
ctx.textAlign = "center"; ctx.textAlign = "center";
this.field.cellList.forEach(cell => { this.field.cellList.forEach(cell => {
const neighborMineCount = cell.getNeighborMineCount(); const neighborMineCount = cell.getNeighborCount(it => it.hasMine);
let contents; let contents;
if (cell.isCovered) { if (cell.isCovered) {
if (cell.hasFlag) if (cell.hasFlag)
@ -260,6 +260,7 @@ class Field {
constructor(width, height, mineCount, seed = undefined) { constructor(width, height, mineCount, seed = undefined) {
this.width = width; this.width = width;
this.height = height; this.height = height;
this.mineCount = mineCount;
const mines = Array(width * height).fill(true, 0, mineCount).fill(false, mineCount); const mines = Array(width * height).fill(true, 0, mineCount).fill(false, mineCount);
shuffleArrayInPlace(mines, seed); shuffleArrayInPlace(mines, seed);
@ -268,6 +269,18 @@ class Field {
this.cells = chunkifyArray(this.cellList, this.width); this.cells = chunkifyArray(this.cellList, this.width);
} }
/**
* Returns a deep copy of this field.
*
* @return {Field} a deep copy of this field
*/
copy() {
const copy = new Field(this.width, this.height, this.mineCount, undefined);
copy.cellList = this.cellList.map(it => it.copy());
copy.cellList.forEach(it => it.field = copy);
copy.cells = chunkifyArray(copy.cellList, copy.width);
}
/** /**
* Returns the cell at the given coordinates, or throws an error if there is no cell there. * Returns the cell at the given coordinates, or throws an error if there is no cell there.
@ -296,16 +309,23 @@ class Field {
return row === undefined ? orElse : row[y]; return row === undefined ? orElse : row[y];
} }
/** /**
* Returns `true` if and only if all mineless cells have been uncovered. * Returns `true` if and only if all mineless cells have been uncovered.
* *
* @return `true` if and only if all mineless cells have been uncovered * @return `true` if and only if all mineless cells have been uncovered
*/ */
isCleared() { isCleared() {
return this.cellList.reduce( return this.cellList.find(it => !it.hasMine && it.isCovered) !== undefined;
(isCleared, cell) => isCleared && (!cell.isCovered || cell.hasMine), }
true
); /**
* Returns `true` if and only if a mine has been uncovered.
*
* @returns {boolean} if and only if a mine has been uncovered
*/
isFailed() {
return this.cellList.find(it => it.hasMine && !it.isCovered) !== undefined;
} }
} }
@ -331,6 +351,18 @@ class Cell {
this.hasFlag = false; this.hasFlag = false;
} }
/**
* Returns a deep copy of this cell, without a reference to any field.
*
* @returns {Cell} a deep copy of this cell, without a reference to any field
*/
copy() {
const copy = new Cell(undefined, this.x, this.y, this.hasMine);
copy.isCovered = this.isCovered;
copy.hasFlag = this.hasFlag
return copy;
}
/** /**
* Returns the `Cell`s that are adjacent to this cell. * Returns the `Cell`s that are adjacent to this cell.
@ -351,21 +383,13 @@ class Cell {
} }
/** /**
* Returns the number of neighbors that have a flag. * Returns the number of neighbors that satisfy the given property.
* *
* @returns {number} the number of neighbors that have a flag * @param property {function} the property to check on each neighbor
* @returns {number} the number of neighbors that satisfy the given property
*/ */
getNeighborFlagCount() { getNeighborCount(property) {
return this.getNeighbors().filter(it => it.hasFlag).length; return this.getNeighbors().filter(property).length;
}
/**
* Returns the number of neighbors that have a mine.
*
* @returns {number} the number of neighbors that have a mine
*/
getNeighborMineCount() {
return this.getNeighbors().filter(it => it.hasMine).length;
} }
@ -375,7 +399,7 @@ class Cell {
*/ */
chord() { chord() {
if (this.isCovered) return; if (this.isCovered) return;
if (this.getNeighborMineCount() !== this.getNeighborFlagCount()) return; if (this.getNeighborCount(it => it.hasFlag) !== this.getNeighborCount(it => it.hasMine)) return;
this.getNeighbors() this.getNeighbors()
.filter(it => it.isCovered && !it.hasFlag) .filter(it => it.isCovered && !it.hasFlag)
@ -397,7 +421,7 @@ class Cell {
} }
this.getNeighbors() this.getNeighbors()
.filter(it => it.getNeighborMineCount() === 0 && !it.hasMine && !it.hasFlag) .filter(it => it.getNeighborCount(it => it.hasMine) === 0 && !it.hasMine && !it.hasFlag)
.forEach(it => it.uncover()); .forEach(it => it.uncover());
} }
@ -418,7 +442,7 @@ class Cell {
this.isCovered = false; this.isCovered = false;
this.hasFlag = false; this.hasFlag = false;
if (!this.hasMine && this.getNeighborMineCount() === 0) if (!this.hasMine && this.getNeighborCount(it => it.hasMine) === 0)
this.chord(); this.chord();
} }
} }
@ -477,7 +501,7 @@ doAfterLoad(() => {
// Initialize game // Initialize game
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
document.getElementById("settingsSeed").value = $("#settingsSeed").value =
urlParams.get("seed") === null urlParams.get("seed") === null
? "" + Math.floor(Math.random() * 1000000000000) ? "" + Math.floor(Math.random() * 1000000000000)
: urlParams.get("seed"); : urlParams.get("seed");