Back to the paper

Ripple Reveal

Skill-spread 0.61 · Reveals expand in rings that halt at the first numbers.

Mines left
40
Moves
0
Agent playback
Difficulty

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

A generated reveal strategy that opens the board in concentric rings out from the click. Each ring is revealed all at once, but the moment a ring contains any numbered (mine-adjacent) cell, the whole ripple stops there. Instead of a single large flood you get a distance-layered clue structure — a clean expanding front bounded by the nearest numbers — that a skilled solver can read ring by ring, while random play gains little from the layering. Standard 8-neighbor adjacency, single life.

How to read the board

The rule in code

The generated mechanic this game runs. The browser engine is an algorithm-faithful port of it.

class RippleReveal(RevealStrategy):
    """Reveal expands in concentric BFS rings from the click, but halts the
    entire expansion the moment a ring contains any numbered cell."""

    def reveal(self, board, r, c):
        cell = board.grid[r][c]
        if cell.adjacent_mines > 0:
            cell.is_revealed = True
            return [(r, c)]

        revealed = []
        visited = {(r, c)}
        ring = [(r, c)]
        while ring:
            ring_revealed = []
            for cr, cc in ring:
                curr = board.grid[cr][cc]
                if curr.is_mine or curr.is_flagged:
                    continue
                if not curr.is_revealed:
                    curr.is_revealed = True
                    ring_revealed.append((cr, cc))
            revealed.extend(ring_revealed)

            # stop the whole ripple once any numbered cell shows up in this ring
            if any(board.grid[cr][cc].adjacent_mines > 0 for cr, cc in ring_revealed):
                break

            next_ring = []
            for cr, cc in ring_revealed:
                if board.grid[cr][cc].adjacent_mines != 0:
                    continue
                for nr, nc in board.neighbors(cr, cc):
                    if (nr, nc) not in visited:
                        nb = board.grid[nr][nc]
                        if not nb.is_mine and not nb.is_flagged and not nb.is_revealed:
                            visited.add((nr, nc))
                            next_ring.append((nr, nc))
            ring = next_ring
        return revealed

More mechanics to play

5×5 Radius + Drifting MinesClues count mines over a 5×5 region while mines wander each turn.Telegraphed MinesA rotating subset of mines flashes a warning each turn.Ranked Neighborhood InfoClues show comparative rank, not absolute mine counts.Checkerboard RevealCascades skip every other cell, leaving a hidden lattice.