import { Antichess } from 'chessops/variant';// Create positionconst pos = Antichess.default();// Check the context to see if captures are forcedconst ctx = pos.ctx();if (ctx.mustCapture) { console.log('Must capture!');}// Get legal moves (only captures if mustCapture is true)const dests = pos.dests(square, ctx);// Check win conditionif (pos.isVariantEnd()) { const outcome = pos.variantOutcome(); // Current player wins if they have no pieces left console.log('Winner:', outcome?.winner);}
Moves are filtered to only captures when required:
import { Antichess } from 'chessops/variant';const pos = Antichess.default();const ctx = pos.ctx();// If mustCapture is true, only capture moves are legalconst dests = pos.dests(square, ctx);// Returns: captures only if ctx.mustCapture, otherwise all moves
// Game ends when current player has no piecesif (pos.isVariantEnd()) { // From variant.ts:334-336 // isVariantEnd(): boolean { // return this.board[this.turn].isEmpty(); // }}// Stalemate also wins for the stalemated playerconst outcome = pos.variantOutcome(ctx);if (ctx.variantEnd || pos.isStalemate(ctx)) { // Current player wins return { winner: this.turn };}
In Antichess, there is no concept of check. The kingAttackers() method always returns an empty set.
import { KingOfTheHill } from 'chessops/variant';import { SquareSet } from 'chessops/squareSet';const pos = KingOfTheHill.default();// Play movespos.play({ from: 12, to: 28 }); // e2-e4// Check if game ended (king in center)if (pos.isVariantEnd()) { const outcome = pos.variantOutcome(); console.log(`${outcome?.winner} got their king to the center!`);}// The center squaresconst center = SquareSet.center(); // d4, e4, d5, e5
import { ThreeCheck } from 'chessops/variant';import { RemainingChecks } from 'chessops/setup';import { parseFen } from 'chessops/fen';const setup = parseFen( 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1').unwrap();// Set custom remaining checkssetup.remainingChecks = new RemainingChecks(3, 3);setup.remainingChecks.white = 2; // White has given 1 check alreadysetup.remainingChecks.black = 3;const result = ThreeCheck.fromSetup(setup);
// Only bare king is insufficient materialconst pos = ThreeCheck.default();const isInsufficient = pos.hasInsufficientMaterial('white');// Returns true only if white has only their king
import { Horde } from 'chessops/variant';const pos = Horde.default();// White has no kingconst whiteKing = pos.board.kingOf('white');console.log('White king:', whiteKing); // undefined// Black has normal setupconst blackKing = pos.board.kingOf('black');console.log('Black has king:', blackKing !== undefined);// Check win conditionsif (pos.isVariantEnd()) { const outcome = pos.variantOutcome(); if (outcome?.winner === 'white') { console.log('White captured all black pieces!'); } else { console.log('Black captured all white pieces!'); }}
// Game ends when either side has no piecesif (pos.board.white.isEmpty()) { return { winner: 'black' };}if (pos.board.black.isEmpty()) { return { winner: 'white' };}
protected validate(): Result<undefined, PositionError> { if (this.board.occupied.isEmpty()) return Result.err(new PositionError(IllegalSetup.Empty)); // Exactly one king (black's) if (this.board.king.size() !== 1) return Result.err(new PositionError(IllegalSetup.Kings)); // Cannot give check to opponent's king const otherKing = this.board.kingOf(opposite(this.turn)); if (defined(otherKing) && this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) { return Result.err(new PositionError(IllegalSetup.OppositeCheck)); } // Pawn placement rules for (const color of COLORS) { const backranks = this.board.pieces(color, 'king').isEmpty() ? SquareSet.backrank(opposite(color)) : SquareSet.backranks(); if (this.board.pieces(color, 'pawn').intersects(backranks)) { return Result.err(new PositionError(IllegalSetup.PawnsOnBackrank)); } } return Result.ok(undefined);}
Horde has complex insufficient material rules (variant.ts:607-813). The side with the king can always win by capturing the horde, but the horde may have insufficient material depending on piece composition.
protected validate(): Result<undefined, PositionError> { // Position is invalid if: // - There is a check // - There are any pawns if (this.isCheck() || this.board.pawn.nonEmpty()) { return Result.err(new PositionError(IllegalSetup.Variant)); } return super.validate();}
Racing Kings never has insufficient material - both players can always race their king to the 8th rank.