Three Reversi variants with flanking capture, a positional AI, and the same embed and SDK every family uses.
Every game family shares one embed surface. Select the family and variant through the URL.
<iframe
src="https://engine.moddable.games/play/?embed=1&family=reversi&variant=standard"
style="width:100%;max-width:560px;aspect-ratio:1/1;border:none"
title="Play Reversi"
></iframe>
| Param | Values | Default |
|---|---|---|
embed | 1 | Required for embed mode |
family | reversi | chess |
variant | Any variant key below | standard |
opponent | ai | human | ai |
difficulty | beginner | easy | medium | hard | expert | medium |
theme | Board theme id | classic |
Commands accept either the generic game: prefix or the family prefix, so game:undo and reversi:undo both work.
iframe.contentWindow.postMessage({ type: 'game:setVariant', variant: 'anti-reversi' }, '*')
iframe.contentWindow.postMessage({ type: 'game:setDifficulty', difficulty: 'hard' }, '*')
iframe.contentWindow.postMessage({ type: 'game:newGame' }, '*')
iframe.contentWindow.postMessage({ type: 'game:undo' }, '*')
iframe.contentWindow.postMessage({ type: 'game:pass' }, '*')
iframe.contentWindow.postMessage({ type: 'game:resign' }, '*')
iframe.contentWindow.postMessage({ type: 'game:requestState' }, '*')
window.addEventListener('message', (e) => {
switch (e.data.type) {
case 'game:ready': break // { family, variant, state }
case 'game:move': break // { move, state }
case 'game:status': break // { text, gameOver, family, variant }
case 'game:state': break // { state } in reply to requestState
}
})
All three variants from the moddable-rules Reversi hub are playable. Each is fully declared in frontmatter; the plugin holds no variant-specific code.
| Key | Board | Distinguishing rule |
|---|---|---|
standard | 8×8 | Most discs wins; flanking in all 8 directions |
six-by-six | 6×6 | Same rules, smaller board; faster games |
anti-reversi | 8×8 | Fewest discs wins (misère); forced moves unchanged |
The plugin is pure logic with zero game knowledge. All configuration arrives via frontmatter:
| Config key | Effect |
|---|---|
directions | "all" | "orthogonal" | "diagonal" |
mustFlip | Placement must flip at least one disc |
winBy | "most" | "fewest" |
passWhenNoMoves | Auto-pass when no legal placement exists |
The game ends when the board is full or neither player can move. A wipeout (one player has zero discs) also ends immediately.
import { createGame, getLegalMoves, createAI, listVariants } from 'moddable-engine/play'
listVariants('reversi') // [{ key, label, group, board }]
const game = createGame('reversi', 'standard')
game.applyMove({ action: 'place', coord: 20 })
const ai = createAI('reversi', 'standard', { difficulty: 'hard' })
ai.pickMove(game.getState().slice, 0) // minimax with positional weighting