Bridge Training

Parsers

Contract strings, scoring and vulnerability aliases, and the engine.parse module that gathers every parser and type guard.

Import from @workspace/bridge/parsers. These parsers accept loosely formatted input from files and forms and return canonical domain values; the strict membership predicates (isScoringMode, isVulnerability…) live in Utils.

Contracts

FunctionSignatureDescription
parseContractString(contract: string) => DisplayContract | nullAccepts ^[1-7](S|H|D|C|NT)(X|XX)?$. Returns { level, suit, doubled } or null.
buildContract(contract: string, declarer: Player) => Contract | nullSame parsing plus declarer and trump (the suit, or null for NT).
parsers.ts
parseContractString("3NT"); // => { level: 3, suit: "NT", doubled: "none" }
parseContractString("4SX"); // => { level: 4, suit: "S", doubled: "X" }
parseContractString("6DXX"); // => { level: 6, suit: "D", doubled: "XX" }
parseContractString("8S"); // => null

buildContract("5HX", "S"); // => { level: 5, suit: "H", trump: "H", declarer: "S", doubled: "X" }
buildContract("3NT", "N"); // => { level: 3, suit: "NT", trump: null, declarer: "N", doubled: "none" }

Scoring

Input is trimmed, upper-cased and stripped of spaces, hyphens and underscores before the alias lookup.

FunctionSignatureDescription
parseScoring(candidate: string) => ScoringModeCanonical mode, "UNSET" when unknown.
mapScoring<T>(value: string, mapping: Record<ScoringModeSet, T>) => T | undefinedLooks the parsed mode up in mapping; undefined when unknown.
AliasesResult
IMP, IMPS, IMP PAIRS"IMP"
TPP, TOTAL POINT(S), MATCHPOINT(S), MP"TPP"
parsers.ts
parseScoring("IMP"); // => "IMP"
parseScoring("match points"); // => "TPP"
parseScoring("total_points"); // => "TPP"
parseScoring("Butler"); // => "UNSET"

mapScoring("imps", { IMP: "International Match Points", TPP: "Total points" }); // => "International Match Points"
mapScoring("Butler", { IMP: 1, TPP: 2 }); // => undefined

Vulnerability

Input is trimmed, upper-cased and stripped of spaces, hyphens, underscores and slashes.

FunctionSignatureDescription
parseVulnerability(vulnerability: string) => VulnerabilityCanonical value, "UNSET" when unknown.
mapVulnerability<T>(value: string, mapping: Record<VulnerabilitySet, T>) => T | undefinedLooks the parsed value up in mapping; undefined when unknown.
AliasesResult
NONE, LOVE"NONE"
NS, N/S, N-S"NS"
EW, E/W, E-W"EW"
ALL, BOTH"ALL"
parsers.ts
parseVulnerability("None"); // => "NONE"
parseVulnerability("Love"); // => "NONE"
parseVulnerability("N/S"); // => "NS"
parseVulnerability("Both"); // => "ALL"
parseVulnerability("Dealer"); // => "UNSET"

mapVulnerability("Both", { NONE: "o", NS: "n", EW: "e", ALL: "b" }); // => "b"
mapVulnerability("??", { NONE: 0, NS: 1, EW: 2, ALL: 3 }); // => undefined

engine.parse

engine.parse has no configuration. It gathers the three parsers above with the card, bid and player parsers and guards that are otherwise reached through @workspace/bridge/card, @workspace/bridge/auction and @workspace/bridge/player.

Cards

MemberSignatureDescription
parseSuit(value: string) => Suit | nullS, H, D, C.
parseRank(value: string) => Rank | nullSingle canonical character; "10" is not accepted.
parseCard(value: string) => Card | nullUppercases and collapses "10" first, then validates.
toCard(input: CardInput) => CardCanonical string from a Card or { suit, rank }; throws InvalidNotationError when it denotes no card.
suitOf(card: Card) => SuitReader.
rankOf(card: Card) => RankReader.
isRank(value: string) => value is Rank
isCard(value: unknown) => value is Card
DEFAULT_RANK_ORDERreadonly Rank[]13 ranks, highest first.
sortRanksDefault(ranks: readonly Rank[]) => Rank[]Default order, highest first; unknown ranks sort last.

Bids

MemberSignatureDescription
parseBid(value: string) => Bid | nullRegular (1H, 3NT) or special (Pass, X, XX, Alert).
splitBid(bid: Bid) => RegularBidParts | null{ level, suit }; null for special bids.
toBid(input: BidInput) => BidCanonical string from a Bid or { level, suit }; throws InvalidNotationError when it denotes no bid.
isBid(value: unknown) => value is Bid

Players and contracts

MemberSignatureDescription
isPlayer(value: string) => value is PlayerCase-insensitive N, E, S, W.
parseVulnerability, parseScoringas above
parseContractString, buildContractas above
parsers.ts
const engine = createBridgeEngine(
  createBridgeContext({ teachingMode: "auction", locale: "en" }),
);

engine.parse.parseCard("SA"); // => "SA"
engine.parse.parseCard("S1"); // => null
engine.parse.parseRank("T"); // => "T"
engine.parse.parseRank("10"); // => null (strict single-character ranks)
engine.parse.suitOf("HQ"); // => "H"
engine.parse.toCard({ suit: "H", rank: "Q" }); // => "HQ"
engine.parse.parseBid("3NT"); // => "3NT"
engine.parse.toBid({ level: 3, suit: "NT" }); // => "3NT"
engine.parse.splitBid("3NT"); // => { level: 3, suit: "NT" }
engine.parse.isPlayer("n"); // => true
engine.parse.sortRanksDefault(["2", "A", "T"]); // => ["A", "T", "2"]
engine.parse.parseVulnerability("Both"); // => "ALL"
engine.parse.buildContract("4S", "W"); // => { level: 4, suit: "S", trump: "S", declarer: "W", doubled: "none" }