Calculations

Specific Game Logic Calculations

In Minesweeper, every click—whether left, right, or a special interaction like clicking on a number—triggers specific calculations that influence the game state. Understanding these in-game calculations is crucial for anyone developing Minesweeper, as each action must be precisely handled to provide a smooth and intuitive player experience.

In this article, we’ll break down the key interactions that occur when players interact with Minesweeper cells, including code examples to illustrate these mechanics.

Basic Interactions: Left Click (Reveal) and Right Click (Flag)

1. Left Click: Revealing a Cell

When a player left-clicks a cell, they reveal its content, which may be a number (indicating the count of nearby mines), an empty space, or a mine.

Code Example

typescript

function handleLeftClick(cell: MinesweeperCell) { 
    // If the cell is flagged, ignore the click
    if (cell.isFlagged) return;

    // If the cell contains a mine, the game is lost
    if (cell.isMine) {
        revealAllMines();
        gameOver();
    } else {
        revealCell(cell);
    }
}
function revealCell(cell: MinesweeperCell) {
    // Mark cell as revealed
    cell.isRevealed = true;

    // If the cell has no adjacent mines, reveal neighboring cells
    if (cell.adjacentMines === 0) {
        for (let neighbor of cell.getNeighbors()) {
            if (!neighbor.isRevealed && !neighbor.isFlagged) {
                revealCell(neighbor); // Recursively reveal empty cells
            }
        }
    }
}

In this example:

  • If a cell contains a mine, revealAllMines() is called to end the game.
  • If the cell has no adjacent mines, a recursive reveal occurs to uncover all connected, empty cells.

2. Right Click: Flagging or Unflagging a Cell

Right-clicking a cell allows the player to place or remove a flag, which they can use to mark potential mines.

Code Example

typescript

function handleRightClick(cell: MinesweeperCell) { 
    // If the cell is already revealed, ignore the click
    if (cell.isRevealed) return;

    // Toggle the flagged status of the cell
    cell.isFlagged = !cell.isFlagged;

    // Update the remaining mine count
    updateMineCount();
}

This function toggles the isFlagged property for a cell. Flags are typically restricted to unrevealed cells only, ensuring that players cannot flag already revealed cells.

Mobile Adaptation: Long Press for Flagging

On mobile devices, long-press gestures replace right-clicks. Here’s an example of a simple long-press detection for flagging cells:

Code Example

typescript

let pressTimer: number;

function handleLongPressStart(cell: MinesweeperCell) {
    pressTimer = setTimeout(() => handleRightClick(cell), 500); // 500ms for long press
}

function handleLongPressEnd() {
    clearTimeout(pressTimer); // Clear timer if user releases early
}

// Attach event listeners for touch events on each cell
cellElement.addEventListener('touchstart', () => handleLongPressStart(cell));
cellElement.addEventListener('touchend', handleLongPressEnd);

In this mobile-friendly code:

  • handleLongPressStart() initiates a timer when a touch starts.

  • handleLongPressEnd() cancels the timer if the user releases the touch early, allowing flags to be set only with a sustained press.

Advanced Interactions: Satisfied Number Cells

Once a number cell is satisfied—meaning it has the correct number of flagged neighboring cells—players can click it to reveal all adjacent cells. This action speeds up gameplay by revealing multiple cells at once.

Code Example

typescript

function handleNumberClick(cell: MinesweeperCell) {
    // Check if the number cell is satisfied
    if (isSatisfied(cell)) {
        // Reveal all neighboring cells that are not flagged
        for (let neighbor of cell.getNeighbors()) {
            if (!neighbor.isRevealed && !neighbor.isFlagged) {
                revealCell(neighbor);
            }
        }
    }
}

function isSatisfied(cell: MinesweeperCell) {
    // Count flagged neighbors and compare to the cell's number
    let flagCount = 0;
    for (let neighbor of cell.getNeighbors()) {
        if (neighbor.isFlagged) flagCount++;
    }
    return flagCount === cell.adjacentMines;
}

The isSatisfied() function checks if the number of flagged neighbors matches the cell's adjacentMines value. If satisfied, all unrevealed, unflagged neighbors are revealed with revealCell().

Recursive Reveal: Empty Cells with No Adjacent Mines

When a player clicks an empty cell (a cell with 0 adjacent mines), the game reveals all connected empty cells, creating a “cascade” effect.

Code Example

typescript

function revealEmptyCell(cell) {
    if (!cell.isRevealed && !cell.isMine && cell.adjacentMines === 0) {
        cell.isRevealed = true;
        for (let neighbor of cell.getNeighbors()) {
            if (!neighbor.isRevealed && !neighbor.isFlagged) {
                revealEmptyCell(neighbor);
            }
        }
    }
}

This function recursively reveals all connected empty cells and their adjacent numbered cells, providing players with immediate information about a large section of the board.

Game-Over Condition and Win Checks

The game ends either when the player reveals a mine (loses) or successfully flags all mines and reveals all safe cells (wins).

Code Example

typescript

function checkWin() {
    for (let row of board) {
        for (let cell of row) {
            if (!cell.isMine && !cell.isRevealed) return false; // Unrevealed safe cells
        }
    }
    return true;
}

function gameOver() {
    revealAllMines();
    alert("Game Over!");
}

function checkGameEnd() {
    if (checkWin()) {
        alert("Congratulations! You've won!");
    }
}

This code checks if all safe cells are revealed, confirming a win when true. gameOver() is triggered upon clicking a mine, revealing all mines to show the full board.

Summary

Each Minesweeper interaction requires precise logic to ensure smooth gameplay. From basic left- and right-clicks to advanced interactions like satisfied number cells, the code must account for all possible scenarios. Here's a quick recap of each action covered:

Left Click (Reveal)

Reveals a cell and triggers recursive reveals for empty cells.

Right Click (Flag):

Toggles flag status for marking suspected mines.

Satisfied Number Cell Click:

Reveals all unflagged neighboring cells when flagged neighbors match the cell's number.

Recursive Empty Cell Reveal:

Uncovers large sections of the board by revealing all connected empty cells.

Game-End Conditions:

Checks for win or loss based on cell reveals and flagged mines.

These interactions provide Minesweeper's characteristic balance between logic and suspense. By understanding these calculations, you'll have a solid foundation for implementing Minesweeper's core mechanics in any development environment.