Crazyhouse is a chess variant where captured pieces can be dropped back on the board. Captured pieces are stored in “pockets” and can be placed on any empty square as a move.
import { Crazyhouse } from 'chessops/variant';// Create a new Crazyhouse positionconst pos = Crazyhouse.default();// Play a normal movepos.play({ from: 12, to: 28 }); // e2-e4// After capturing, check pocketsif (pos.pockets) { console.log('White pocket:', pos.pockets.white); console.log('Black pocket:', pos.pockets.black);}
Drop moves place a piece from your pocket onto an empty square:
import { Crazyhouse } from 'chessops/variant';import { isDrop } from 'chessops/types';const pos = Crazyhouse.default();// Get valid drop destinationsconst dropSquares = pos.dropDests();// Make a drop moveconst dropMove = { role: 'knight', to: 42 // f6};if (isDrop(dropMove)) { pos.play(dropMove);}
Drops follow specific rules implemented in dropDests():
const pos = Crazyhouse.default();const ctx = pos.ctx();// Get valid drop destinationsconst dropSquares = pos.dropDests(ctx);// Pawns cannot drop on backranks// Non-pawns can drop anywhere empty// When in check, can only drop to block
Pawns cannot be dropped on the 1st or 8th rank. The dropDests() method enforces this by intersecting with SquareSet.backranks().complement().
Promoted pieces are tracked separately and revert to pawns when captured:
const pos = Crazyhouse.default();// Promoted pieces are trackedconsole.log(pos.board.promoted);// When a promoted piece is captured, it goes to pocket as a pawn// This is handled automatically in setupUnchecked():// this.board.promoted = setup.board.promoted// .intersect(setup.board.occupied)// .diff(setup.board.king)// .diff(setup.board.pawn);
import { Crazyhouse } from 'chessops/variant';import { parseSquare } from 'chessops';import { isDrop } from 'chessops/types';// Start a gameconst pos = Crazyhouse.default();// Play some movespos.play({ from: parseSquare('e2')!, to: parseSquare('e4')! });pos.play({ from: parseSquare('d7')!, to: parseSquare('d5')! });pos.play({ from: parseSquare('e4')!, to: parseSquare('d5')! }); // capture// Now white has a pawn in pocketif (pos.pockets) { console.log('White has pawn:', pos.pockets.white.pawn === 1); // Get drop destinations for current player const dropSquares = pos.dropDests(); console.log(`Can drop on ${dropSquares.size()} squares`); // Make a drop if (dropSquares.has(parseSquare('e3')!)) { pos.play({ role: 'pawn', to: parseSquare('e3')! }); }}// Clone position for analysisconst clone = pos.clone();clone.play({ from: parseSquare('e7')!, to: parseSquare('e5')! });// Original position unchangedconsole.log('Position turn:', pos.turn);console.log('Clone turn:', clone.turn);
import { Move, isDrop, isNormal } from 'chessops/types';function handleMove(move: Move) { if (isDrop(move)) { console.log(`Drop ${move.role} on square ${move.to}`); } else if (isNormal(move)) { console.log(`Move from ${move.from} to ${move.to}`); if (move.promotion) { console.log(`Promoting to ${move.promotion}`); } }}
When a promoted piece is captured, it returns to the pocket as a pawn, not as the promoted piece. This is automatically handled by the setupUnchecked() method.