From 0efba1b1646f286a4d57df0c6887a05eb43c74bf Mon Sep 17 00:00:00 2001 From: Lubomir Dolezal Date: Fri, 19 Jan 2024 16:09:27 +0100 Subject: [PATCH] chore: various changes and lint --- .../components/Modal/MinesweeperDialog.vue | 10 +- app/src/components/map/LayerControl.vue | 5 + app/src/components/map/Map.vue | 42 +++-- app/src/config/ideas.js | 2 +- app/src/plugins/minesweeper/board.js | 34 ++-- app/src/plugins/minesweeper/game.js | 9 +- app/src/plugins/minesweeper/index.js | 170 ++++++++---------- 7 files changed, 130 insertions(+), 142 deletions(-) diff --git a/app/src/components/Modal/MinesweeperDialog.vue b/app/src/components/Modal/MinesweeperDialog.vue index 5305c3a5e9..3ce36498bf 100644 --- a/app/src/components/Modal/MinesweeperDialog.vue +++ b/app/src/components/Modal/MinesweeperDialog.vue @@ -5,7 +5,7 @@ @@ -47,7 +47,8 @@ {{ game.game.mineCount }} - Copy to Clipboard + Copy to Clipboard @@ -77,7 +78,8 @@ {{ game.game.mineCount }} - Copy to Clipboard + Copy to Clipboard @@ -126,7 +128,7 @@ export default { copyStatsToClipboard() { const date = new Date(); - var string; + let string; if (this.mode === 'win') { string = `✨ #EOxMinesweeper Challenge ${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()} diff --git a/app/src/components/map/LayerControl.vue b/app/src/components/map/LayerControl.vue index f21cc6c53a..0f92398392 100644 --- a/app/src/components/map/LayerControl.vue +++ b/app/src/components/map/LayerControl.vue @@ -21,6 +21,11 @@ class="layerControl" :class="{'scrollable': appConfig.id === 'gtif' && $vuetify.breakpoint.smAndDown}" > + + + x + +
- Reveal + GAME: Reveal all { + document.addEventListener('minesweeper:start', this.startMineSweepCounter); + + document.addEventListener('minesweeper:continue', this.continueMineSweepCounter); + + document.addEventListener('minesweeper:win', this.winMineSweep); + + document.addEventListener('minesweeper:gameover', this.gameoverMineSweep); + }, + methods: { + startMineSweepCounter() { console.info('Minesweeper::StartTimer'); this.minesweeper.timer = setInterval(() => { this.minesweeper.elapsedSeconds += 1; }, 1000); - }); - - document.addEventListener('minesweeper:continue', () => { + }, + continueMineSweepCounter() { if (this.minesweeper.game.isGameCompleted) { document.dispatchEvent(new Event('minesweeper:win')); } - }); - - document.addEventListener('minesweeper:win', () => { + }, + winMineSweep() { clearInterval(this.minesweeper.timer); this.minesweeper.mode = 'win'; this.minesweeper.isDialogEnabled = true; - }); - - document.addEventListener('minesweeper:gameover', () => { + }, + gameoverMineSweep() { clearInterval(this.minesweeper.timer); this.minesweeper.mode = 'gameover'; this.minesweeper.isDialogEnabled = true; - }); - }, - methods: { + }, convertDateForMsg(time) { let timeConverted = null; if (Array.isArray(time)) { @@ -1129,7 +1132,6 @@ export default { this.minesweeper.isEnabled = false; } else { this.minesweeper.game = new Minesweeper(map, this.indicator.minesweeperOptions); - // this.minesweeper.uids = await createHexMap(map, this.indicator.minesweeperOptions); this.minesweeper.isEnabled = true; this.minesweeper.isDialogEnabled = true; } @@ -1147,6 +1149,10 @@ export default { this.onFetchCustomAreaIndicator, ); window.removeEventListener('message', this.handleExternalMapMessage); + document.removeEventListener('minesweeper:start', this.startMineSweepCounter); + document.removeEventListener('minesweeper:continue', this.continueMineSweepCounter); + document.removeEventListener('minesweeper:win', this.winMineSweep); + document.removeEventListener('minesweeper:gameover', this.gameoverMineSweep); }, }; diff --git a/app/src/config/ideas.js b/app/src/config/ideas.js index e596b1495b..f701192028 100644 --- a/app/src/config/ideas.js +++ b/app/src/config/ideas.js @@ -312,7 +312,7 @@ export const globalIndicators = [ protocol: 'cog', id: 'AQ5', sources: [ - { url: 'https://eox-ideas.s3.eu-central-1.amazonaws.com/ideas_data/Copernicus_DSM_30_N47_00_E014_00_DEM_COG.tif' }, + { url: 'https://eox-gtif-public.s3.eu-central-1.amazonaws.com/ideas_data/Copernicus_DSM_30_N47_00_E014_00_DEM_COG.tif' }, ], style: { variables: { diff --git a/app/src/plugins/minesweeper/board.js b/app/src/plugins/minesweeper/board.js index e91e45c34f..a8ed5d8259 100644 --- a/app/src/plugins/minesweeper/board.js +++ b/app/src/plugins/minesweeper/board.js @@ -49,6 +49,8 @@ export default class HexSweeperGame { const tile = this.board[y][x]; if (!tile.isMine) { tile.isRevealed = true; + } else { + tile.isFlagged = true; } } } @@ -57,10 +59,12 @@ export default class HexSweeperGame { async fromGeoTIFF(options) { try { const tiff = await fromUrl(options.geotiff.url); + // get currently zoomed to location index + const locationIndex = 0; // Convert geographic coordinates to distances using EPSG:3857 - const xmin = proj4(options.geotiff.projection, 'EPSG:3857', [this.locations[0][0], this.locations[0][1]]); - const xmax = proj4(options.geotiff.projection, 'EPSG:3857', [this.locations[0][2], this.locations[0][3]]); + const xmin = proj4(options.geotiff.projection, 'EPSG:3857', [this.locations[locationIndex][0], this.locations[locationIndex][1]]); + const xmax = proj4(options.geotiff.projection, 'EPSG:3857', [this.locations[locationIndex][2], this.locations[locationIndex][3]]); const xDistance = xmax[0] - xmin[0]; const yDistance = xmax[1] - xmin[1]; @@ -73,10 +77,9 @@ export default class HexSweeperGame { // Account for the fact that hexagons are wider than tall * 1.2, ); - // Read the GeoTIFF data into a 1-dimensional array let data = (await tiff.readRasters({ - bbox: options.locations[0], + bbox: options.locations[locationIndex], width: this.width, height: this.height, resampleMethod: 'bilinear', @@ -96,7 +99,7 @@ export default class HexSweeperGame { data = flippedData; - const centerInLatLon = [this.locations[0][0], this.locations[0][1]]; + const centerInLatLon = [this.locations[locationIndex][0], this.locations[locationIndex][1]]; this.center = proj4(options.geotiff.projection, 'EPSG:3857', centerInLatLon); console.log(`GeoTIFF size is ${this.width}x${this.height}`); @@ -163,12 +166,7 @@ export default class HexSweeperGame { } } - enforceBounds(x, y) { - if (this.isOutOfBounds(x, y)) { - // console.warn(`Coordinates [${x}, ${y}] are out of bounds`); - } - } - + /* eslint-disable class-methods-use-this */ getNeighborCoordinates(x, y) { const offsets = (y % 2 === 0) ? EVEN_NEIGHBOR_OFFSETS @@ -183,6 +181,7 @@ export default class HexSweeperGame { * @param {number} r - The axial row coordinate. * @returns {{ x: number, y: number }} Game board coordinates. */ + convertAxialToGameCoords(q, r) { const x = q + Math.floor(r / 2); const y = r; @@ -197,11 +196,11 @@ export default class HexSweeperGame { * @returns {[number, number]} Axial coordinates [q, r]. */ convertGameCoordsToAxial(x, y) { - this.enforceBounds(x, y); const q = x - Math.floor(y / 2); const r = y; return [q, r]; } + /* eslint-enable class-methods-use-this */ /** * Gets the count of adjacent mines for a given tile on the game board. @@ -211,7 +210,6 @@ export default class HexSweeperGame { * @returns {number} The count of adjacent mines. */ getAdjacentMineCount(x, y) { - this.enforceBounds(x, y); const tile = this.get(x, y); return tile.adjacentMines; } @@ -231,6 +229,7 @@ export default class HexSweeperGame { ? EVEN_NEIGHBOR_OFFSETS : ODD_NEIGHBOR_OFFSETS; + // eslint-disable-next-line no-restricted-syntax for (const [dx, dy] of neighbors) { const nx = x + dx; const ny = y + dy; @@ -259,6 +258,9 @@ export default class HexSweeperGame { let coordinatePairs = [[x, y]]; const tile = this.get(x, y); + if (!tile) { + return null; + } if (tile.isRevealed || tile.isFlagged) return []; tile.isRevealed = true; @@ -298,7 +300,9 @@ export default class HexSweeperGame { } get(x, y) { - this.enforceBounds(x, y); - return this.board[y][x]; + if (!this.isOutOfBounds(x, y)) { + return this.board[y][x]; + } + return null; } } diff --git a/app/src/plugins/minesweeper/game.js b/app/src/plugins/minesweeper/game.js index 6c042be763..71faa439ff 100644 --- a/app/src/plugins/minesweeper/game.js +++ b/app/src/plugins/minesweeper/game.js @@ -14,7 +14,10 @@ import { export default class Minesweeper { constructor(map, options) { this.vectorSource = new VectorSource(); - this.vectorLayer = new VectorLayer({ source: this.vectorSource }); + this.vectorLayer = new VectorLayer({ + source: this.vectorSource, + name: 'Minesweep game board', + }); this.map = map; this.options = options; this.game = new HexSweeperGame(options, 0.2); @@ -25,7 +28,7 @@ export default class Minesweeper { async setupGame() { await this.game.fromGeoTIFF(this.options); - const gridLayers = setupGrid(this.map, this.options, this.game); + const gridLayers = setupGrid(this.game); this.grid = gridLayers.grid; this.uids = gridLayers.uids; @@ -64,8 +67,6 @@ export default class Minesweeper { setupGrid() { return setupGrid( - this.map, - this.options, this.game, ); } diff --git a/app/src/plugins/minesweeper/index.js b/app/src/plugins/minesweeper/index.js index fbeadb05ce..ce06849381 100644 --- a/app/src/plugins/minesweeper/index.js +++ b/app/src/plugins/minesweeper/index.js @@ -1,48 +1,85 @@ import { Feature } from 'ol'; import { Polygon } from 'ol/geom'; -import { Image, Vector as VectorLayer } from 'ol/layer'; -import { Vector as VectorSource } from 'ol/source'; import { Text, Style, Fill, Stroke, } from 'ol/style'; import HexGrid from 'ol-ext/render/HexGrid'; import HexMap from 'ol-games/source/HexMap'; +// eslint-disable-next-line import HexSweeperGame from './board'; -export { - createHexMap, - setupGrid, - updateTileVisuals, - updateAllTileVisuals, - handleMapClick, - handleMapRightClick, - getTileStyle, - drawGameBoard, -}; - /** * Set up the game grid using HexGrid and HexMap. * - * @param {Object} map - The OpenLayers map instance. + * @param {Object} game - The game object. * @returns {Object} The created `HexGrid`. */ -const setupGrid = (map, options, game) => { +const setupGrid = (game) => { const grid = new HexGrid({ size: game.gameSize, origin: game.center, }); const hex = new HexMap({ hexGrid: grid }); - const imageLayer = new Image({ source: hex }); - map.addLayer(imageLayer); return { - uids: [imageLayer.ol_uid, hex.ol_uid], + uids: [hex.ol_uid], grid, }; }; +const getTileStyle = (tile) => { + let style; + if (tile.isRevealed === true) { + if (tile.isMine) { + style = new Style({ + stroke: new Stroke({ color: '#000', width: 1 }), + fill: new Fill({ color: 'red' }), + text: new Text({ + text: '💣', + font: '20px Calibri,sans-serif', + fill: new Fill({ color: '#fff' }), + stroke: new Stroke({ color: '#000', width: 3 }), + }), + }); + } else { + style = new Style({ + stroke: new Stroke({ color: '#000', width: 1 }), + fill: new Fill({ color: '#fff0' }), + text: new Text({ + text: tile.adjacentMines ? tile.adjacentMines.toString() : '0', + font: '20px Calibri,sans-serif', + fill: new Fill({ color: '#000' }), + stroke: new Stroke({ color: '#fff', width: 3 }), + }), + }); + } + } else if (tile.isFlagged) { + style = new Style({ + stroke: new Stroke({ color: '#000', width: 1 }), + fill: new Fill({ color: 'blue' }), + text: new Text({ + text: '⚑', + font: '20px Calibri,sans-serif', + fill: new Fill({ color: '#fff' }), + stroke: new Stroke({ color: '#000', width: 3 }), + }), + }); + } else { + style = new Style({ + stroke: new Stroke({ color: '#000', width: 0.5 }), + fill: new Fill({ color: '#aaa' }), // Unrevealed tile color + text: new Text({ + text: '', + font: '20px Calibri,sans-serif', + }), + }); + } + + return style; +}; + const updateTileVisuals = ( x, y, @@ -121,10 +158,14 @@ const handleMapClick = ( const [x, y] = [gameCoords.x - 1, gameCoords.y]; const revealedCoordsList = game.revealTile(x, y); + if (!revealedCoordsList) { + return; + } - for (const [x, y] of revealedCoordsList) { - hasUncoveredMine = hasUncoveredMine || game.get(x, y).isMine; - updateTileVisualsCallback(x, y, grid, vectorSource, game); + // eslint-disable-next-line no-restricted-syntax + for (const [xx, yy] of revealedCoordsList) { + hasUncoveredMine = hasUncoveredMine || game.get(xx, yy).isMine; + updateTileVisualsCallback(xx, yy, grid, vectorSource, game); } if (hasUncoveredMine) { @@ -132,8 +173,6 @@ const handleMapClick = ( } else { document.dispatchEvent(new Event('minesweeper:continue')); } - - return hasUncoveredMine; }; const handleMapRightClick = (e, game, grid, vectorSource, vectorLayer) => { @@ -151,53 +190,6 @@ const handleMapRightClick = (e, game, grid, vectorSource, vectorLayer) => { updateTileVisuals(x, y, grid, vectorSource, vectorLayer, game); }; -const getTileStyle = (tile) => { - let style; - if (tile.isRevealed === true) { - if (tile.isMine) { - style = new Style({ - fill: new Fill({ color: 'red' }), - text: new Text({ - text: '💣', - font: '20px Calibri,sans-serif', - fill: new Fill({ color: '#fff' }), - stroke: new Stroke({ color: '#000', width: 3 }), - }), - }); - } else { - style = new Style({ - fill: new Fill({ color: '#fff0' }), - text: new Text({ - text: tile.adjacentMines ? tile.adjacentMines.toString() : '0', - font: '20px Calibri,sans-serif', - fill: new Fill({ color: '#000' }), - stroke: new Stroke({ color: '#fff', width: 3 }), - }), - }); - } - } else if (tile.isFlagged) { - style = new Style({ - fill: new Fill({ color: 'blue' }), - text: new Text({ - text: '⚑', - font: '20px Calibri,sans-serif', - fill: new Fill({ color: '#fff' }), - stroke: new Stroke({ color: '#000', width: 3 }), - }), - }); - } else { - style = new Style({ - fill: new Fill({ color: '#aaa' }), // Unrevealed tile color - text: new Text({ - text: '', - font: '20px Calibri,sans-serif', - }), - }); - } - - return style; -}; - /** * Draw the game board by creating hexagon features and adding them to the map. * @@ -227,34 +219,12 @@ const drawGameBoard = (map, game, grid, vectorSource) => { } }; -/** -* Initializes and sets up the hex map game. -* -* @param {Object} map - The OpenLayers map instance. -*/ -const createHexMap = async (map, options) => { - const vectorSource = new VectorSource(); - const vectorLayer = new VectorLayer({ - source: vectorSource, - }); - const game = new HexSweeperGame(options, 0.2); - await game.fromGeoTIFF(options); - - const { uids, grid } = setupGrid(map, options, game); - let hasUncoveredMine = false; - - map.on('click', (e) => { - hasUncoveredMine = handleMapClick(e, game, grid, vectorSource); - }); - map.on('contextmenu', (e) => { - handleMapRightClick(e, game, grid, vectorSource, vectorLayer); - return false; - }); - - drawGameBoard(map, game, grid, vectorSource); - - map.addLayer(vectorLayer); - updateAllTileVisuals(game, grid, vectorSource, vectorLayer); - - return uids; +export { + setupGrid, + updateTileVisuals, + updateAllTileVisuals, + handleMapClick, + handleMapRightClick, + getTileStyle, + drawGameBoard, };