Ripple Reveal
Skill-spread 0.61 · Reveals expand in rings that halt at the first numbers.
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
- A click on an empty cell ripples outward and stops as soon as numbers appear.
- The outermost revealed ring is your live constraint frontier — read it first.
- Because reveals are bounded, you'll open new fronts by clicking safe edge cells.
- Clue numbers are the ordinary count of the 8 surrounding mines.
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