Gunjin軍人

@johnmorrisdotca/gunjin 0.1.2 · 10 entry points · 67 exports

@johnmorrisdotca/gunjin

boardFeatures Coordinate decodePublicReplay drawGunjinBoard DrawOptions encodePublicReplay GameMode GUNJIN_STYLE GunjinMount Language legalMovesForCurrentPlayer MatchResult Material modeName mountGunjin MountOptions MoveAction PieceStyle Player playerName PlayerView publicPosition PublicPosition publicReplay PublicReplay roleName STRINGS ViewedPiece viewForPlayer words

function boardFeatures

boardFeatures(mode: AuthoritativeMatch["mode"], width: number, height: number): { camps: Coordinate[]; headquarters: Coordinate[]; }

Public board markings, with no role-dependent information.

type Coordinate

type Coordinate = { x: number; y: number };

Zero-based board location shared by engine actions and public views.

function decodePublicReplay

decodePublicReplay(code: string): PublicReplay | null

Validates a role-free replay record for display; it cannot resume a match.

function drawGunjinBoard

drawGunjinBoard(view: PlayerView, options?: DrawOptions): string

Draws only a redacted player view. Enemy identities never enter this renderer.

type DrawOptions

type DrawOptions = { language?: Language; material?: Material; pieceStyle?: PieceStyle; selected?: Coordinate | null; targets?: readonly Coordinate[]; draft?: readonly SetupPiece[]; };

Visual settings and temporary selection marks for the role-redacted SVG renderer.

function encodePublicReplay

encodePublicReplay(match: AuthoritativeMatch): string

Serializes the role-free public replay record as JSON.

type GameMode

type GameMode = "hidden-hasami" | "luzhanqi-mini" | "salpakan" | "stratego-lite" | "gunjin-shogi";

Selects one of the five rule modules supported by this package.

const GUNJIN_STYLE

GUNJIN_STYLE: "\n.gj-root{font:1rem/1.45 system-ui,sans-serif;color:var(--kz-ink,#202521);max-width:62rem;margin:auto}\n.gj-board{position:relative;width:min(100%,42rem);margin:1rem auto;outline:none}\n.gj-cells{position:absolute;inset:0;display:grid;grid-template-columns:repeat(var(--gj-width),1fr);grid-template-rows:repeat(var(--gj-height),1fr)}\n.gj-cell{min-width:0;min-height:0;border:0;background:transparent;cu…

Scoped presentation styles applied by the hotseat mount.

type GunjinMount

type GunjinMount = { view: () => ReturnType<typeof viewForPlayer>; replay: () => string; set: (options: MountOptions) => void; destroy: () => void; };

Public controls returned by {@link mountGunjin}; no authoritative state is exposed.

type Language

type Language = "en" | "ja";

Supported interface locales.

function legalMovesForCurrentPlayer

legalMovesForCurrentPlayer(match: AuthoritativeMatch, player: Player): { from: Coordinate; to: Coordinate; }[]

Legal move coordinates for the player whose turn it is; roles are never returned.

type MatchResult

type MatchResult = { winner: Player | null; reason: "objective-captured" | "capture-threshold" | "blocked" | "flag-won" | "flag-held" | "resigned" | "agreed-draw" | "repetition"; };

Public outcome recorded when a match ends.

type Material

type Material = "ivory" | "wood" | "slate";

Board palettes shared with the game family.

function modeName

modeName(language: Language, mode: GameMode): string

Returns the localized display name for a ruleset.

function mountGunjin

mountGunjin(host: HTMLElement, initial: AuthoritativeMatch, initialOptions?: MountOptions): GunjinMount

Mounts a hotseat player. Only redacted views and replay data leave this handle.

type MountOptions

type MountOptions = { language?: Language; material?: Material; pieceStyle?: PieceStyle; onChange?: (position: PublicPosition) => void; onFinish?: (result: { winner: Player | null; reason: string }) => void; };

Locale, materials, and safe public callbacks for a mounted hotseat player.

type MoveAction

type MoveAction = { from: Coordinate; to: Coordinate; expectedTurn: number; };

Move requests are public, deterministic and rejected if their turn is stale.

type PieceStyle

type PieceStyle = "ink" | "tiles";

Available piece silhouettes.

type Player

type Player = 0 | 1;

The player whose private side is red.

function playerName

playerName(language: Language, player: Player): string

Returns the localized name for one side.

type PlayerView

type PlayerView = { mode: GameMode; phase: MatchPhase; viewer: Player; currentPlayer: Player; width: number; height: number; pieces: readonly ViewedPiece[] | null; turn: number; setupStep: number; ownSetup: readonly Piece[] | null; publicLog: readonly PublicEvent[]; result?: MatchResult; drawOffer?: Player; };

Information safe to render for one player at the current pass boundary.

function publicPosition

publicPosition(match: AuthoritativeMatch): PublicPosition

Redacted position for spectators: only player ownership and occupied cells are returned.

type PublicPosition

type PublicPosition = { mode: GameMode; phase: MatchPhase; width: number; height: number; pieces: readonly Omit<ViewedPiece, "kind" | "id">[] | null; turn: number; result?: MatchResult; };

Role-free current position suitable for observers and change callbacks.

function publicReplay

publicReplay(match: AuthoritativeMatch): PublicReplay

Creates a public replay with only combat ranks that the selected rules expose.

type PublicReplay

type PublicReplay = { version: 1; mode: GameMode; width: number; height: number; events: readonly PublicEvent[]; result?: MatchResult; };

A shareable public record. It contains no piece roles, IDs, or setup layouts.

function roleName

roleName(language: Language, role: string): string

Returns a localized piece label, with a readable fallback for unknown roles.

const STRINGS

STRINGS: { readonly en: { readonly title: "Gunjin"; readonly pass: "Pass the device to the named player, then continue."; readonly setup: "Place every piece in your home area, then submit your side."; readonly turn: "Move one piece. Opponent ranks stay hidden."; readonly captureFlagTurn: "Choose a move. Ranks are revealed when pieces battle."; readonly battleHistory: "Recent battles"; readonly battle: "Battle"; read…

English and Japanese interface labels used by the renderer and player.

type ViewedPiece

type ViewedPiece = Coordinate & { owner: Player; kind: string | null; hidden: boolean; id?: string; };

Player-facing piece. Opponent kind is always null and opponent IDs are omitted.

function viewForPlayer

viewForPlayer(match: AuthoritativeMatch, viewer: Player): PlayerView

A player view redacts opponent roles and suppresses the board during device handoff.

function words

words(language?: Language): { readonly title: "Gunjin"; readonly pass: "Pass the device to the named player, then continue."; readonly setup: "Place every piece in your home area, then submit your side."; readonly turn: "Move one piece. Opponent ranks stay hidden."; readonly captureFlagTurn: "Choose a move. Ranks are revealed when pieces battle."; readonly battleHistory: "Recent battles"; readonly battle: "Battle"; readonly selectPiece: "Choose one of your pieces."; readonly selectTarget: "Choose a highlighted destination."; readonly invalidSetup: "That setup does not meet this mode's placeme…

Returns the localized interface string table.

@johnmorrisdotca/gunjin/hasami

createHasamiMatch hasamiRoster playHasamiMove submitHasamiSetup

function createHasamiMatch

createHasamiMatch(size?: SetupSize): ReturnType<typeof createMatch>

Makes a Hasami-inspired match with a 7×7 or 9×9 board.

function hasamiRoster

hasamiRoster(size: 7 | 9): readonly string[]

Returns the ordered private setup roster for the selected square board size.

function playHasamiMove

playHasamiMove(match: ReturnType<typeof createMatch>, player: Player, action: MoveAction): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Applies a legal move action to a Hasami match, rejecting stale turns.

function submitHasamiSetup

submitHasamiSetup(match: ReturnType<typeof createMatch>, player: Player, placements: readonly SetupPiece[], expectedSetupStep: number): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Submits one player's complete setup; the expected step rejects stale submissions.

@johnmorrisdotca/gunjin/luzhanqi-mini

createLuzhanqiMiniMatch luzhanqiMiniRoster playLuzhanqiMiniMove submitLuzhanqiMiniSetup

function createLuzhanqiMiniMatch

createLuzhanqiMiniMatch(): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Makes the fixed 7×8 streamlined land-battle training game.

function luzhanqiMiniRoster

luzhanqiMiniRoster(): readonly string[]

Returns the ordered 14-piece setup roster for one side.

function playLuzhanqiMiniMove

playLuzhanqiMiniMove(match: ReturnType<typeof createMatch>, player: Player, action: MoveAction): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Applies a legal move action, rejecting stale turn numbers.

function submitLuzhanqiMiniSetup

submitLuzhanqiMiniSetup(match: ReturnType<typeof createMatch>, player: Player, placements: readonly SetupPiece[], expectedSetupStep: number): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Submits a complete side setup and advances the hotseat setup phase.

@johnmorrisdotca/gunjin/salpakan

createSalpakanMatch playSalpakanMove salpakanRoster submitSalpakanSetup

function createSalpakanMatch

createSalpakanMatch(): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Makes the fixed classic 9×8 Salpakan match.

function playSalpakanMove

playSalpakanMove(match: ReturnType<typeof createMatch>, player: Player, action: MoveAction): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Applies a legal move action, rejecting stale turn numbers.

function salpakanRoster

salpakanRoster(): readonly string[]

Returns the ordered 21-piece setup roster for one side.

function submitSalpakanSetup

submitSalpakanSetup(match: ReturnType<typeof createMatch>, player: Player, placements: readonly SetupPiece[], expectedSetupStep: number): import("/home/runner/work/gunjin/gunjin/src/types").AuthoritativeMatch

Submits a complete side setup and advances the hotseat setup phase.

@johnmorrisdotca/gunjin/stratego-lite

acknowledgePass createMatch playMove rosterForSetup STRATEGO_LITE_RULES strategoCombat submitSetup

function acknowledgePass

acknowledgePass(match: AuthoritativeMatch, player: Player, expectedTurn: number): AuthoritativeMatch

Confirms that the device has passed to the player named on the cover screen.

function createMatch

createMatch(mode: GameMode, size?: SetupSize): AuthoritativeMatch

Creates an authoritative match. Keep this state on a trusted host.

function playMove

playMove(match: AuthoritativeMatch, player: Player, action: MoveAction): AuthoritativeMatch

Current-player moves with deterministic stale-turn rejection.

function rosterForSetup

rosterForSetup(match: AuthoritativeMatch, player: Player): readonly string[]

The private roster for the player currently arranging their side.

const STRATEGO_LITE_RULES

STRATEGO_LITE_RULES: ModeRules

Original streamlined capture-flag rules using the published Original roster and combat table.

function strategoCombat

strategoCombat(attacker: string, defender: string): "attacker" | "defender" | "both"

Resolves a Capture Flag battle without mutating either piece or match.

function submitSetup

submitSetup(match: AuthoritativeMatch, player: Player, placements: readonly SetupPiece[], expectedSetupStep: number): AuthoritativeMatch

Submits one player's hidden setup and then shows a pass-device screen.

@johnmorrisdotca/gunjin/gunjin-shogi

acknowledgePass createMatch GUNJIN_SHOGI_RULES gunjinCombat playMove rosterForSetup submitSetup

function acknowledgePass

acknowledgePass(match: AuthoritativeMatch, player: Player, expectedTurn: number): AuthoritativeMatch

Confirms that the device has passed to the player named on the cover screen.

function createMatch

createMatch(mode: GameMode, size?: SetupSize): AuthoritativeMatch

Creates an authoritative match. Keep this state on a trusted host.

const GUNJIN_SHOGI_RULES

GUNJIN_SHOGI_RULES: ModeRules

The documented 31-piece club ruleset, on a plain 9×9 board.

function gunjinCombat

gunjinCombat(attacker: string, defender: string): "attacker" | "defender" | "both"

Resolves a club-rules Gunjin Shogi battle without mutating match state. A piece that attacks a flag takes it, and wins; a flag that attacks anything else is removed with it.

function playMove

playMove(match: AuthoritativeMatch, player: Player, action: MoveAction): AuthoritativeMatch

Current-player moves with deterministic stale-turn rejection.

function rosterForSetup

rosterForSetup(match: AuthoritativeMatch, player: Player): readonly string[]

The private roster for the player currently arranging their side.

function submitSetup

submitSetup(match: AuthoritativeMatch, player: Player, placements: readonly SetupPiece[], expectedSetupStep: number): AuthoritativeMatch

Submits one player's hidden setup and then shows a pass-device screen.

@johnmorrisdotca/gunjin/trusted

decodeTrustedMatch encodeTrustedMatch

function decodeTrustedMatch

decodeTrustedMatch(code: string): AuthoritativeMatch | null

Reads trusted host storage. The caller must keep the decoded match private.

function encodeTrustedMatch

encodeTrustedMatch(match: AuthoritativeMatch): string

Host-only serialization. The returned string contains both players' secret roles; never send it to a browser, another player, or a public replay endpoint.

@johnmorrisdotca/gunjin/views

boardFeatures legalMovesForCurrentPlayer publicPosition viewForPlayer

function boardFeatures

boardFeatures(mode: AuthoritativeMatch["mode"], width: number, height: number): { camps: Coordinate[]; headquarters: Coordinate[]; }

Public board markings, with no role-dependent information.

function legalMovesForCurrentPlayer

legalMovesForCurrentPlayer(match: AuthoritativeMatch, player: Player): { from: Coordinate; to: Coordinate; }[]

Legal move coordinates for the player whose turn it is; roles are never returned.

function publicPosition

publicPosition(match: AuthoritativeMatch): PublicPosition

Redacted position for spectators: only player ownership and occupied cells are returned.

function viewForPlayer

viewForPlayer(match: AuthoritativeMatch, viewer: Player): PlayerView

A player view redacts opponent roles and suppresses the board during device handoff.

@johnmorrisdotca/gunjin/draw

drawGunjinBoard DrawOptions

function drawGunjinBoard

drawGunjinBoard(view: PlayerView, options?: DrawOptions): string

Draws only a redacted player view. Enemy identities never enter this renderer.

type DrawOptions

type DrawOptions = { language?: Language; material?: Material; pieceStyle?: PieceStyle; selected?: Coordinate | null; targets?: readonly Coordinate[]; draft?: readonly SetupPiece[]; };

Visual settings and temporary selection marks for the role-redacted SVG renderer.

@johnmorrisdotca/gunjin/play

GunjinMount mountGunjin MountOptions

type GunjinMount

type GunjinMount = { view: () => ReturnType<typeof viewForPlayer>; replay: () => string; set: (options: MountOptions) => void; destroy: () => void; };

Public controls returned by {@link mountGunjin}; no authoritative state is exposed.

function mountGunjin

mountGunjin(host: HTMLElement, initial: AuthoritativeMatch, initialOptions?: MountOptions): GunjinMount

Mounts a hotseat player. Only redacted views and replay data leave this handle.

type MountOptions

type MountOptions = { language?: Language; material?: Material; pieceStyle?: PieceStyle; onChange?: (position: PublicPosition) => void; onFinish?: (result: { winner: Player | null; reason: string }) => void; };

Locale, materials, and safe public callbacks for a mounted hotseat player.