Hitotsu一つ

@johnmorrisdotca/hitotsu 1.1.0 · 2 entry points · 93 exports

@johnmorrisdotca/hitotsu

callMatters cardOfMove colourOf colourWords decodeHitotsu DRAW_TWO encodeHitotsu faceOf freshSeed handOf HITOTSU_CARD_BOX HITOTSU_CAUGHT HITOTSU_CHALLENGE_LOST HITOTSU_CLASSIC HITOTSU_COLOUR_LOOK HITOTSU_COLOURS HITOTSU_DECK HITOTSU_DECK_SIZE HITOTSU_DEFAULT_SIZE HITOTSU_FACE_MARK HITOTSU_MOST_PLAYERS HITOTSU_ONE_HAND HITOTSU_PAPER HITOTSU_PARTY HITOTSU_POINTS HITOTSU_SIZES HITOTSU_STRINGS HitotsuCard HitotsuCardMove hitotsuCardShapes hitotsuCardSvg HitotsuChallenge HitotsuColour hitotsuComputer hitotsuComputerJump HitotsuGame HitotsuHandle hitotsuJumpIns hitotsuMatches HitotsuMove hitotsuMoves HitotsuNews HitotsuOptions hitotsuPlayable hitotsuPoints HitotsuResult HitotsuShape hitotsuShapeSvg HitotsuStrings HitotsuTableOptions HitotsuTableSetUp hitotsuTop hitotsuView HitotsuView hitotsuWinners hitotsuWords identical isDrawCard isHitotsuCard isNumber isWild longestColour mixSeed mountHitotsu movesFor namedTable playableFor playHitotsu quickMove Random readHitotsuMove readHitotsuOptions readTableMove readTableSetUp reshuffledHitotsu REVERSE SEED_MOST seededRandom shuffled shuffledHitotsu SKIP sortHitotsu startHitotsu startTable tableComputerMove tableToPlay waysFor WILD WILD_FOUR

function callMatters

callMatters(game: HitotsuGame, seat: number): boolean

Whether the call is a choice now: this seat is about to play its second-last card.

function cardOfMove

cardOfMove: (move: HitotsuCardMove) => HitotsuCard

The card a card move puts down.

function colourOf

colourOf(card: HitotsuCard): HitotsuColour | null

A card's colour, or null for a wild.

function colourWords

colourWords(colour: HitotsuColour): string

function decodeHitotsu

decodeHitotsu(text: string | null): HitotsuGame | null

const DRAW_TWO

DRAW_TWO: "D"

function encodeHitotsu

encodeHitotsu(game: HitotsuGame): string

function faceOf

faceOf(card: HitotsuCard): string

A card's face: a digit, or S, R, D, W, F.

function freshSeed

freshSeed(random?: Random): number

A fresh seed for a new deal.

function handOf

handOf(game: HitotsuGame, seat: number): HitotsuCard[]

A seat's hand; an empty one for a seat the table does not have.

const HITOTSU_CARD_BOX

HITOTSU_CARD_BOX: { readonly width: 100; readonly height: 140; }

The card's width and height in the design's units.

const HITOTSU_CAUGHT

HITOTSU_CAUGHT: 2

Cards taken for going down to one without calling it, and for a Wild Draw Four challenged and found honest.

const HITOTSU_CHALLENGE_LOST

HITOTSU_CHALLENGE_LOST: 6

const HITOTSU_CLASSIC

HITOTSU_CLASSIC: HitotsuOptions

The published rules: no stacking, no jumping in, sevens and zeros as plain numbers, one card drawn, a Wild Draw Four that may be challenged, seven cards dealt.

const HITOTSU_COLOUR_LOOK

HITOTSU_COLOUR_LOOK: Record<HitotsuColour | "W", { fill: string; ink: string; element: string; name: string; }>

Each colour's fill, the ink written on it, its element and its name; W is the wilds' and the back's.

const HITOTSU_COLOURS

HITOTSU_COLOURS: readonly HitotsuColour[]

The four colours in the order a hand sorts them and a picker offers them.

const HITOTSU_DECK

HITOTSU_DECK: readonly string[]

Every card, in the deck's own order.

const HITOTSU_DECK_SIZE

HITOTSU_DECK_SIZE: 108

The cards in the deck: 25 in each colour and eight wilds.

const HITOTSU_DEFAULT_SIZE

HITOTSU_DEFAULT_SIZE: 500

const HITOTSU_FACE_MARK

HITOTSU_FACE_MARK: Record<string, string>

What each face shows in the middle of a card and in its corners; a number shows itself.

const HITOTSU_MOST_PLAYERS

HITOTSU_MOST_PLAYERS: 8

The most at a table: eight, which one deck of 108 deals seven each and leaves a stock to draw from.

const HITOTSU_ONE_HAND

HITOTSU_ONE_HAND: 1

HOW LONG A GAME OF HITOTSU LASTS, its "size": to 200 or 500 points, or a single hand (1), the party table's game. 500 is the published game's total.

const HITOTSU_PAPER

HITOTSU_PAPER: "#fffdf6"

The card's paper, round every card and under the diamond.

const HITOTSU_PARTY

HITOTSU_PARTY: HitotsuOptions

PARTY MODE: the house rules a big table plays by, and a short game — five cards each, one hand, draw cards stacking on any draw card, jumping in, and sevens and zeros moving hands round. Each can still be changed at the set-up.

const HITOTSU_POINTS

HITOTSU_POINTS: { readonly action: 20; readonly wild: 50; }

What a card left in a hand is worth to the player who went out: its number, twenty an action card, fifty a wild.

const HITOTSU_SIZES

HITOTSU_SIZES: readonly [1, 200, 500]

const HITOTSU_STRINGS

HITOTSU_STRINGS: Required<HitotsuStrings>

type HitotsuCard

type HitotsuCard = string;

A card by its short name: its colour letter (W for a wild), its face — a digit, S skip, R reverse, D draw two, W wild, F wild draw four — and which copy of that card it is, so the two red fives are R50 and R51. Two cards are the same card to play when their first two letters are.

type HitotsuCardMove

type HitotsuCardMove = Extract<HitotsuMove, { play: HitotsuCard }> | Extract<HitotsuMove, { jump: HitotsuCard }>;

A move that puts a card down: in turn, or jumping in.

function hitotsuCardShapes

hitotsuCardShapes(card: HitotsuCard | null, called?: HitotsuColour): HitotsuShape[]

The shapes of one card, in drawing order: a face, or the back for null. called marks a wild on the pile with the colour it called.

function hitotsuCardSvg

hitotsuCardSvg(card: HitotsuCard | null, { width, called, title }?: { width?: number; called?: HitotsuColour; title?: string; }): string

A whole card as an SVG document, width pixels wide (140/100 of it tall): a face, or the back for null.

type HitotsuChallenge

type HitotsuChallenge = { by: number; bluffed: boolean };

A Wild Draw Four the player to move may challenge: who played it, and whether they held a card of the colour it was played on.

type HitotsuColour

type HitotsuColour = "R" | "Y" | "G" | "B";

A card's colour: red, yellow, green or blue. A wild card has none until it is played and one is called.

function hitotsuComputer

hitotsuComputer(game: HitotsuGame): HitotsuMove

function hitotsuComputerJump

hitotsuComputerJump(game: HitotsuGame): HitotsuMove | null

A computer's card played out of turn, where the table jumps in: the first computer seat round from the player to move that holds a card identical to the top one. Null when none can, or jump-in is not played.

type HitotsuGame

type HitotsuGame = { size: number; players: readonly string[]; computers: readonly boolean[]; seed: number; options: HitotsuOptions; moves: readonly HitotsuMove[]; /** Which hand this is, from 0: it decides who plays first. */ hand: number; phase: "playing" | "over"; hands: HitotsuCard[][]; /** Face down, top card first. */ stock: HitotsuCard[]; /** Face up, top card last. */ discard: HitotsuCard[]; /** The colour t…

A GAME OF HITOTSU: its table and moves (what is kept), and the hand they have reached. size is the score that wins — 200 or 500 — or 1 for a game of a single hand.

type HitotsuHandle

type HitotsuHandle = { /** The game as it stands. */ game(): HitotsuGame; /** Deal again, with any options changed. */ restart(options?: Omit<HitotsuTableOptions, "strings" | "theme" | "onMove">): void; destroy(): void; };

function hitotsuJumpIns

hitotsuJumpIns(game: HitotsuGame): HitotsuMove[]

JUMPING IN: with the option on, any other player holding a card identical to the one on top — same colour, same face, never a wild — may play it out of turn, and play goes on from them. Not on a draw waiting to be taken, a challenge waiting to be made, or while the player to move decides about a card they drew.

function hitotsuMatches

hitotsuMatches(game: HitotsuGame, card: HitotsuCard): boolean

Whether a card may go on the pile on an ordinary turn: a wild always; otherwise the colour to follow, or the top card's face.

type HitotsuMove

type HitotsuMove = | { play: HitotsuCard; /** The colour a wild card calls. */ colour?: HitotsuColour; /** The seat a seven swaps hands with, when sevens and zeros are played. */ swap?: number; /** "Hitotsu!", called as the second-last card goes down. */ call?: boolean; } | { draw: true } | { pass: true } | { take: true } | { challenge: true } | { jump: HitotsuCard; seat: number; colour?: HitotsuColour; swap?: numbe…

One move: a card played, a draw, a turn passed, a pending draw taken, a Wild Draw Four challenged, or a card played out of turn.

function hitotsuMoves

hitotsuMoves(game: HitotsuGame): HitotsuMove[]

Every move the player to move may make now; none once the game is over. Cards played out of turn are hitotsuJumpIns.

type HitotsuNews

type HitotsuNews = | { kind: "caught"; seat: number } | { kind: "took"; seat: number; count: number } | { kind: "challenge"; seat: number; by: number; guilty: boolean } | { kind: "swap"; seat: number; with: number } | { kind: "rotate"; direction: 1 | -1 } | { kind: "jump"; seat: number } | { kind: "skipped"; seat: number } | { kind: "reversed" } | { kind: "drew"; seat: number; count: number };

Something that happened in the last move, for the table to say: nothing a player could not have seen.

type HitotsuOptions

type HitotsuOptions = { /** * Stacking a draw card on a draw card, so the next player takes the total: * never (the published rule), a Draw Two on a Draw Two and a Wild Draw Four * on a Wild Draw Four, or any draw card on any (progressive draw). */ stacking: "off" | "same" | "any"; /** Jump-in: a card identical to the one on top may be played out of turn, and play goes on from whoever played it. */ jumpIn: boolean; …

How the house plays: each popular variant, as a choice at the set-up.

function hitotsuPlayable

hitotsuPlayable(game: HitotsuGame): HitotsuCard[]

The cards the player to move may play now: on a draw, what stacks; after drawing, the card drawn if it goes.

function hitotsuPoints

hitotsuPoints(card: HitotsuCard): number

What a card left in hand is worth to the player who went out.

type HitotsuResult

type HitotsuResult = { winners: number[]; points: number; blocked: boolean };

How a hand ended: who won it and what they scored, or who held least when nobody could go on.

type HitotsuShape

type HitotsuShape = | { kind: "rect"; x: number; y: number; width: number; height: number; rx: number; fill: string; stroke?: string; strokeWidth?: number; transform?: string } | { kind: "path"; d: string; fill: string } | { kind: "circle"; cx: number; cy: number; r: number; fill: string; stroke?: string; strokeWidth?: number } | { kind: "text"; x: number; y: number; text: string; fontSize: number; fontWeight?: stri…

One shape of the design. Text is centred on its x, and its y is the baseline.

function hitotsuShapeSvg

hitotsuShapeSvg(shape: HitotsuShape): string

One shape as SVG markup.

type HitotsuStrings

type HitotsuStrings = { you: string; computer: (n: number) => string; yourTurn: string; toPlay: (who: string) => string; follow: (colour: string) => string; facing: (who: string, count: number) => string; drew: (who: string) => string; challengeOpen: (who: string, by: string) => string; cards: (count: number) => string; points: (count: number) => string; draw: string; keep: string; take: (count: number) => string; c…

Every word the table says, so a host page can put its own in (strings when it mounts).

type HitotsuTableOptions

type HitotsuTableOptions = { /** Everybody at the table, seat 0 first: seat 0 is the person at this screen, the rest computers. Two to eight; four by default. */ players?: readonly string[]; /** The house rules: `HITOTSU_CLASSIC` (the default), `HITOTSU_PARTY`, or any mix. */ rules?: HitotsuOptions; /** What wins: 200 or 500 points, or 1 for a single hand (the default). */ size?: number; /** The seed the deals are s…

type HitotsuTableSetUp

type HitotsuTableSetUp = { seed: number; options: HitotsuOptions };

What a set-up sends beyond a length and the seats: the seed it was dealt from, and the house rules.

function hitotsuTop

hitotsuTop(game: HitotsuGame): HitotsuCard

function hitotsuView

hitotsuView(game: HitotsuGame, seat?: number): HitotsuView

type HitotsuView

type HitotsuView = { seat: number; hand: readonly HitotsuCard[]; counts: readonly number[]; colour: HitotsuColour; /** The seat that plays after this one, as things stand. */ next: number; drawn: HitotsuCard | null; /** A Wild Draw Four this seat may challenge: who played it. Nothing of whether it was a bluff. */ challengeFrom: number | null; legal: readonly HitotsuMove[]; };

A COMPUTER AT THE HITOTSU TABLE. It sees its own hand, the pile, the colour to follow, what it faces, and how many cards each player holds — never another hand, and never whether a Wild Draw Four it faces was a bluff.

- Facing a draw, it stacks if it can (a Draw Two before a Wild Draw Four), and otherwise takes it — or challenges a Wild Draw Four played by a hand big enough that it most likely held the colour. - On its turn it plays an ordinary card when it has one: an action card at the player next to go out, else the card that keeps it in the colour it holds most of and sheds the most points. Wilds are saved for when nothing else goes, and a Wild Draw Four for last, and it never bluffs one. - A seven swaps with the smallest hand; a colour called is the one it holds most of. It always calls "Hitotsu!", and jumps in whenever it can. - With nothing to play it draws, and plays the card drawn if it goes and is not a wild (which it keeps).

function hitotsuWinners

hitotsuWinners(game: HitotsuGame): number[]

Once the game is over: whoever went out in a game of one hand; otherwise the highest score, level on it sharing the win.

function hitotsuWords

hitotsuWords(card: HitotsuCard): string

"red five", "blue draw two", "wild draw four", as a sentence and a screen reader say it.

function identical

identical(a: HitotsuCard, b: HitotsuCard): boolean

Whether two cards are the same card to play (the two red fives are).

function isDrawCard

isDrawCard(card: HitotsuCard): boolean

Whether a card makes somebody draw: a Draw Two or a Wild Draw Four.

function isHitotsuCard

isHitotsuCard(value: unknown): value is HitotsuCard

function isNumber

isNumber(card: HitotsuCard): boolean

Whether a card is a number, 0 to 9.

function isWild

isWild(card: HitotsuCard): boolean

function longestColour

longestColour(hand: readonly HitotsuCard[]): HitotsuColour

The colour this hand holds most of, red first among equals so the choice is always the same.

function mixSeed

mixSeed(seed: number, salt: number): number

Two numbers mixed into one seed, so each hand of a game is shuffled from its own.

function mountHitotsu

mountHitotsu(target: HTMLElement, options?: HitotsuTableOptions): HitotsuHandle

Put a table of Hitotsu into an element: the person at this screen in seat 0, computers in the rest. Tap a card that glows to play it (a wild asks for a colour, a seven under sevens-and-zeros for a hand to swap with), tap the stock to draw, and call Hitotsu! before the second-last card goes down.

function movesFor

movesFor(game: HitotsuGame, seat: number): HitotsuMove[]

Everything this seat may do now: its own turn's moves, or, at another's turn, the cards it may jump in with.

function namedTable

namedTable(game: HitotsuGame, names: readonly (string | undefined)[]): HitotsuGame

The game with its seats' names written in, a seat with no name keeping the one it had.

function playableFor

playableFor(game: HitotsuGame, seat: number): HitotsuCard[]

The cards this seat may play now, in turn or jumping in.

function playHitotsu

playHitotsu(game: HitotsuGame, move: HitotsuMove): HitotsuGame | null

function quickMove

quickMove(game: HitotsuGame, seat: number, card: HitotsuCard, call: boolean): HitotsuMove | null

What a card tapped twice plays: its one way, or null where there is a colour or a seat to choose.

type Random

type Random = () => number;

A source of numbers in [0, 1): Math.random, or a seeded one so a deal can be made again.

function readHitotsuMove

readHitotsuMove(value: unknown): HitotsuMove | null

A move as something sent it, checked for its shape only: whether it may be made is the rules'.

function readHitotsuOptions

readHitotsuOptions(value: unknown): HitotsuOptions | null

House rules as something sent them, checked for shape, or null.

function readTableMove

readTableMove(sent: unknown): HitotsuMove | null

A move as a device sent it, checked for its shape, or null; a jump is never a move at a table on several devices.

function readTableSetUp

readTableSetUp(sent: unknown): HitotsuTableSetUp | null

The set-up as a device sent it, checked for its shape, jumping in taken off, or null.

function reshuffledHitotsu

reshuffledHitotsu(cards: readonly HitotsuCard[], seed: number, salt: number): HitotsuCard[]

These cards shuffled again, the same way for the same seed and salt: a pile turned over to make a new stock.

const REVERSE

REVERSE: "R"

const SEED_MOST

SEED_MOST: number

The largest seed a deal takes: a whole number that travels in an address or a request as it is.

function seededRandom

seededRandom(seed: number): Random

A seeded generator (mulberry32): the same seed gives the same numbers, on every machine.

function shuffled

shuffled<T>(items: readonly T[], random: Random): T[]

A shuffled copy (Fisher–Yates); the list given is left as it was.

function shuffledHitotsu

shuffledHitotsu(seed: number, hand: number): HitotsuCard[]

The deck shuffled for one hand of one game: the same seed and hand always the same order.

const SKIP

SKIP: "S"

HITOTSU'S DECK, as the rules see it: 108 short names. Each colour has one zero, two of each number one to nine, and two each of Skip, Reverse and Draw Two; then four Wilds and four Wild Draw Fours.

A name is its colour letter, its face and its copy (R50, R51), so a hand of two red fives holds two different names and a rule can take one of them away without the other.

function sortHitotsu

sortHitotsu(hand: readonly HitotsuCard[]): HitotsuCard[]

A hand as a player holds it: by colour, numbers then actions, the wilds last.

function startHitotsu

startHitotsu(size: number, players: readonly string[], seed?: number, options?: HitotsuOptions, computers?: readonly boolean[]): HitotsuGame | null

function startTable

startTable(size: number, count: number, sent: unknown, computers?: readonly number[]): HitotsuGame | null

A new table: count seats with blank names (a table's names are its seats', written in when it is shown), the seats in computers played by the computer player. Null for a set-up that does not read, or a table the rules will not start.

function tableComputerMove

tableComputerMove(game: HitotsuGame, seat: number): HitotsuMove | null

The computer player's move for this seat, or null when the table is not waiting on it.

function tableToPlay

tableToPlay(game: HitotsuGame): number | null

The seat the table waits on, or null once the game is over.

function waysFor

waysFor(game: HitotsuGame, seat: number, card: HitotsuCard, call: boolean): HitotsuCardMove[]

The ways this card may go down, the call made or not as the player said (where that is a choice).

const WILD

WILD: "W"

const WILD_FOUR

WILD_FOUR: "F"

@johnmorrisdotca/hitotsu/react

HitotsuCardDrawing HitotsuCardImage HitotsuTable HitotsuTableProps

function HitotsuCardDrawing

HitotsuCardDrawing({ card, called }: { card: HitotsuCard | null; called?: HitotsuColour; }): import("/home/runner/work/hitotsu/hitotsu/node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/index").JSX.Element

One card's drawing, to go inside any SVG whose box is 100 by 140: a face, or the back for null. called marks a wild on the pile with the colour it called. The design is hitotsuCardShapes, so this and hitotsuCardSvg always agree.

function HitotsuCardImage

HitotsuCardImage({ card, called, ...svg }: { card: HitotsuCard | null; called?: HitotsuColour; } & SVGAttributes<SVGSVGElement>): import("/home/runner/work/hitotsu/hitotsu/node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/index").JSX.Element

A card as a whole SVG, sized by its parent or its own width: <HitotsuCardImage card="R70" width={80} />.

function HitotsuTable

HitotsuTable(props: HitotsuTableProps): import("/home/runner/work/hitotsu/hitotsu/node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/index").JSX.Element

A whole table, you against computers, as a React component: <HitotsuTable rules={HITOTSU_PARTY} players={["You", "Aki", "Ben"]} />.

A thin wrapper. The table is plain DOM (mountHitotsu), mounted into this component's own element once the browser has it and taken back on unmount, so it renders nothing on the server and needs no provider. Options are read when it mounts; give it a new key to deal again with different ones.

type HitotsuTableProps

type HitotsuTableProps = HitotsuTableOptions & { onReady?: (table: HitotsuHandle) => void } & Omit<HTMLAttributes<HTMLDivElement>, keyof HitotsuTableOptions>;