miaoda-game-canasta-rules
v0.3.2
Published
Four-player Classic Canasta complete-match rules profile.
Readme
miaoda-game-canasta-rules
Immutable, engine-neutral rules for fixed Classic Canasta profile
pagat-classic-4p-partnership-5000: four seats in partnerships 0/2 and 1/3, two decks plus four
Jokers, eleven-card hands, exposed red threes, frozen and whole discard piles, batch melds, Canastas,
going out, hand settlement, and a 5000-point match target.
pnpm add miaoda-game-canasta-rulesRun a match
import {
applyCanastaAction,
createCanastaGame,
createCanastaPlayerView,
} from 'miaoda-game-canasta-rules';
let state = createCanastaGame({
playerIds: ['north', 'east', 'south', 'west'],
seed: 2026,
});
const playerId = state.activePlayerId;
const view = createCanastaPlayerView(state, playerId);
if (view.legalActions.canDrawStock) {
const drawn = applyCanastaAction(state, { type: 'draw-stock', playerId });
if (drawn.ok) state = drawn.state;
}Build every action from the current player view. meldResources groups natural cards by rank and
provides one shared wild-card pool. Opening melds may require several rank groups in one atomic
meld action. A take-discard action takes the whole pile and must include the top card in a legal
meld plan; additionalMelds can satisfy the partnership's initial threshold. When the stock is empty,
use canEndForEmptyStock unless the view requires an available discard-pile pickup.
The player view contains the viewer's hand, per-player hand counts, stock count, discard top, public
team meld cards, exposed red threes, scores, result, and exact legal-action resources. It never contains
the stock order or opponent hands. After settlement, the current dealer may use start-next-hand if
the match is not complete.
Public events
import { projectCanastaEvents } from 'miaoda-game-canasta-rules';
if (result.ok) {
sendToPlayer(projectCanastaEvents(result.events, playerId, result.state));
}draw exposes only the acting player, including when red threes cause replacement draws.
take-discard exposes only cards committed to public melds, not the rest of the pile moved into the
player's hand. meld and discard carry public card ids. finished carries the two team scores and
fully explainable settlement breakdown; hand-started carries only the next dealer. The projector
returns detached objects, filters dynamic team records to team-a and team-b, and rejects malformed
or unknown runtime events.
Restore a snapshot
import { restoreCanastaState } from 'miaoda-game-canasta-rules';
state = restoreCanastaState(JSON.parse(savedJson));Restore checks the fixed deck, zones and card conservation; seat/team contracts; turn and meld audit fields; red threes; public meld metadata; scores; and derived hand settlement before returning detached data. Authenticate persisted snapshots at the host boundary. Send clients only player views and projected events, never authoritative hands, deck zones, or RNG state.
