Reversi

Three Reversi variants with flanking capture, a positional AI, and the same embed and SDK every family uses.

Embed via iframe

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>

URL parameters

ParamValuesDefault
embed1Required for embed mode
familyreversichess
variantAny variant key belowstandard
opponentai | humanai
difficultybeginner | easy | medium | hard | expertmedium
themeBoard theme idclassic

postMessage control

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' }, '*')

Events from embed

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
  }
})

Variants

All three variants from the moddable-rules Reversi hub are playable. Each is fully declared in frontmatter; the plugin holds no variant-specific code.

KeyBoardDistinguishing rule
standard8×8Most discs wins; flanking in all 8 directions
six-by-six6×6Same rules, smaller board; faster games
anti-reversi8×8Fewest discs wins (misère); forced moves unchanged

Mechanics

The plugin is pure logic with zero game knowledge. All configuration arrives via frontmatter:

Config keyEffect
directions"all" | "orthogonal" | "diagonal"
mustFlipPlacement must flip at least one disc
winBy"most" | "fewest"
passWhenNoMovesAuto-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.

SDK

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