Xiangqi

Chinese chess on a 9×10 board: generals confined to their palaces, a river the elephants cannot cross, and a cannon that captures only by jumping a screen.

Embed via iframe

<iframe
  src="https://engine.moddable.games/play/?embed=1&family=xiangqi&variant=standard"
  style="width:100%;max-width:560px;aspect-ratio:9/10;border:none"
  title="Play Xiangqi"
></iframe>

The parameters, commands and events are identical to every other family. See the Go page for the full table; substitute family=xiangqi.

Variants

Parameters follow the xiangqi hub in moddable-rules, and each setup is copied verbatim from the variant's frontmatter — the same string the published board diagram is drawn from.

KeyBoardDistinguishing rule
standard9×10River, palace confinement, flying general, cannon screen capture
minixiangqi7×7Reduced board, no river; elephants and advisors move freely
xiangqi-427×6Minimal board (42 points), fast games

Three variants are registered. Six more exist in the hub and are held back for the reasons under known gaps.

Pieces and notation

The plugin declares one vocabulary, and it is the same vocabulary the variant frontmatter uses. Symbols are the canonical Xiangqi FEN letters, so a position read from the rules parses here and renders through the piece mapping the board diagram already uses. Red is player 0 and takes the uppercase letter.

TypeRedBlackMovement
generalKkOne step orthogonally, never leaving the palace
advisorAaOne step diagonally, never leaving the palace
elephantEeTwo points diagonally, blocked at the midpoint, never crossing the river
horseHhKnight's move, blocked by a piece on the leg it leaves along
chariotRrSlides orthogonally, as a rook
cannonCcSlides orthogonally to move; captures only by jumping exactly one screen
soldierPpOne step forward; gains sideways steps after crossing the river

The soldier is P rather than S because that is what canonical Xiangqi FEN uses. Getting this wrong is not cosmetic: the symbol a piece serialises to is what the renderer resolves against the piece set, so a piece emitting an unmapped symbol is simply not drawn.

Variant parameters

The plugin is parametric, with no per-variant code:

ParameterDefaultEffect
rows / cols10 / 9Board dimensions
hasRivertrueElephants may not cross; soldiers widen after crossing
flyingGeneralRuletrueThe generals may not face each other down an open file
cannonJumpToMovefalseWhen true the cannon must jump a screen to move as well as to capture
passAllowedfalseAdds { action: 'pass' } to the move list

The plugin composes the rules constraint.region, capture.screen-jump, constraint.facing, check and checkmate.

Interaction

Xiangqi uses the move interaction model: click to select one of your own pieces, click again to commit. Selection is rejected on empty points and on the opponent's pieces, and every generated move is filtered through the check test before it is offered, so the flying general rule constrains the move list rather than being caught after the fact.

import { interactionModelFor } from 'moddable-engine/play'

const model = interactionModelFor('xiangqi')   // the 'move' model
model.handleClick(from, ctx)                   // { type: 'select', pos }
model.handleClick(to, ctx)                     // { type: 'move', move }

SDK

import { createGame, getLegalMoves, getGameStatus, createAI, listVariants } from 'moddable-engine/play'

listVariants('xiangqi')                  // [{ key, label, group, board, description }]
const game = createGame('xiangqi', 'standard')
game.getLegalMoves()                     // [{ from, to }, ...]
game.applyMove({ from: 84, to: 63 })
getGameStatus('xiangqi', 'standard', game.getState())

const ai = createAI('xiangqi', 'standard', { difficulty: 'hard' })
ai.pickMove(game.getState().slice, 0)

Difficulty accepts beginner, easy, medium, hard and expert, as it does for every family.

Known gaps

Six hub variants are not registered. Each is documented in the rulebook frontmatter (engine.unsupported) with its reason: