Six sow-and-capture variants on the pit topology, with bonus turns, relay sowing, 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=mancala&variant=kalah"
style="width:100%;max-width:560px;aspect-ratio:2/1;border:none"
title="Play Mancala"
></iframe>
| Param | Values | Default |
|---|---|---|
embed | 1 | Required for embed mode |
family | mancala | chess |
variant | Any variant key below | kalah |
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 mancala:undo both work.
iframe.contentWindow.postMessage({ type: 'game:setVariant', variant: 'oware' }, '*')
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: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 six variants from the moddable-rules Mancala hub are playable. Each is fully declared in frontmatter; the plugin holds no variant-specific code.
| Key | Pits | Distinguishing rule |
|---|---|---|
kalah | 6 per side | Capture opposite pit; bonus turn when last seed lands in own store |
oware | 6 per side | Capture from opponent's row when last seed makes 2 or 3; grand-slam protection |
congkak | 7 per side | Bonus turn on store landing; Malaysian variant |
sungka | 7 per side | Filipino variant; simultaneous first sow |
ayo | 6 per side | Relay sowing (continue from the pit the last seed lands in) |
toguz-korgool | 9 per side | Tuz capture (claim an opponent pit permanently) |
The plugin handles sowing, capture, and store logic. All configuration arrives via frontmatter:
| Config key | Effect |
|---|---|
pitsPerSide | Number of pits each player owns (6, 7, or 9) |
seedsPerPit | Starting seeds in each pit |
captureRule | When and how seeds are captured (opposite, count-based, relay) |
bonusTurnOnStore | Last seed in own store earns another turn |
relaySowing | Continue sowing from the pit where the last seed landed |
The game ends when one side is empty. Remaining seeds go to their owner's store. Most seeds wins.
import { createGame, createAI, listVariants } from 'moddable-engine/play'
listVariants('mancala') // [{ key, label, group, board }]
const game = createGame('mancala', 'kalah')
game.applyMove({ action: 'sow', pit: 2, to: 'pit-2' })
const ai = createAI('mancala', 'kalah', { difficulty: 'hard' })
ai.pickMove(game.getState().slice, 0) // minimax with pit evaluation