5×5 Radius + Drifting Mines
Skill-spread 0.71 · Clues count mines over a 5×5 region while mines wander each turn.
Left-click reveals · right-click flags (long-press on mobile). Or hand it to an agent above and watch it play — PAFG is the paper's fixed symbolic solver, PAFG-LLM is the mechanic-adapted one.
The mechanic
The highest-lift mechanic in the archive — it best illustrates how far a generated variant can drift from canonical Minesweeper while staying playable. Two mechanics compose: adjacency is widened to a 5×5 (radius-2) neighborhood so every clue counts mines over 24 surrounding cells, and mines drift — each turn every unflagged mine has a 30% chance of wandering into an adjacent empty cell. Flagging a mine pins it in place, which keeps flagging meaningful as a deduction tool. You start with 3 health because the moving hazards make a single life unforgiving.
How to read the board
- Numbers count mines within the whole 5×5 box around a cell — expect large values.
- After every move, unflagged mines may drift one step, so old clues update in place.
- Flag a mine to pin it; pinned mines stop drifting and stabilize nearby clues.
- You have 3 lives — hitting a mine costs one but the game continues.
The rule in code
The generated mechanic this game runs. The browser engine is an algorithm-faithful port of it.
class Radius2MooreNeighborhood(Neighborhood):
"""24 cells in a 5x5 box — every clue counts mines over this whole region."""
def offsets(self):
return [(dr, dc)
for dr in range(-2, 3)
for dc in range(-2, 3)
if (dr, dc) != (0, 0)]
class DriftingMines(MineBehavior):
"""Each turn, every unflagged mine has drift_prob chance of walking into an
adjacent unrevealed, unflagged, non-mine cell. Flagged mines stay pinned."""
DEFAULT_DRIFT_PROB = 0.3
def on_post_action(self, board, game, action):
moved = False
mines = [(r, c)
for r in range(board.config.rows)
for c in range(board.config.cols)
if board.grid[r][c].is_mine and not board.grid[r][c].is_flagged]
for (r, c) in mines:
if self._rng.random() >= self.drift_prob:
continue
candidates = [(nr, nc) for nr, nc in board.neighbors(r, c)
if not board.grid[nr][nc].is_revealed
and not board.grid[nr][nc].is_flagged
and not board.grid[nr][nc].is_mine]
if candidates:
dst = self._rng.choice(candidates)
if board.move_mine((r, c), dst):
moved = True
if moved:
board.recompute_adjacency()