Nine Go variants with territory scoring, an MCTS opponent, embed support, and the same headless 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=go&variant=9x9"
style="width:100%;max-width:560px;aspect-ratio:1/1;border:none"
title="Play Go"
></iframe>
| Param | Values | Default |
|---|---|---|
embed | 1 | Required for embed mode |
family | go | chess |
variant | Any variant key below | standard |
opponent | ai | human | ai in embed |
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 go:undo both work.
iframe.contentWindow.postMessage({ type: 'game:setVariant', variant: 'capture-go' }, '*')
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
}
})
Variant parameters follow the Go hub in moddable-rules. Nine of the fourteen hub variants are registered; the rest are listed under gaps below.
| Key | Board | Distinguishing rule |
|---|---|---|
standard | 19×19 | Territory scoring, komi 6.5, positional superko |
13x13 | 13×13 | Standard rules, komi 6.5 |
9x9 | 9×9 | Standard rules, komi 5.5 |
capture-go | 9×9 | First capture wins, passing removed from the move list |
one-colour | 19×19 | Standard rules rendered with a single stone colour |
stoical | 19×19 | Cannot capture on the turn after being captured |
toroidal-go | 11×11 | Edges wrap both ways, komi 4.5 |
gomoku | 15×15 | No captures, exactly five in a row wins, overlines do not |
ninuki-renju | 15×15 | Five in a row, or ten stones captured in pairs |
A variant is a plain object of declarative configuration plus optional hooks. Nothing about a variant requires touching the plugin.
export const captureGo = {
key: 'capture-go',
label: 'Capture Go',
size: 9,
komi: 0,
allowPass: false,
hooks: {
moveFilter(moves) {
return moves.filter(m => m.action !== 'pass')
},
},
winCondition(slice) {
if (slice.captures[0] >= 1) return 'black'
if (slice.captures[1] >= 1) return 'white'
return null
},
}
Available hooks: init, validateMove, applyMove, getLegalMoves, checkWin, moveFilter, captureEffect, continueTurn, beforeMove, afterMove. Top-level winCondition and evaluate are checked before the default rules. Variants compose through extends, which merges hooks rather than replacing them.
Two passes end play and report scoring rather than a winner, so the interface can run a dead-stone marking phase before the count. Call the plugin's score() once stones are agreed.
import { scoreGame } from 'moddable-engine/plugins/go'
const result = scoreGame(slice, {
getNeighbours,
method: 'territory', // or 'area'
komi: 6.5,
deadStones: [40, 41],
})
// { winner, margin, scores: { black, white }, territory, stones, neutral }
Territory scoring counts surrounded points plus prisoners. Area scoring counts surrounded points plus stones on the board. Empty regions bordered by both colours are neutral and count to neither side.
import { createGame, getLegalMoves, getGameStatus, createAI, listVariants } from 'moddable-engine/play'
listVariants('go') // [{ key, label, group, board, description }]
const game = createGame('go', '9x9')
game.applyMove({ coord: 40 })
getGameStatus('go', '9x9', game.getState())
const ai = createAI('go', '9x9', { difficulty: 'hard' })
ai.pickMove(game.getState().slice, 0) // MCTS by default for Go
Five hub variants are deliberately not registered, because each needs a mechanic the engine does not model yet: