ms_reveal_cell
Reveal a cell in Minesweeper by sending a scout to (row, col); if no mines nearby, surrounding cells open automatically. Uses one step.
Instructions
Send a Fluffling scout to a square at (row, col). If it's clear of nearby mines, the surrounding area cascades open automatically. Counts as one step this turn.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| row | Yes | Row index: 0 = top row, 8 = bottom row | |
| col | Yes | Column index: 0 = left col, 8 = right col |
Implementation Reference
- src/games/minesweeper.ts:204-206 (registration)Registration of the ms_reveal_cell tool on the MCP server, in the registerMinesweeperTools function.
); server.tool( - src/games/minesweeper.ts:209-212 (schema)Zod schema for the tool's input: row and col as integers between 0 and 8.
{ row: z.number().int().min(0).max(8).describe("Row index: 0 = top row, 8 = bottom row"), col: z.number().int().min(0).max(8).describe("Column index: 0 = left col, 8 = right col"), }, - src/games/minesweeper.ts:213-267 (handler)Handler function that executes the ms_reveal_cell logic: validates game state, places mines on first move, reveals cell with BFS cascade, checks for mine hits, win conditions, and turn limits.
async ({ row, col }) => { if (msGame.status === "won" || msGame.status === "lost") { return { content: [{ type: "text", text: `The crossing is over (${msGame.status}). Call ms_new_game to try again.` }], isError: true }; } if (msGame.status === "paused") { return { content: [{ type: "text", text: `⏸ The Flufflings are resting. Check in with your player then call ms_next_turn to continue.\n\n${renderState(msGame)}` }], isError: true }; } if (msGame.revealed[row][col]) { return { content: [{ type: "text", text: `A Fluffling already scouted (row ${row}, col ${col}). Pick somewhere new.\n\n${renderState(msGame)}` }], isError: true }; } if (msGame.flagged[row][col]) { return { content: [{ type: "text", text: `There's a warning post at (row ${row}, col ${col})! Remove it with ms_flag_cell before sending a scout.\n\n${renderState(msGame)}` }], isError: true }; } // First move: place mines now, guaranteeing this cell is safe if (msGame.status === "waiting") { placeMines(row, col, msGame); msGame.status = "in_progress"; msGame.turnNumber = 1; } // Hit a mine? if (msGame.mines[row][col]) { msGame.status = "lost"; return { content: [{ type: "text", text: `💥 Oh no! A Fluffling triggered a mine at (row ${row}, col ${col})! The crossing has failed.\n\n${renderState(msGame)}`, }], }; } // Safe — cascade reveal floodReveal(msGame, row, col); msGame.movesThisTurn++; // Win check if (checkWin(msGame)) { msGame.status = "won"; return { content: [{ type: "text", text: `🎉 The last safe path is cleared at (row ${row}, col ${col})! The Flufflings scamper across the finish line, terrified but alive!\n\n${renderState(msGame)}`, }], }; } applyTurnLimit(msGame); return { content: [{ type: "text", text: `Scout sent to (row ${row}, col ${col}) — path clear!\n\n${renderState(msGame)}`, }], }; } - src/games/minesweeper.ts:65-75 (helper)Helper to count adjacent mines for a given cell, used by floodReveal to determine cascade boundaries.
function countAdjacentMines(mines: boolean[][], row: number, col: number): number { let count = 0; for (let dr = -1; dr <= 1; dr++) { for (let dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; const r = row + dr, c = col + dc; if (r >= 0 && r < ROWS && c >= 0 && c < COLS && mines[r][c]) count++; } } return count; } - src/games/minesweeper.ts:77-104 (helper)BFS flood-fill helper that reveals all connected empty cells and their numeric borders, called by the ms_reveal_cell handler when a safe cell is clicked.
function floodReveal(state: MinesweeperState, startRow: number, startCol: number): void { // BFS cascade: reveal all connected zero-adj cells and their numeric borders. const queue: [number, number][] = [[startRow, startCol]]; const visited = new Set<string>(); while (queue.length > 0) { const [r, c] = queue.shift()!; const key = `${r},${c}`; if (visited.has(key)) continue; visited.add(key); if (r < 0 || r >= ROWS || c < 0 || c >= COLS) continue; if (state.revealed[r][c] || state.flagged[r][c]) continue; state.revealed[r][c] = true; state.revealedCount++; // Only cascade from cells with zero adjacent mines if (countAdjacentMines(state.mines, r, c) === 0) { for (let dr = -1; dr <= 1; dr++) { for (let dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; queue.push([r + dr, c + dc]); } } } } }