perf: track a small list of highlighted cells

This commit is contained in:
ayo 2026-07-02 20:55:03 +02:00
parent 6e6cf2c4f8
commit 749b47fe40
2 changed files with 39 additions and 8 deletions

View file

@ -84,6 +84,8 @@ const Minesweeper = function(appId, version, hooks = undefined) {
let flagsCount = setting.mines let flagsCount = setting.mines
// Mine positions stored as a Set of numeric keys (row * cols + col) for O(1) lookup // Mine positions stored as a Set of numeric keys (row * cols + col) for O(1) lookup
let mines = new Set() let mines = new Set()
// Cells currently highlighted, so removeHighlights only resets these (<=9) instead of the whole grid
let highlightedCells = []
this.initialize = function() { this.initialize = function() {
const headingElement = document.createElement('h1') const headingElement = document.createElement('h1')
@ -190,6 +192,7 @@ const Minesweeper = function(appId, version, hooks = undefined) {
grid.oncontextmenu = () => false grid.oncontextmenu = () => false
flagsCount = setting.mines flagsCount = setting.mines
mines.clear() mines.clear()
highlightedCells = []
for (let i = 0; i < setting.rows; i++) { for (let i = 0; i < setting.rows; i++) {
let row = grid.insertRow(i) let row = grid.insertRow(i)
@ -637,19 +640,20 @@ const Minesweeper = function(appId, version, hooks = undefined) {
} }
function removeHighlights() { function removeHighlights() {
for (let i=0; i<setting.rows; i++) { for (let i = 0; i < highlightedCells.length; i++) {
const rows = grid.rows[i] const currentCell = highlightedCells[i]
if (!rows) continue // guard: a tracked cell may have been flagged/clicked since it was highlighted
for(let j=0; j<setting.cols; j++) { if (getStatus(currentCell) == 'highlighted') setStatus(currentCell, 'default')
let currentCell = grid.rows[i].cells[j]
if (getStatus(currentCell) == 'highlighted') setStatus(currentCell, 'default')
}
} }
highlightedCells = []
} }
function highlightCell(cell) { function highlightCell(cell) {
if (isFlagged(cell)) return if (isFlagged(cell)) return
if (!gameIsDone() && getStatus(cell) == 'default') setStatus(cell, 'highlighted') // currentCell.classList.add('highlight'); if (!gameIsDone() && getStatus(cell) == 'default') {
setStatus(cell, 'highlighted') // currentCell.classList.add('highlight');
highlightedCells.push(cell)
}
} }
function highlightSurroundingCell(cell) { function highlightSurroundingCell(cell) {

View file

@ -89,4 +89,31 @@ describe('Minesweeper board', () => {
expect(grid.getAttribute('game-status')).toBe('inactive') expect(grid.getAttribute('game-status')).toBe('inactive')
everyCell(grid, cell => expect(cell.getAttribute('data-status')).toBe('default')) everyCell(grid, cell => expect(cell.getAttribute('data-status')).toBe('default'))
}) })
it('highlights the pressed cell and clears it when the press moves away', () => {
const grid = mountGame()
const a = grid.rows[5].cells[5]
const b = grid.rows[5].cells[6]
const c = grid.rows[5].cells[7]
// Press-and-hold left on A -> A highlighted.
a.dispatchEvent(new MouseEvent('mousedown', { button: 0, bubbles: true }))
expect(a.getAttribute('data-status')).toBe('highlighted')
// Drag the held press across B then C. Each move must clear the previous
// highlight and leave no stale ones behind.
b.dispatchEvent(new MouseEvent('mousemove', { bubbles: true }))
c.dispatchEvent(new MouseEvent('mousemove', { bubbles: true }))
expect(a.getAttribute('data-status')).toBe('default')
expect(b.getAttribute('data-status')).toBe('default')
expect(c.getAttribute('data-status')).toBe('highlighted')
// Exactly one cell should remain highlighted across the whole grid.
let highlighted = 0
everyCell(grid, cell => {
if (cell.getAttribute('data-status') === 'highlighted') highlighted++
})
expect(highlighted).toBe(1)
})
}) })