@alpaca-software/40kdc-data 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/bundle-schemas.d.ts.map +1 -1
- package/dist/bundle-schemas.js +17 -0
- package/dist/bundle-schemas.js.map +1 -1
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -1
- package/dist/codegen-data.js +2 -1
- package/dist/codegen-data.js.map +1 -1
- package/dist/commands/populate-base-sizes.d.ts +2 -0
- package/dist/commands/populate-base-sizes.d.ts.map +1 -0
- package/dist/commands/populate-base-sizes.js +158 -0
- package/dist/commands/populate-base-sizes.js.map +1 -0
- package/dist/convert-faction.d.ts +3 -1
- package/dist/convert-faction.d.ts.map +1 -1
- package/dist/convert-faction.js +49 -16
- package/dist/convert-faction.js.map +1 -1
- package/dist/converters/base-size-bridge.d.ts +122 -0
- package/dist/converters/base-size-bridge.d.ts.map +1 -0
- package/dist/converters/base-size-bridge.js +198 -0
- package/dist/converters/base-size-bridge.js.map +1 -0
- package/dist/converters/base-size-guide-extract.d.ts +11 -0
- package/dist/converters/base-size-guide-extract.d.ts.map +1 -0
- package/dist/converters/base-size-guide-extract.js +59 -0
- package/dist/converters/base-size-guide-extract.js.map +1 -0
- package/dist/converters/option-bridge.d.ts +36 -0
- package/dist/converters/option-bridge.d.ts.map +1 -0
- package/dist/converters/option-bridge.js +72 -0
- package/dist/converters/option-bridge.js.map +1 -0
- package/dist/converters/option-parser.d.ts +56 -0
- package/dist/converters/option-parser.d.ts.map +1 -0
- package/dist/converters/option-parser.js +209 -0
- package/dist/converters/option-parser.js.map +1 -0
- package/dist/converters/wargear-options.d.ts +55 -0
- package/dist/converters/wargear-options.d.ts.map +1 -0
- package/dist/converters/wargear-options.js +187 -0
- package/dist/converters/wargear-options.js.map +1 -0
- package/dist/data/bundle.generated.js +1 -1
- package/dist/data/bundle.generated.js.map +1 -1
- package/dist/data/dataset.d.ts +10 -2
- package/dist/data/dataset.d.ts.map +1 -1
- package/dist/data/dataset.js +16 -2
- package/dist/data/dataset.js.map +1 -1
- package/dist/data/entities.d.ts +3 -1
- package/dist/data/entities.d.ts.map +1 -1
- package/dist/data/entities.js +4 -0
- package/dist/data/entities.js.map +1 -1
- package/dist/data/index.d.ts +5 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +5 -1
- package/dist/data/index.js.map +1 -1
- package/dist/data/loadout.d.ts +60 -0
- package/dist/data/loadout.d.ts.map +1 -0
- package/dist/data/loadout.js +135 -0
- package/dist/data/loadout.js.map +1 -0
- package/dist/data/types.d.ts +4 -2
- package/dist/data/types.d.ts.map +1 -1
- package/dist/data/types.js +2 -1
- package/dist/data/types.js.map +1 -1
- package/dist/export/rosterizer.js +1 -1
- package/dist/export/rosterizer.js.map +1 -1
- package/dist/gen-conformance.js +25 -2
- package/dist/gen-conformance.js.map +1 -1
- package/dist/generated.d.ts +112 -55
- package/dist/generated.d.ts.map +1 -1
- package/dist/generated.js.map +1 -1
- package/dist/import/rosterizer.d.ts +1 -1
- package/dist/import/rosterizer.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/runner.d.ts +16 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +55 -1
- package/dist/runner.js.map +1 -1
- package/dist/scoring/index.d.ts +135 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +195 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/translate/condition.d.ts.map +1 -1
- package/dist/translate/condition.js +4 -0
- package/dist/translate/condition.js.map +1 -1
- package/dist/translate/index.d.ts +1 -1
- package/dist/translate/index.d.ts.map +1 -1
- package/dist/translate/index.js.map +1 -1
- package/dist/translate/scoring.d.ts +6 -0
- package/dist/translate/scoring.d.ts.map +1 -1
- package/dist/translate/scoring.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +13 -5
- package/dist/validate.js.map +1 -1
- package/package.json +4 -4
- package/schemas/$defs/common.schema.json +14 -0
- package/schemas/core/secondary-card.schema.json +10 -0
- package/schemas/core/unit-composition.schema.json +5 -1
- package/schemas/core/unit.schema.json +2 -10
- package/schemas/core/wargear-option.schema.json +32 -6
- package/schemas/core/wargear.schema.json +24 -0
- package/schemas/enrichment/ability-dsl/condition.schema.json +3 -2
package/dist/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * NDJSON conformance runner — the TypeScript implementation of the wire\n * protocol in `conformance/RUNNER_PROTOCOL.md`. Each line on stdin is a JSON\n * request `{op, args?}`; each line on stdout is a JSON response\n * `{ok: true, value}` or `{ok: false, error_kind, error_payload?}`.\n *\n * This file exports {@link processRequest} so vitest can drive the runner\n * in-process without spawning a child; the bottom `if (isCliMain())` block\n * wires the same dispatcher to real stdin/stdout for the cross-impl differ.\n *\n * The runner is a *thin* wrapper over the existing public API — it is not the\n * canonical way to use the package. Library consumers should import the\n * functions directly; the runner exists to give the cross-implementation\n * differ a uniform interface across language ports.\n */\nimport { createInterface } from \"node:readline\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport process from \"node:process\";\n\nimport { Dataset } from \"./data/dataset.js\";\nimport { normalizeName } from \"./data/normalize.js\";\nimport { exportRoster, type ExportFormat } from \"./export/index.js\";\nimport { importRoster, tryImportRoster, REGISTERED_ADAPTERS } from \"./import/import-roster.js\";\nimport { selectAdapter } from \"./import/adapter.js\";\nimport { createValidator } from \"./schema-loader.js\";\nimport { attributeStages, crunch, type Buff, type EngineContext, type EngineInput } from \"./cruncher/index.js\";\nimport { describeScoringCard } from \"./translate/index.js\";\nimport { resolveLayout, TerrainResolveError } from \"./terrain/index.js\";\nimport type { TerrainTemplate, TerrainLayout } from \"./terrain/resolve.js\";\nimport type Ajv from \"ajv\";\n\n// -----------------------------------------------------------------------------\n// Constants — spec version and implementation identity.\n// -----------------------------------------------------------------------------\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction loadSpecVersion(): number {\n // The corpus lives at repo-root/conformance/. Walk up from tools/src/ until\n // we find it so the runner works both from source (tsx) and from dist/.\n for (const candidate of [\n join(__dirname, \"../../conformance/SPEC_VERSION\"),\n join(__dirname, \"../../../conformance/SPEC_VERSION\"),\n ]) {\n try {\n return Number.parseInt(readFileSync(candidate, \"utf8\").trim(), 10);\n } catch {\n // try next\n }\n }\n throw new Error(\"could not locate conformance/SPEC_VERSION\");\n}\n\nfunction loadImplVersion(): string {\n for (const candidate of [\n join(__dirname, \"../package.json\"),\n join(__dirname, \"../../package.json\"),\n ]) {\n try {\n return (JSON.parse(readFileSync(candidate, \"utf8\")) as { version: string }).version;\n } catch {\n // try next\n }\n }\n return \"unknown\";\n}\n\nconst SPEC_VERSION = loadSpecVersion();\nconst IMPL_VERSION = loadImplVersion();\nconst IMPL_NAME = \"ts\";\n\n// -----------------------------------------------------------------------------\n// Error envelope helpers and the closed `error_kind` enum.\n// -----------------------------------------------------------------------------\n\nexport type RunnerResponse =\n | { ok: true; value: unknown }\n | { ok: false; error_kind: ErrorKind; error_payload?: unknown };\n\nconst ERROR_KINDS = [\n \"INVALID_INPUT\",\n \"UNKNOWN_OP\",\n \"UNKNOWN_ENTITY\",\n \"IMPORT_FAILED\",\n \"EXPORT_FAILED\",\n \"VALIDATION_ERROR\",\n \"CRUNCH_ERROR\",\n \"INTERNAL_ERROR\",\n] as const;\ntype ErrorKind = (typeof ERROR_KINDS)[number];\n\nfunction ok(value: unknown): RunnerResponse {\n return { ok: true, value };\n}\nfunction err(kind: ErrorKind, payload?: unknown): RunnerResponse {\n return payload === undefined\n ? { ok: false, error_kind: kind }\n : { ok: false, error_kind: kind, error_payload: payload };\n}\n\n// -----------------------------------------------------------------------------\n// Runner state — init must be the first request; subsequent ops fail with\n// INVALID_INPUT until init succeeds. Dataset and validator are lazy.\n// -----------------------------------------------------------------------------\n\nexport interface RunnerState {\n initialized: boolean;\n locale: string;\n tz: string;\n seed: number;\n dataset?: Dataset;\n validator?: Ajv;\n}\n\nexport function createRunnerState(): RunnerState {\n return { initialized: false, locale: \"C\", tz: \"UTC\", seed: 0 };\n}\n\nfunction getDataset(state: RunnerState): Dataset {\n if (!state.dataset) state.dataset = Dataset.embedded();\n return state.dataset;\n}\n\nfunction getValidator(state: RunnerState): Ajv {\n if (!state.validator) state.validator = createValidator();\n return state.validator;\n}\n\n// -----------------------------------------------------------------------------\n// Op handlers.\n// -----------------------------------------------------------------------------\n\nfunction handleInit(state: RunnerState, args: unknown): RunnerResponse {\n if (state.initialized) {\n return err(\"INVALID_INPUT\", { detail: \"init called twice\" });\n }\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"init args must be an object\" });\n }\n const a = args as { spec_version?: unknown; locale?: unknown; tz?: unknown; seed?: unknown };\n if (a.spec_version !== SPEC_VERSION) {\n return err(\"INVALID_INPUT\", {\n detail: `spec_version mismatch: runner=${SPEC_VERSION}, request=${String(a.spec_version)}`,\n });\n }\n if (a.locale !== \"C\") {\n return err(\"INVALID_INPUT\", { detail: `unsupported locale: ${String(a.locale)} (only \"C\")` });\n }\n if (a.tz !== \"UTC\") {\n return err(\"INVALID_INPUT\", { detail: `unsupported tz: ${String(a.tz)} (only \"UTC\")` });\n }\n if (typeof a.seed !== \"number\") {\n return err(\"INVALID_INPUT\", { detail: \"seed must be a number\" });\n }\n state.initialized = true;\n state.locale = a.locale;\n state.tz = a.tz;\n state.seed = a.seed;\n return ok({ impl: IMPL_NAME, spec_version: SPEC_VERSION, impl_version: IMPL_VERSION });\n}\n\nfunction handleNormalize(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"normalize args must be an object\" });\n }\n const a = args as { input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"normalize.input must be a string\" });\n }\n return ok(normalizeName(a.input));\n}\n\nfunction handleImport(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"import args must be an object\" });\n }\n const a = args as { format?: unknown; input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"import.input must be a string\" });\n }\n try {\n // The wire protocol carries every input as a string: JSON payloads come\n // through as the JSON text, text payloads come through as-is. The import\n // pipeline decides which by attempting to parse JSON first.\n const trimmed = a.input.trimStart();\n let decoded: unknown;\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n decoded = JSON.parse(a.input);\n } catch {\n decoded = a.input;\n }\n } else {\n decoded = a.input;\n }\n const roster = importRoster(decoded, { dataset: getDataset(state) });\n return ok(roster);\n } catch (e) {\n return err(\"IMPORT_FAILED\", { detail: (e as Error).message, format: a.format ?? null });\n }\n}\n\nfunction handleTryImport(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"try_import args must be an object\" });\n }\n const a = args as { input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"try_import.input must be a string\" });\n }\n const result = tryImportRoster(a.input, { dataset: getDataset(state) });\n if (!result.ok) {\n return err(\"IMPORT_FAILED\", { reason: result.reason, message: result.message });\n }\n return ok({ format: result.format, roster: result.roster });\n}\n\nconst EXPORT_FORMATS: ExportFormat[] = [\n \"newrecruit-json\",\n \"newrecruit-wtc-compact\",\n \"newrecruit-wtc-full\",\n \"newrecruit-simple\",\n \"roster-json\",\n \"rosterizer\",\n];\n\nfunction handleExport(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"export args must be an object\" });\n }\n const a = args as { format?: unknown; roster?: unknown };\n if (typeof a.format !== \"string\" || !EXPORT_FORMATS.includes(a.format as ExportFormat)) {\n return err(\"INVALID_INPUT\", { detail: `unknown export format: ${String(a.format)}` });\n }\n if (typeof a.roster !== \"object\" || a.roster === null) {\n return err(\"INVALID_INPUT\", { detail: \"export.roster must be an object\" });\n }\n try {\n // We assume the caller passes the canonical resolved Roster shape; if they\n // pass something the serializer can't handle, this throws.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ok(exportRoster(a.roster as any, a.format as ExportFormat));\n } catch (e) {\n return err(\"EXPORT_FAILED\", { detail: (e as Error).message });\n }\n}\n\nfunction handleLinkedQuery(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"linked_query args must be an object\" });\n }\n const a = args as { query?: unknown; input?: unknown };\n if (typeof a.query !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"linked_query.query must be a string\" });\n }\n const ds = getDataset(state);\n const input = (a.input ?? {}) as Record<string, string>;\n try {\n switch (a.query) {\n case \"find_unit\":\n return ok(ds.units.find(input.query ?? \"\")?.id ?? null);\n case \"find_weapon\":\n return ok(ds.weapons.find(input.query ?? \"\")?.id ?? null);\n case \"find_faction\":\n return ok(ds.factions.find(input.query ?? \"\")?.id ?? null);\n case \"find_ability\":\n return ok(ds.abilities.find(input.query ?? \"\")?.id ?? null);\n case \"abilities_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.abilities.map((x) => x.id));\n }\n case \"weapons_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.weapons.map((x) => x.id));\n }\n case \"phases_of\": {\n const ab = ds.abilities.get(input.abilityId);\n if (!ab) return err(\"UNKNOWN_ENTITY\", { kind: \"ability\", id: input.abilityId });\n return ok([...ab.phases]);\n }\n case \"faction_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.faction?.id ?? null);\n }\n case \"abilities_of_faction\":\n return ok(ds.abilities.byFaction(input.factionId).map((x) => x.id));\n case \"weapons_of_faction\": {\n const f = ds.factions.get(input.factionId);\n if (!f) return err(\"UNKNOWN_ENTITY\", { kind: \"faction\", id: input.factionId });\n return ok(f.weapons.map((x) => x.id));\n }\n default:\n return err(\"INVALID_INPUT\", { detail: `unknown linked_query: ${a.query}` });\n }\n } catch (e) {\n return err(\"INTERNAL_ERROR\", { detail: (e as Error).message });\n }\n}\n\nconst VALIDATOR_TARGETS: Record<string, string> = {\n unit: \"https://40kdc.dev/schemas/core/unit.schema.json\",\n weapon: \"https://40kdc.dev/schemas/core/weapon.schema.json\",\n faction: \"https://40kdc.dev/schemas/core/faction.schema.json\",\n ability: \"https://40kdc.dev/schemas/enrichment/ability-dsl/ability.schema.json\",\n};\n\nfunction ajvKeywordToCode(keyword: string): string {\n switch (keyword) {\n case \"required\":\n return \"REQUIRED_MISSING\";\n case \"type\":\n return \"TYPE_MISMATCH\";\n case \"enum\":\n return \"ENUM_VIOLATION\";\n case \"pattern\":\n case \"format\":\n return \"PATTERN_MISMATCH\";\n case \"minimum\":\n case \"maximum\":\n case \"exclusiveMinimum\":\n case \"exclusiveMaximum\":\n case \"minLength\":\n case \"maxLength\":\n case \"minItems\":\n case \"maxItems\":\n return \"RANGE_VIOLATION\";\n case \"additionalProperties\":\n return \"ADDITIONAL_PROPERTY\";\n case \"uniqueItems\":\n return \"UNIQUE_VIOLATION\";\n default:\n return `UNMAPPED:${keyword}`;\n }\n}\n\nfunction handleValidate(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"validate args must be an object\" });\n }\n const a = args as { target?: unknown; value?: unknown };\n if (typeof a.target !== \"string\" || !(a.target in VALIDATOR_TARGETS)) {\n return err(\"INVALID_INPUT\", { detail: `unknown validator target: ${String(a.target)}` });\n }\n let validate;\n try {\n validate = getValidator(state).getSchema(VALIDATOR_TARGETS[a.target]);\n } catch (e) {\n return err(\"VALIDATION_ERROR\", { detail: (e as Error).message });\n }\n if (!validate) {\n return err(\"VALIDATION_ERROR\", { detail: `schema not loaded: ${a.target}` });\n }\n validate(a.value);\n const raw = validate.errors ?? [];\n const seen = new Set<string>();\n const out: { path: string; code: string }[] = [];\n for (const e of raw) {\n const code = ajvKeywordToCode(e.keyword);\n if (code.startsWith(\"UNMAPPED:\")) continue;\n const path =\n e.keyword === \"required\"\n ? `${e.instancePath}/${(e.params as { missingProperty?: string }).missingProperty ?? \"\"}`\n : e.instancePath;\n const key = `${path}|${code}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({ path, code });\n }\n return ok(out);\n}\n\ninterface CrunchArgs {\n attacker?: { weaponId?: string; profileIndex?: number };\n modelsFiring?: number;\n target?: { unitId?: string; profileIndex?: number; modelCount?: number };\n context?: EngineContext;\n buffs?: Buff[];\n}\n\n/**\n * Validate the wire-shape `crunch`/`attribution` args and assemble the\n * {@link EngineInput} both ops share, or return a typed runner error. The two\n * ops have identical inputs — separating this lets each handler stay tiny and\n * keeps the validation contract in one place.\n */\nfunction buildEngineInput(\n state: RunnerState,\n a: CrunchArgs,\n opName: string,\n): { ok: true; input: EngineInput } | { ok: false; response: RunnerResponse } {\n if (!a.attacker?.weaponId || typeof a.attacker.profileIndex !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.attacker.weaponId/profileIndex required` }) };\n }\n if (!a.target?.unitId || typeof a.target.profileIndex !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.target.unitId/profileIndex required` }) };\n }\n if (typeof a.modelsFiring !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.modelsFiring required` }) };\n }\n if (!a.context) {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.context required` }) };\n }\n const ds = getDataset(state);\n const weapon = ds.weapons.get(a.attacker.weaponId);\n if (!weapon) return { ok: false, response: err(\"UNKNOWN_ENTITY\", { kind: \"weapon\", id: a.attacker.weaponId }) };\n const unit = ds.units.get(a.target.unitId);\n if (!unit) return { ok: false, response: err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: a.target.unitId }) };\n const input: EngineInput = {\n attacker: { weapon: weapon.raw, profileIndex: a.attacker.profileIndex },\n target: {\n unit: unit.raw,\n profileIndex: a.target.profileIndex,\n ...(a.target.modelCount !== undefined ? { modelCount: a.target.modelCount } : {}),\n },\n modelsFiring: a.modelsFiring,\n buffs: a.buffs ?? [],\n context: a.context,\n };\n return { ok: true, input };\n}\n\nfunction handleCrunch(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"crunch args must be an object\" });\n }\n const built = buildEngineInput(state, args as CrunchArgs, \"crunch\");\n if (!built.ok) return built.response;\n try {\n // Canonical wire shape: stages array only. `resolved` is impl-internal\n // (TS/Rust shape diverges); per-stage `detail` strings aren't byte-equal\n // across impls. The differ compares per-stage `expected` with 5e-4\n // tolerance — that's the cross-impl contract.\n const out = crunch(built.input, getDataset(state));\n return ok({ stages: out.stages.map((s) => ({ name: s.name, expected: s.expected })) });\n } catch (e) {\n return err(\"CRUNCH_ERROR\", { detail: (e as Error).message });\n }\n}\n\nfunction handleAttribution(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"attribution args must be an object\" });\n }\n const a = args as CrunchArgs & { epsilon?: number };\n const built = buildEngineInput(state, a, \"attribution\");\n if (!built.ok) return built.response;\n try {\n const opts = typeof a.epsilon === \"number\" ? { epsilon: a.epsilon } : undefined;\n // Drop `detail` from the wire (impl-specific formatting). Keep all\n // numeric fields and the kind-tagged BuffSource shape that's already\n // serde-compatible.\n const stages = attributeStages(built.input, getDataset(state), opts);\n return ok(\n stages.map((s) => ({\n name: s.name,\n expected: s.expected,\n baseline: s.baseline,\n lifts: s.lifts,\n residual: s.residual,\n intrinsics: s.intrinsics,\n })),\n );\n } catch (e) {\n return err(\"CRUNCH_ERROR\", { detail: (e as Error).message });\n }\n}\n\nfunction handleTranslateScoring(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"translate_scoring args must be an object\" });\n }\n const a = args as { cardId?: unknown };\n if (typeof a.cardId !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"translate_scoring.cardId must be a string\" });\n }\n const card = getDataset(state).secondaryCards.get(a.cardId);\n if (!card) return err(\"UNKNOWN_ENTITY\", { kind: \"secondary-card\", id: a.cardId });\n return ok({ awards: describeScoringCard(card) });\n}\n\nfunction handleResolveTerrain(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain args must be an object\" });\n }\n const a = args as { layout?: unknown; templates?: unknown };\n if (typeof a.layout !== \"object\" || a.layout === null) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain.layout must be an object\" });\n }\n const templates = a.templates ?? [];\n if (!Array.isArray(templates)) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain.templates must be an array\" });\n }\n try {\n const pieces = resolveLayout(a.layout as TerrainLayout, templates as TerrainTemplate[]);\n return ok({ pieces });\n } catch (e) {\n if (e instanceof TerrainResolveError) {\n return err(\"INVALID_INPUT\", { detail: e.message });\n }\n return err(\"INTERNAL_ERROR\", { detail: (e as Error).message });\n }\n}\n\n// -----------------------------------------------------------------------------\n// Dispatcher and per-line entry point.\n// -----------------------------------------------------------------------------\n\n/**\n * Apply one decoded request to the runner state and return the response. Used\n * directly by tests; the CLI loop wraps it with line parsing.\n */\nexport function dispatch(state: RunnerState, req: { op: string; args?: unknown }): RunnerResponse {\n if (!state.initialized && req.op !== \"init\") {\n return err(\"INVALID_INPUT\", { detail: \"must init before any other op\" });\n }\n switch (req.op) {\n case \"init\":\n return handleInit(state, req.args);\n case \"version\":\n return ok({ impl: IMPL_NAME, spec_version: SPEC_VERSION, impl_version: IMPL_VERSION });\n case \"normalize\":\n return handleNormalize(req.args);\n case \"import\":\n return handleImport(state, req.args);\n case \"try_import\":\n return handleTryImport(state, req.args);\n case \"export\":\n return handleExport(req.args);\n case \"linked_query\":\n return handleLinkedQuery(state, req.args);\n case \"validate\":\n return handleValidate(state, req.args);\n case \"crunch\":\n return handleCrunch(state, req.args);\n case \"attribution\":\n return handleAttribution(state, req.args);\n case \"translate_scoring\":\n return handleTranslateScoring(state, req.args);\n case \"resolve_terrain\":\n return handleResolveTerrain(req.args);\n case \"shutdown\":\n return ok(null);\n default:\n return err(\"UNKNOWN_OP\", { op: req.op });\n }\n}\n\n/**\n * Process one line of stdin (one NDJSON request) and return the line that\n * should be written to stdout (one NDJSON response). Returns `null` only on\n * fully-empty input lines, which should be silently ignored.\n */\nexport function processRequest(state: RunnerState, line: string): string | null {\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n let req: { op?: unknown; args?: unknown };\n try {\n req = JSON.parse(trimmed);\n } catch (e) {\n return JSON.stringify(err(\"INVALID_INPUT\", { detail: `not valid JSON: ${(e as Error).message}` }));\n }\n if (typeof req.op !== \"string\") {\n return JSON.stringify(err(\"INVALID_INPUT\", { detail: \"request must have a string `op` field\" }));\n }\n const response = dispatch(state, { op: req.op, args: req.args });\n return JSON.stringify(response);\n}\n\n// -----------------------------------------------------------------------------\n// CLI: wire stdin/stdout. Only runs when this file is the process entry point.\n// -----------------------------------------------------------------------------\n\nfunction isCliMain(): boolean {\n // process.argv[1] is the path the runtime invoked. With tsx and node both,\n // it points at this file (or its compiled .js form). Comparing absolute\n // paths is the most robust portable check.\n if (!process.argv[1]) return false;\n const entry = process.argv[1];\n const here = fileURLToPath(import.meta.url);\n return entry === here || entry.endsWith(\"/runner.js\") || entry.endsWith(\"/runner.ts\");\n}\n\nasync function runCli(): Promise<void> {\n const state = createRunnerState();\n const rl = createInterface({ input: process.stdin });\n // We must respond on the same tick the request arrives — the differ\n // pipelines requests and expects responses in order. readline preserves\n // line ordering, so processing inside `line` handler is sufficient.\n for await (const line of rl) {\n const out = processRequest(state, line);\n if (out !== null) {\n process.stdout.write(out + \"\\n\");\n }\n // `shutdown` returns `ok(null)`; honor it by exiting after the response\n // is flushed.\n try {\n const req = JSON.parse(line);\n if (req && req.op === \"shutdown\") {\n process.exit(0);\n }\n } catch {\n // already handled above; not a shutdown\n }\n }\n}\n\nif (isCliMain()) {\n runCli().catch((e) => {\n // Last-ditch INTERNAL_ERROR so the differ sees a typed failure rather\n // than an opaque crash.\n process.stdout.write(\n JSON.stringify({\n ok: false,\n error_kind: \"INTERNAL_ERROR\",\n error_payload: { detail: (e as Error).message },\n }) + \"\\n\",\n );\n process.exit(1);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * NDJSON conformance runner — the TypeScript implementation of the wire\n * protocol in `conformance/RUNNER_PROTOCOL.md`. Each line on stdin is a JSON\n * request `{op, args?}`; each line on stdout is a JSON response\n * `{ok: true, value}` or `{ok: false, error_kind, error_payload?}`.\n *\n * This file exports {@link processRequest} so vitest can drive the runner\n * in-process without spawning a child; the bottom `if (isCliMain())` block\n * wires the same dispatcher to real stdin/stdout for the cross-impl differ.\n *\n * The runner is a *thin* wrapper over the existing public API — it is not the\n * canonical way to use the package. Library consumers should import the\n * functions directly; the runner exists to give the cross-implementation\n * differ a uniform interface across language ports.\n */\nimport { createInterface } from \"node:readline\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport process from \"node:process\";\n\nimport { Dataset } from \"./data/dataset.js\";\nimport { normalizeName } from \"./data/normalize.js\";\nimport { maximalLoadout } from \"./data/loadout.js\";\nimport { exportRoster, type ExportFormat } from \"./export/index.js\";\nimport { importRoster, tryImportRoster, REGISTERED_ADAPTERS } from \"./import/import-roster.js\";\nimport { selectAdapter } from \"./import/adapter.js\";\nimport { createValidator } from \"./schema-loader.js\";\nimport { attributeStages, crunch, type Buff, type EngineContext, type EngineInput } from \"./cruncher/index.js\";\nimport { describeScoringCard } from \"./translate/index.js\";\nimport { resolveLayout, TerrainResolveError } from \"./terrain/index.js\";\nimport type { TerrainTemplate, TerrainLayout } from \"./terrain/resolve.js\";\nimport type Ajv from \"ajv\";\n\n// -----------------------------------------------------------------------------\n// Constants — spec version and implementation identity.\n// -----------------------------------------------------------------------------\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction loadSpecVersion(): number {\n // The corpus lives at repo-root/conformance/. Walk up from tools/src/ until\n // we find it so the runner works both from source (tsx) and from dist/.\n for (const candidate of [\n join(__dirname, \"../../conformance/SPEC_VERSION\"),\n join(__dirname, \"../../../conformance/SPEC_VERSION\"),\n ]) {\n try {\n return Number.parseInt(readFileSync(candidate, \"utf8\").trim(), 10);\n } catch {\n // try next\n }\n }\n throw new Error(\"could not locate conformance/SPEC_VERSION\");\n}\n\nfunction loadImplVersion(): string {\n for (const candidate of [\n join(__dirname, \"../package.json\"),\n join(__dirname, \"../../package.json\"),\n ]) {\n try {\n return (JSON.parse(readFileSync(candidate, \"utf8\")) as { version: string }).version;\n } catch {\n // try next\n }\n }\n return \"unknown\";\n}\n\nconst SPEC_VERSION = loadSpecVersion();\nconst IMPL_VERSION = loadImplVersion();\nconst IMPL_NAME = \"ts\";\n\n// -----------------------------------------------------------------------------\n// Error envelope helpers and the closed `error_kind` enum.\n// -----------------------------------------------------------------------------\n\nexport type RunnerResponse =\n | { ok: true; value: unknown }\n | { ok: false; error_kind: ErrorKind; error_payload?: unknown };\n\nconst ERROR_KINDS = [\n \"INVALID_INPUT\",\n \"UNKNOWN_OP\",\n \"UNKNOWN_ENTITY\",\n \"IMPORT_FAILED\",\n \"EXPORT_FAILED\",\n \"VALIDATION_ERROR\",\n \"CRUNCH_ERROR\",\n \"INTERNAL_ERROR\",\n] as const;\ntype ErrorKind = (typeof ERROR_KINDS)[number];\n\nfunction ok(value: unknown): RunnerResponse {\n return { ok: true, value };\n}\nfunction err(kind: ErrorKind, payload?: unknown): RunnerResponse {\n return payload === undefined\n ? { ok: false, error_kind: kind }\n : { ok: false, error_kind: kind, error_payload: payload };\n}\n\n// -----------------------------------------------------------------------------\n// Runner state — init must be the first request; subsequent ops fail with\n// INVALID_INPUT until init succeeds. Dataset and validator are lazy.\n// -----------------------------------------------------------------------------\n\nexport interface RunnerState {\n initialized: boolean;\n locale: string;\n tz: string;\n seed: number;\n dataset?: Dataset;\n validator?: Ajv;\n}\n\nexport function createRunnerState(): RunnerState {\n return { initialized: false, locale: \"C\", tz: \"UTC\", seed: 0 };\n}\n\nfunction getDataset(state: RunnerState): Dataset {\n if (!state.dataset) state.dataset = Dataset.embedded();\n return state.dataset;\n}\n\nfunction getValidator(state: RunnerState): Ajv {\n if (!state.validator) state.validator = createValidator();\n return state.validator;\n}\n\n// -----------------------------------------------------------------------------\n// Op handlers.\n// -----------------------------------------------------------------------------\n\nfunction handleInit(state: RunnerState, args: unknown): RunnerResponse {\n if (state.initialized) {\n return err(\"INVALID_INPUT\", { detail: \"init called twice\" });\n }\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"init args must be an object\" });\n }\n const a = args as { spec_version?: unknown; locale?: unknown; tz?: unknown; seed?: unknown };\n if (a.spec_version !== SPEC_VERSION) {\n return err(\"INVALID_INPUT\", {\n detail: `spec_version mismatch: runner=${SPEC_VERSION}, request=${String(a.spec_version)}`,\n });\n }\n if (a.locale !== \"C\") {\n return err(\"INVALID_INPUT\", { detail: `unsupported locale: ${String(a.locale)} (only \"C\")` });\n }\n if (a.tz !== \"UTC\") {\n return err(\"INVALID_INPUT\", { detail: `unsupported tz: ${String(a.tz)} (only \"UTC\")` });\n }\n if (typeof a.seed !== \"number\") {\n return err(\"INVALID_INPUT\", { detail: \"seed must be a number\" });\n }\n state.initialized = true;\n state.locale = a.locale;\n state.tz = a.tz;\n state.seed = a.seed;\n return ok({ impl: IMPL_NAME, spec_version: SPEC_VERSION, impl_version: IMPL_VERSION });\n}\n\nfunction handleNormalize(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"normalize args must be an object\" });\n }\n const a = args as { input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"normalize.input must be a string\" });\n }\n return ok(normalizeName(a.input));\n}\n\nfunction handleImport(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"import args must be an object\" });\n }\n const a = args as { format?: unknown; input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"import.input must be a string\" });\n }\n try {\n // The wire protocol carries every input as a string: JSON payloads come\n // through as the JSON text, text payloads come through as-is. The import\n // pipeline decides which by attempting to parse JSON first.\n const trimmed = a.input.trimStart();\n let decoded: unknown;\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n decoded = JSON.parse(a.input);\n } catch {\n decoded = a.input;\n }\n } else {\n decoded = a.input;\n }\n const roster = importRoster(decoded, { dataset: getDataset(state) });\n return ok(roster);\n } catch (e) {\n return err(\"IMPORT_FAILED\", { detail: (e as Error).message, format: a.format ?? null });\n }\n}\n\nfunction handleTryImport(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"try_import args must be an object\" });\n }\n const a = args as { input?: unknown };\n if (typeof a.input !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"try_import.input must be a string\" });\n }\n const result = tryImportRoster(a.input, { dataset: getDataset(state) });\n if (!result.ok) {\n return err(\"IMPORT_FAILED\", { reason: result.reason, message: result.message });\n }\n return ok({ format: result.format, roster: result.roster });\n}\n\nconst EXPORT_FORMATS: ExportFormat[] = [\n \"newrecruit-json\",\n \"newrecruit-wtc-compact\",\n \"newrecruit-wtc-full\",\n \"newrecruit-simple\",\n \"roster-json\",\n \"rosterizer\",\n];\n\nfunction handleExport(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"export args must be an object\" });\n }\n const a = args as { format?: unknown; roster?: unknown };\n if (typeof a.format !== \"string\" || !EXPORT_FORMATS.includes(a.format as ExportFormat)) {\n return err(\"INVALID_INPUT\", { detail: `unknown export format: ${String(a.format)}` });\n }\n if (typeof a.roster !== \"object\" || a.roster === null) {\n return err(\"INVALID_INPUT\", { detail: \"export.roster must be an object\" });\n }\n try {\n // We assume the caller passes the canonical resolved Roster shape; if they\n // pass something the serializer can't handle, this throws.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ok(exportRoster(a.roster as any, a.format as ExportFormat));\n } catch (e) {\n return err(\"EXPORT_FAILED\", { detail: (e as Error).message });\n }\n}\n\n/**\n * Canonical string encoding of a base size for cross-impl comparison (mirrors the\n * string-encoding used by `maximal_loadout`). Returns null for an absent base.\n * round 32 → \"round:32\"\n * oval 75×42 → \"oval:75x42\"\n * small flyer → \"flying-base:small:draft\"\n * hull (draft) → \"hull:draft\"\n */\nexport function encodeBase(\n b:\n | { shape: string; diameter?: number; width?: number; length?: number; size?: string; draft?: boolean }\n | null\n | undefined,\n): string | null {\n if (!b) return null;\n const parts: string[] = [b.shape];\n if (b.shape === \"round\" && b.diameter != null) parts.push(String(b.diameter));\n else if (b.shape === \"oval\" && b.width != null && b.length != null) parts.push(`${b.width}x${b.length}`);\n else if (b.shape === \"flying-base\" && b.size) parts.push(b.size);\n if (b.draft) parts.push(\"draft\");\n return parts.join(\":\");\n}\n\nfunction handleLinkedQuery(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"linked_query args must be an object\" });\n }\n const a = args as { query?: unknown; input?: unknown };\n if (typeof a.query !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"linked_query.query must be a string\" });\n }\n const ds = getDataset(state);\n const input = (a.input ?? {}) as Record<string, string>;\n try {\n switch (a.query) {\n case \"find_unit\":\n return ok(ds.units.find(input.query ?? \"\")?.id ?? null);\n case \"find_weapon\":\n return ok(ds.weapons.find(input.query ?? \"\")?.id ?? null);\n case \"find_faction\":\n return ok(ds.factions.find(input.query ?? \"\")?.id ?? null);\n case \"find_ability\":\n return ok(ds.abilities.find(input.query ?? \"\")?.id ?? null);\n case \"abilities_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.abilities.map((x) => x.id));\n }\n case \"weapons_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.weapons.map((x) => x.id));\n }\n case \"wargear_options_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.wargearOptions.map((x) => x.id));\n }\n case \"maximal_loadout\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n const modelCount = Number(input.modelCount);\n const lo = maximalLoadout(u.raw, modelCount, ds.wargearOptionsOf(u.raw));\n // Encode the id→count map as sorted \"id:count\" strings for set compare.\n return ok([...lo.counts].map(([id, n]) => `${id}:${n}`).sort());\n }\n case \"phases_of\": {\n const ab = ds.abilities.get(input.abilityId);\n if (!ab) return err(\"UNKNOWN_ENTITY\", { kind: \"ability\", id: input.abilityId });\n return ok([...ab.phases]);\n }\n case \"faction_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(u.faction?.id ?? null);\n }\n case \"base_size_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n return ok(encodeBase(u.raw.base_size_mm));\n }\n case \"model_bases_of\": {\n const u = ds.units.get(input.unitId);\n if (!u) return err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: input.unitId });\n const comp = ds.unitCompositions.find((c) => c.unit_id === input.unitId);\n // Ordered \"modelName=encodedBase\" pairs in declared model order.\n return ok((comp?.models ?? []).map((m) => `${m.name}=${encodeBase(m.base_size_mm) ?? \"none\"}`));\n }\n case \"abilities_of_faction\":\n return ok(ds.abilities.byFaction(input.factionId).map((x) => x.id));\n case \"weapons_of_faction\": {\n const f = ds.factions.get(input.factionId);\n if (!f) return err(\"UNKNOWN_ENTITY\", { kind: \"faction\", id: input.factionId });\n return ok(f.weapons.map((x) => x.id));\n }\n default:\n return err(\"INVALID_INPUT\", { detail: `unknown linked_query: ${a.query}` });\n }\n } catch (e) {\n return err(\"INTERNAL_ERROR\", { detail: (e as Error).message });\n }\n}\n\nconst VALIDATOR_TARGETS: Record<string, string> = {\n unit: \"https://40kdc.dev/schemas/core/unit.schema.json\",\n weapon: \"https://40kdc.dev/schemas/core/weapon.schema.json\",\n faction: \"https://40kdc.dev/schemas/core/faction.schema.json\",\n ability: \"https://40kdc.dev/schemas/enrichment/ability-dsl/ability.schema.json\",\n wargear: \"https://40kdc.dev/schemas/core/wargear.schema.json\",\n \"wargear-option\": \"https://40kdc.dev/schemas/core/wargear-option.schema.json\",\n};\n\nfunction ajvKeywordToCode(keyword: string): string {\n switch (keyword) {\n case \"required\":\n return \"REQUIRED_MISSING\";\n case \"type\":\n return \"TYPE_MISMATCH\";\n case \"enum\":\n return \"ENUM_VIOLATION\";\n case \"pattern\":\n case \"format\":\n return \"PATTERN_MISMATCH\";\n case \"minimum\":\n case \"maximum\":\n case \"exclusiveMinimum\":\n case \"exclusiveMaximum\":\n case \"minLength\":\n case \"maxLength\":\n case \"minItems\":\n case \"maxItems\":\n return \"RANGE_VIOLATION\";\n case \"additionalProperties\":\n return \"ADDITIONAL_PROPERTY\";\n case \"uniqueItems\":\n return \"UNIQUE_VIOLATION\";\n default:\n return `UNMAPPED:${keyword}`;\n }\n}\n\nfunction handleValidate(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"validate args must be an object\" });\n }\n const a = args as { target?: unknown; value?: unknown };\n if (typeof a.target !== \"string\" || !(a.target in VALIDATOR_TARGETS)) {\n return err(\"INVALID_INPUT\", { detail: `unknown validator target: ${String(a.target)}` });\n }\n let validate;\n try {\n validate = getValidator(state).getSchema(VALIDATOR_TARGETS[a.target]);\n } catch (e) {\n return err(\"VALIDATION_ERROR\", { detail: (e as Error).message });\n }\n if (!validate) {\n return err(\"VALIDATION_ERROR\", { detail: `schema not loaded: ${a.target}` });\n }\n validate(a.value);\n const raw = validate.errors ?? [];\n const seen = new Set<string>();\n const out: { path: string; code: string }[] = [];\n for (const e of raw) {\n const code = ajvKeywordToCode(e.keyword);\n if (code.startsWith(\"UNMAPPED:\")) continue;\n const path =\n e.keyword === \"required\"\n ? `${e.instancePath}/${(e.params as { missingProperty?: string }).missingProperty ?? \"\"}`\n : e.instancePath;\n const key = `${path}|${code}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({ path, code });\n }\n return ok(out);\n}\n\ninterface CrunchArgs {\n attacker?: { weaponId?: string; profileIndex?: number };\n modelsFiring?: number;\n target?: { unitId?: string; profileIndex?: number; modelCount?: number };\n context?: EngineContext;\n buffs?: Buff[];\n}\n\n/**\n * Validate the wire-shape `crunch`/`attribution` args and assemble the\n * {@link EngineInput} both ops share, or return a typed runner error. The two\n * ops have identical inputs — separating this lets each handler stay tiny and\n * keeps the validation contract in one place.\n */\nfunction buildEngineInput(\n state: RunnerState,\n a: CrunchArgs,\n opName: string,\n): { ok: true; input: EngineInput } | { ok: false; response: RunnerResponse } {\n if (!a.attacker?.weaponId || typeof a.attacker.profileIndex !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.attacker.weaponId/profileIndex required` }) };\n }\n if (!a.target?.unitId || typeof a.target.profileIndex !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.target.unitId/profileIndex required` }) };\n }\n if (typeof a.modelsFiring !== \"number\") {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.modelsFiring required` }) };\n }\n if (!a.context) {\n return { ok: false, response: err(\"INVALID_INPUT\", { detail: `${opName}.context required` }) };\n }\n const ds = getDataset(state);\n const weapon = ds.weapons.get(a.attacker.weaponId);\n if (!weapon) return { ok: false, response: err(\"UNKNOWN_ENTITY\", { kind: \"weapon\", id: a.attacker.weaponId }) };\n const unit = ds.units.get(a.target.unitId);\n if (!unit) return { ok: false, response: err(\"UNKNOWN_ENTITY\", { kind: \"unit\", id: a.target.unitId }) };\n const input: EngineInput = {\n attacker: { weapon: weapon.raw, profileIndex: a.attacker.profileIndex },\n target: {\n unit: unit.raw,\n profileIndex: a.target.profileIndex,\n ...(a.target.modelCount !== undefined ? { modelCount: a.target.modelCount } : {}),\n },\n modelsFiring: a.modelsFiring,\n buffs: a.buffs ?? [],\n context: a.context,\n };\n return { ok: true, input };\n}\n\nfunction handleCrunch(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"crunch args must be an object\" });\n }\n const built = buildEngineInput(state, args as CrunchArgs, \"crunch\");\n if (!built.ok) return built.response;\n try {\n // Canonical wire shape: stages array only. `resolved` is impl-internal\n // (TS/Rust shape diverges); per-stage `detail` strings aren't byte-equal\n // across impls. The differ compares per-stage `expected` with 5e-4\n // tolerance — that's the cross-impl contract.\n const out = crunch(built.input, getDataset(state));\n return ok({ stages: out.stages.map((s) => ({ name: s.name, expected: s.expected })) });\n } catch (e) {\n return err(\"CRUNCH_ERROR\", { detail: (e as Error).message });\n }\n}\n\nfunction handleAttribution(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"attribution args must be an object\" });\n }\n const a = args as CrunchArgs & { epsilon?: number };\n const built = buildEngineInput(state, a, \"attribution\");\n if (!built.ok) return built.response;\n try {\n const opts = typeof a.epsilon === \"number\" ? { epsilon: a.epsilon } : undefined;\n // Drop `detail` from the wire (impl-specific formatting). Keep all\n // numeric fields and the kind-tagged BuffSource shape that's already\n // serde-compatible.\n const stages = attributeStages(built.input, getDataset(state), opts);\n return ok(\n stages.map((s) => ({\n name: s.name,\n expected: s.expected,\n baseline: s.baseline,\n lifts: s.lifts,\n residual: s.residual,\n intrinsics: s.intrinsics,\n })),\n );\n } catch (e) {\n return err(\"CRUNCH_ERROR\", { detail: (e as Error).message });\n }\n}\n\nfunction handleTranslateScoring(state: RunnerState, args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"translate_scoring args must be an object\" });\n }\n const a = args as { cardId?: unknown };\n if (typeof a.cardId !== \"string\") {\n return err(\"INVALID_INPUT\", { detail: \"translate_scoring.cardId must be a string\" });\n }\n const card = getDataset(state).missionCards.get(a.cardId);\n if (!card) return err(\"UNKNOWN_ENTITY\", { kind: \"secondary-card\", id: a.cardId });\n return ok({ awards: describeScoringCard(card) });\n}\n\nfunction handleResolveTerrain(args: unknown): RunnerResponse {\n if (typeof args !== \"object\" || args === null) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain args must be an object\" });\n }\n const a = args as { layout?: unknown; templates?: unknown };\n if (typeof a.layout !== \"object\" || a.layout === null) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain.layout must be an object\" });\n }\n const templates = a.templates ?? [];\n if (!Array.isArray(templates)) {\n return err(\"INVALID_INPUT\", { detail: \"resolve_terrain.templates must be an array\" });\n }\n try {\n const pieces = resolveLayout(a.layout as TerrainLayout, templates as TerrainTemplate[]);\n return ok({ pieces });\n } catch (e) {\n if (e instanceof TerrainResolveError) {\n return err(\"INVALID_INPUT\", { detail: e.message });\n }\n return err(\"INTERNAL_ERROR\", { detail: (e as Error).message });\n }\n}\n\n// -----------------------------------------------------------------------------\n// Dispatcher and per-line entry point.\n// -----------------------------------------------------------------------------\n\n/**\n * Apply one decoded request to the runner state and return the response. Used\n * directly by tests; the CLI loop wraps it with line parsing.\n */\nexport function dispatch(state: RunnerState, req: { op: string; args?: unknown }): RunnerResponse {\n if (!state.initialized && req.op !== \"init\") {\n return err(\"INVALID_INPUT\", { detail: \"must init before any other op\" });\n }\n switch (req.op) {\n case \"init\":\n return handleInit(state, req.args);\n case \"version\":\n return ok({ impl: IMPL_NAME, spec_version: SPEC_VERSION, impl_version: IMPL_VERSION });\n case \"normalize\":\n return handleNormalize(req.args);\n case \"import\":\n return handleImport(state, req.args);\n case \"try_import\":\n return handleTryImport(state, req.args);\n case \"export\":\n return handleExport(req.args);\n case \"linked_query\":\n return handleLinkedQuery(state, req.args);\n case \"validate\":\n return handleValidate(state, req.args);\n case \"crunch\":\n return handleCrunch(state, req.args);\n case \"attribution\":\n return handleAttribution(state, req.args);\n case \"translate_scoring\":\n return handleTranslateScoring(state, req.args);\n case \"resolve_terrain\":\n return handleResolveTerrain(req.args);\n case \"shutdown\":\n return ok(null);\n default:\n return err(\"UNKNOWN_OP\", { op: req.op });\n }\n}\n\n/**\n * Process one line of stdin (one NDJSON request) and return the line that\n * should be written to stdout (one NDJSON response). Returns `null` only on\n * fully-empty input lines, which should be silently ignored.\n */\nexport function processRequest(state: RunnerState, line: string): string | null {\n const trimmed = line.trim();\n if (trimmed === \"\") return null;\n let req: { op?: unknown; args?: unknown };\n try {\n req = JSON.parse(trimmed);\n } catch (e) {\n return JSON.stringify(err(\"INVALID_INPUT\", { detail: `not valid JSON: ${(e as Error).message}` }));\n }\n if (typeof req.op !== \"string\") {\n return JSON.stringify(err(\"INVALID_INPUT\", { detail: \"request must have a string `op` field\" }));\n }\n const response = dispatch(state, { op: req.op, args: req.args });\n return JSON.stringify(response);\n}\n\n// -----------------------------------------------------------------------------\n// CLI: wire stdin/stdout. Only runs when this file is the process entry point.\n// -----------------------------------------------------------------------------\n\nfunction isCliMain(): boolean {\n // process.argv[1] is the path the runtime invoked. With tsx and node both,\n // it points at this file (or its compiled .js form). Comparing absolute\n // paths is the most robust portable check.\n if (!process.argv[1]) return false;\n const entry = process.argv[1];\n const here = fileURLToPath(import.meta.url);\n return entry === here || entry.endsWith(\"/runner.js\") || entry.endsWith(\"/runner.ts\");\n}\n\nasync function runCli(): Promise<void> {\n const state = createRunnerState();\n const rl = createInterface({ input: process.stdin });\n // We must respond on the same tick the request arrives — the differ\n // pipelines requests and expects responses in order. readline preserves\n // line ordering, so processing inside `line` handler is sufficient.\n for await (const line of rl) {\n const out = processRequest(state, line);\n if (out !== null) {\n process.stdout.write(out + \"\\n\");\n }\n // `shutdown` returns `ok(null)`; honor it by exiting after the response\n // is flushed.\n try {\n const req = JSON.parse(line);\n if (req && req.op === \"shutdown\") {\n process.exit(0);\n }\n } catch {\n // already handled above; not a shutdown\n }\n }\n}\n\nif (isCliMain()) {\n runCli().catch((e) => {\n // Last-ditch INTERNAL_ERROR so the differ sees a typed failure rather\n // than an opaque crash.\n process.stdout.write(\n JSON.stringify({\n ok: false,\n error_kind: \"INTERNAL_ERROR\",\n error_payload: { detail: (e as Error).message },\n }) + \"\\n\",\n );\n process.exit(1);\n });\n}\n"]}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card-driven secondary-mission scoring, 10th-edition tactical model.
|
|
3
|
+
*
|
|
4
|
+
* Drawn secondaries are *held* in hand across rounds and **scored once**: the
|
|
5
|
+
* player asserts which of a card's awards they achieved, the engine computes the
|
|
6
|
+
* VP (clamped to the card's cap), records it against the current battle round,
|
|
7
|
+
* and the card is then discarded. There is no multi-turn per-card accrual — a
|
|
8
|
+
* card pays out exactly once.
|
|
9
|
+
*
|
|
10
|
+
* Why "asserted" rather than evaluated: there is no board-state model here, so
|
|
11
|
+
* an award's `when` condition is a human-readable label (see
|
|
12
|
+
* `translate/scoring.ts`'s `describeScoringCard`, which this module never
|
|
13
|
+
* modifies), not something the engine checks. The player ticks the awards they
|
|
14
|
+
* made; the engine does the arithmetic, the OR-tier resolution, the cumulative
|
|
15
|
+
* sums, and the cap.
|
|
16
|
+
*
|
|
17
|
+
* Deck-level rules the card schema deliberately omits live here as constants —
|
|
18
|
+
* chiefly the 5 VP-per-card ceiling of the Tactical approach. The Fixed approach
|
|
19
|
+
* instead uses each award's printed `vp_max`.
|
|
20
|
+
*
|
|
21
|
+
* `PlayerGame` is a plain JSON-serializable object so a UI can persist a whole
|
|
22
|
+
* match (two of them) to localStorage and rehydrate without a revival step.
|
|
23
|
+
*
|
|
24
|
+
* CONFORMANCE FOLLOW-UP: this engine is TypeScript-only for now. A Rust port
|
|
25
|
+
* plus a `conformance/scoring` corpus area (and a `SPEC_VERSION` bump) are a
|
|
26
|
+
* separate change; the public shapes below are the surface that port mirrors,
|
|
27
|
+
* so keep them stable.
|
|
28
|
+
*/
|
|
29
|
+
import type { SecondaryCard } from "../generated.js";
|
|
30
|
+
import type { ScoringAward, ScoringMode } from "../translate/scoring.js";
|
|
31
|
+
/** The Tactical approach caps a single secondary's score at this many VP. */
|
|
32
|
+
export declare const TACTICAL_CARD_CAP = 5;
|
|
33
|
+
/** Battle rounds in a game. */
|
|
34
|
+
export declare const ROUNDS = 5;
|
|
35
|
+
/** Per-player VP ceiling (WTC sheet: grand total out of 100). */
|
|
36
|
+
export declare const GAME_VP_CAP = 100;
|
|
37
|
+
/** An award the player ticks when scoring, with a count for per-instance awards. */
|
|
38
|
+
export interface AssertedAward {
|
|
39
|
+
award: ScoringAward;
|
|
40
|
+
/** Instances achieved (for `vp_per` awards); defaults to 1. */
|
|
41
|
+
count?: number;
|
|
42
|
+
}
|
|
43
|
+
/** VP recorded against a single battle round. */
|
|
44
|
+
export interface RoundCell {
|
|
45
|
+
primary: number;
|
|
46
|
+
secondary: number;
|
|
47
|
+
}
|
|
48
|
+
/** A scored secondary, kept so the record can be shown and undone. */
|
|
49
|
+
export interface ScoreEntry {
|
|
50
|
+
cardId: string;
|
|
51
|
+
/** Battle round (1-based) the card was scored in. */
|
|
52
|
+
round: number;
|
|
53
|
+
vp: number;
|
|
54
|
+
}
|
|
55
|
+
/** One player's whole-game scoring state. Plain data — safe to JSON round-trip. */
|
|
56
|
+
export interface PlayerGame {
|
|
57
|
+
/** Scoring approach: filters `mode` awards and sets the per-score cap. */
|
|
58
|
+
approach: ScoringMode;
|
|
59
|
+
/** Drawn-but-unscored secondaries, by card id. Scoring removes a card from here. */
|
|
60
|
+
handIds: string[];
|
|
61
|
+
/** Per-round VP, index 0 = round 1. Always length {@link ROUNDS}. */
|
|
62
|
+
rounds: RoundCell[];
|
|
63
|
+
/** Log of scored secondaries, in scoring order — the editable record. */
|
|
64
|
+
log: ScoreEntry[];
|
|
65
|
+
}
|
|
66
|
+
/** A fresh player game for the given approach (defaults to tactical). */
|
|
67
|
+
export declare function emptyPlayerGame(approach?: ScoringMode): PlayerGame;
|
|
68
|
+
/** Read a card's `awards`, typed (the generated `SecondaryCard` leaves them opaque). */
|
|
69
|
+
export declare function awardsOf(card: SecondaryCard): ScoringAward[];
|
|
70
|
+
/**
|
|
71
|
+
* The awards a player scores under `approach`. An award with no `mode` is flat
|
|
72
|
+
* (it scores the same either way); an award tagged `fixed`/`tactical` scores
|
|
73
|
+
* only under the matching approach.
|
|
74
|
+
*/
|
|
75
|
+
export declare function awardsForApproach(card: SecondaryCard, approach: ScoringMode): ScoringAward[];
|
|
76
|
+
/**
|
|
77
|
+
* VP for a single asserted award. A flat `vp` ignores `count`; a `vp_per` award
|
|
78
|
+
* scores `vp_per × count`, with `count` clamped to `per_max` when present.
|
|
79
|
+
*/
|
|
80
|
+
export declare function scoreAward(award: ScoringAward, count?: number): number;
|
|
81
|
+
/**
|
|
82
|
+
* VP from everything asserted in one scoring, before the card cap. Awards
|
|
83
|
+
* sharing an `exclusive_group` resolve as "only the highest scores" (the card's
|
|
84
|
+
* literal OR between tier rows); everything else, including `cumulative` "+"
|
|
85
|
+
* rows, sums.
|
|
86
|
+
*/
|
|
87
|
+
export declare function scoreTurn(asserted: AssertedAward[]): number;
|
|
88
|
+
/**
|
|
89
|
+
* A card's per-score VP ceiling under `approach`. Tactical is the universal
|
|
90
|
+
* {@link TACTICAL_CARD_CAP}. Fixed uses the largest `vp_max` printed on the
|
|
91
|
+
* card's scorable awards, or `Infinity` when none is printed (uncapped).
|
|
92
|
+
*/
|
|
93
|
+
export declare function scoreCap(card: SecondaryCard, approach: ScoringMode): number;
|
|
94
|
+
/**
|
|
95
|
+
* The VP a single scoring of `card` grants under `approach`: the asserted awards'
|
|
96
|
+
* total, clamped to the card's cap. This is the amount banked when the card is
|
|
97
|
+
* scored (and then discarded).
|
|
98
|
+
*/
|
|
99
|
+
export declare function scoreSecondaryEvent(asserted: AssertedAward[], card: SecondaryCard, approach: ScoringMode): number;
|
|
100
|
+
/** Add secondary VP to a battle round (1-based). Pure — returns new state. */
|
|
101
|
+
export declare function recordSecondary(pg: PlayerGame, round: number, vp: number): PlayerGame;
|
|
102
|
+
/**
|
|
103
|
+
* Score a held secondary: add its VP to the round, append it to the log, and
|
|
104
|
+
* discard it from hand. Pure. The caller computes `vp` via
|
|
105
|
+
* {@link scoreSecondaryEvent}.
|
|
106
|
+
*/
|
|
107
|
+
export declare function scoreSecondary(pg: PlayerGame, round: number, cardId: string, vp: number): PlayerGame;
|
|
108
|
+
/**
|
|
109
|
+
* Undo a logged scoring by index: subtract its VP from its round, drop the log
|
|
110
|
+
* entry, and return the card to hand so it can be re-scored. Pure; a no-op for
|
|
111
|
+
* an out-of-range index.
|
|
112
|
+
*/
|
|
113
|
+
export declare function removeScore(pg: PlayerGame, index: number): PlayerGame;
|
|
114
|
+
/** Set primary VP for a battle round (1-based) to a clamped value. Pure. */
|
|
115
|
+
export declare function setPrimary(pg: PlayerGame, round: number, vp: number): PlayerGame;
|
|
116
|
+
/** Put a drawn card in hand (no duplicates). Pure. */
|
|
117
|
+
export declare function addToHand(pg: PlayerGame, cardId: string): PlayerGame;
|
|
118
|
+
/** Remove a card from hand (e.g. on score or discard). Pure. */
|
|
119
|
+
export declare function removeFromHand(pg: PlayerGame, cardId: string): PlayerGame;
|
|
120
|
+
/** Total primary VP across the game. */
|
|
121
|
+
export declare function playerPrimary(pg: PlayerGame): number;
|
|
122
|
+
/** Total secondary VP across the game. */
|
|
123
|
+
export declare function playerSecondary(pg: PlayerGame): number;
|
|
124
|
+
/** Grand total VP, capped at {@link GAME_VP_CAP}. */
|
|
125
|
+
export declare function playerTotal(pg: PlayerGame): number;
|
|
126
|
+
/**
|
|
127
|
+
* The WTC 20-point result from two grand totals. The winner's margin maps onto
|
|
128
|
+
* 11 bands (0-5 → 10-10 draw, 6-10 → 11-9, ... 51+ → 20-0); the loser gets the
|
|
129
|
+
* complement. `a`/`b` correspond to the argument order.
|
|
130
|
+
*/
|
|
131
|
+
export declare function wtcResult(totalA: number, totalB: number): {
|
|
132
|
+
a: number;
|
|
133
|
+
b: number;
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scoring/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card-driven secondary-mission scoring, 10th-edition tactical model.
|
|
3
|
+
*
|
|
4
|
+
* Drawn secondaries are *held* in hand across rounds and **scored once**: the
|
|
5
|
+
* player asserts which of a card's awards they achieved, the engine computes the
|
|
6
|
+
* VP (clamped to the card's cap), records it against the current battle round,
|
|
7
|
+
* and the card is then discarded. There is no multi-turn per-card accrual — a
|
|
8
|
+
* card pays out exactly once.
|
|
9
|
+
*
|
|
10
|
+
* Why "asserted" rather than evaluated: there is no board-state model here, so
|
|
11
|
+
* an award's `when` condition is a human-readable label (see
|
|
12
|
+
* `translate/scoring.ts`'s `describeScoringCard`, which this module never
|
|
13
|
+
* modifies), not something the engine checks. The player ticks the awards they
|
|
14
|
+
* made; the engine does the arithmetic, the OR-tier resolution, the cumulative
|
|
15
|
+
* sums, and the cap.
|
|
16
|
+
*
|
|
17
|
+
* Deck-level rules the card schema deliberately omits live here as constants —
|
|
18
|
+
* chiefly the 5 VP-per-card ceiling of the Tactical approach. The Fixed approach
|
|
19
|
+
* instead uses each award's printed `vp_max`.
|
|
20
|
+
*
|
|
21
|
+
* `PlayerGame` is a plain JSON-serializable object so a UI can persist a whole
|
|
22
|
+
* match (two of them) to localStorage and rehydrate without a revival step.
|
|
23
|
+
*
|
|
24
|
+
* CONFORMANCE FOLLOW-UP: this engine is TypeScript-only for now. A Rust port
|
|
25
|
+
* plus a `conformance/scoring` corpus area (and a `SPEC_VERSION` bump) are a
|
|
26
|
+
* separate change; the public shapes below are the surface that port mirrors,
|
|
27
|
+
* so keep them stable.
|
|
28
|
+
*/
|
|
29
|
+
/** The Tactical approach caps a single secondary's score at this many VP. */
|
|
30
|
+
export const TACTICAL_CARD_CAP = 5;
|
|
31
|
+
/** Battle rounds in a game. */
|
|
32
|
+
export const ROUNDS = 5;
|
|
33
|
+
/** Per-player VP ceiling (WTC sheet: grand total out of 100). */
|
|
34
|
+
export const GAME_VP_CAP = 100;
|
|
35
|
+
/** A fresh player game for the given approach (defaults to tactical). */
|
|
36
|
+
export function emptyPlayerGame(approach = "tactical") {
|
|
37
|
+
return {
|
|
38
|
+
approach,
|
|
39
|
+
handIds: [],
|
|
40
|
+
rounds: Array.from({ length: ROUNDS }, () => ({ primary: 0, secondary: 0 })),
|
|
41
|
+
log: [],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Read a card's `awards`, typed (the generated `SecondaryCard` leaves them opaque). */
|
|
45
|
+
export function awardsOf(card) {
|
|
46
|
+
return (card.awards ?? []);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The awards a player scores under `approach`. An award with no `mode` is flat
|
|
50
|
+
* (it scores the same either way); an award tagged `fixed`/`tactical` scores
|
|
51
|
+
* only under the matching approach.
|
|
52
|
+
*/
|
|
53
|
+
export function awardsForApproach(card, approach) {
|
|
54
|
+
return awardsOf(card).filter((a) => a.mode == null || a.mode === approach);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* VP for a single asserted award. A flat `vp` ignores `count`; a `vp_per` award
|
|
58
|
+
* scores `vp_per × count`, with `count` clamped to `per_max` when present.
|
|
59
|
+
*/
|
|
60
|
+
export function scoreAward(award, count = 1) {
|
|
61
|
+
if (award.vp != null)
|
|
62
|
+
return award.vp;
|
|
63
|
+
if (award.vp_per != null) {
|
|
64
|
+
const capped = award.per_max != null ? Math.min(count, award.per_max) : count;
|
|
65
|
+
return award.vp_per * Math.max(0, capped);
|
|
66
|
+
}
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* VP from everything asserted in one scoring, before the card cap. Awards
|
|
71
|
+
* sharing an `exclusive_group` resolve as "only the highest scores" (the card's
|
|
72
|
+
* literal OR between tier rows); everything else, including `cumulative` "+"
|
|
73
|
+
* rows, sums.
|
|
74
|
+
*/
|
|
75
|
+
export function scoreTurn(asserted) {
|
|
76
|
+
const groupBest = new Map();
|
|
77
|
+
let total = 0;
|
|
78
|
+
for (const { award, count } of asserted) {
|
|
79
|
+
const v = scoreAward(award, count ?? 1);
|
|
80
|
+
if (award.exclusive_group != null) {
|
|
81
|
+
const prev = groupBest.get(award.exclusive_group) ?? 0;
|
|
82
|
+
if (v > prev)
|
|
83
|
+
groupBest.set(award.exclusive_group, v);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
total += v;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const v of groupBest.values())
|
|
90
|
+
total += v;
|
|
91
|
+
return total;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A card's per-score VP ceiling under `approach`. Tactical is the universal
|
|
95
|
+
* {@link TACTICAL_CARD_CAP}. Fixed uses the largest `vp_max` printed on the
|
|
96
|
+
* card's scorable awards, or `Infinity` when none is printed (uncapped).
|
|
97
|
+
*/
|
|
98
|
+
export function scoreCap(card, approach) {
|
|
99
|
+
if (approach === "tactical")
|
|
100
|
+
return TACTICAL_CARD_CAP;
|
|
101
|
+
const caps = awardsForApproach(card, "fixed")
|
|
102
|
+
.map((a) => a.vp_max)
|
|
103
|
+
.filter((x) => x != null);
|
|
104
|
+
return caps.length > 0 ? Math.max(...caps) : Infinity;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The VP a single scoring of `card` grants under `approach`: the asserted awards'
|
|
108
|
+
* total, clamped to the card's cap. This is the amount banked when the card is
|
|
109
|
+
* scored (and then discarded).
|
|
110
|
+
*/
|
|
111
|
+
export function scoreSecondaryEvent(asserted, card, approach) {
|
|
112
|
+
return Math.min(scoreTurn(asserted), scoreCap(card, approach));
|
|
113
|
+
}
|
|
114
|
+
function roundIndex(round) {
|
|
115
|
+
return Math.max(0, Math.min(ROUNDS - 1, Math.trunc(round) - 1));
|
|
116
|
+
}
|
|
117
|
+
/** Add secondary VP to a battle round (1-based). Pure — returns new state. */
|
|
118
|
+
export function recordSecondary(pg, round, vp) {
|
|
119
|
+
const i = roundIndex(round);
|
|
120
|
+
const rounds = pg.rounds.map((c, idx) => idx === i ? { ...c, secondary: c.secondary + Math.max(0, vp) } : c);
|
|
121
|
+
return { ...pg, rounds };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Score a held secondary: add its VP to the round, append it to the log, and
|
|
125
|
+
* discard it from hand. Pure. The caller computes `vp` via
|
|
126
|
+
* {@link scoreSecondaryEvent}.
|
|
127
|
+
*/
|
|
128
|
+
export function scoreSecondary(pg, round, cardId, vp) {
|
|
129
|
+
const banked = Math.max(0, vp);
|
|
130
|
+
const recorded = recordSecondary(pg, round, banked);
|
|
131
|
+
return {
|
|
132
|
+
...removeFromHand(recorded, cardId),
|
|
133
|
+
log: [...pg.log, { cardId, round, vp: banked }],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Undo a logged scoring by index: subtract its VP from its round, drop the log
|
|
138
|
+
* entry, and return the card to hand so it can be re-scored. Pure; a no-op for
|
|
139
|
+
* an out-of-range index.
|
|
140
|
+
*/
|
|
141
|
+
export function removeScore(pg, index) {
|
|
142
|
+
const entry = pg.log[index];
|
|
143
|
+
if (!entry)
|
|
144
|
+
return pg;
|
|
145
|
+
const i = roundIndex(entry.round);
|
|
146
|
+
const rounds = pg.rounds.map((c, idx) => idx === i ? { ...c, secondary: Math.max(0, c.secondary - entry.vp) } : c);
|
|
147
|
+
const log = pg.log.filter((_, idx) => idx !== index);
|
|
148
|
+
const handIds = pg.handIds.includes(entry.cardId)
|
|
149
|
+
? pg.handIds
|
|
150
|
+
: [...pg.handIds, entry.cardId];
|
|
151
|
+
return { ...pg, rounds, log, handIds };
|
|
152
|
+
}
|
|
153
|
+
/** Set primary VP for a battle round (1-based) to a clamped value. Pure. */
|
|
154
|
+
export function setPrimary(pg, round, vp) {
|
|
155
|
+
const i = roundIndex(round);
|
|
156
|
+
const rounds = pg.rounds.map((c, idx) => idx === i ? { ...c, primary: Math.max(0, vp) } : c);
|
|
157
|
+
return { ...pg, rounds };
|
|
158
|
+
}
|
|
159
|
+
/** Put a drawn card in hand (no duplicates). Pure. */
|
|
160
|
+
export function addToHand(pg, cardId) {
|
|
161
|
+
if (pg.handIds.includes(cardId))
|
|
162
|
+
return pg;
|
|
163
|
+
return { ...pg, handIds: [...pg.handIds, cardId] };
|
|
164
|
+
}
|
|
165
|
+
/** Remove a card from hand (e.g. on score or discard). Pure. */
|
|
166
|
+
export function removeFromHand(pg, cardId) {
|
|
167
|
+
return { ...pg, handIds: pg.handIds.filter((id) => id !== cardId) };
|
|
168
|
+
}
|
|
169
|
+
/** Total primary VP across the game. */
|
|
170
|
+
export function playerPrimary(pg) {
|
|
171
|
+
return pg.rounds.reduce((sum, c) => sum + c.primary, 0);
|
|
172
|
+
}
|
|
173
|
+
/** Total secondary VP across the game. */
|
|
174
|
+
export function playerSecondary(pg) {
|
|
175
|
+
return pg.rounds.reduce((sum, c) => sum + c.secondary, 0);
|
|
176
|
+
}
|
|
177
|
+
/** Grand total VP, capped at {@link GAME_VP_CAP}. */
|
|
178
|
+
export function playerTotal(pg) {
|
|
179
|
+
return Math.min(GAME_VP_CAP, playerPrimary(pg) + playerSecondary(pg));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The WTC 20-point result from two grand totals. The winner's margin maps onto
|
|
183
|
+
* 11 bands (0-5 → 10-10 draw, 6-10 → 11-9, ... 51+ → 20-0); the loser gets the
|
|
184
|
+
* complement. `a`/`b` correspond to the argument order.
|
|
185
|
+
*/
|
|
186
|
+
export function wtcResult(totalA, totalB) {
|
|
187
|
+
const diff = Math.abs(totalA - totalB);
|
|
188
|
+
const band = diff <= 5 ? 0 : Math.min(10, Math.ceil((diff - 5) / 5));
|
|
189
|
+
const winner = 10 + band;
|
|
190
|
+
const loser = 10 - band;
|
|
191
|
+
if (totalA === totalB)
|
|
192
|
+
return { a: 10, b: 10 };
|
|
193
|
+
return totalA > totalB ? { a: winner, b: loser } : { a: loser, b: winner };
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scoring/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC;AACxB,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAmC/B,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,WAAwB,UAAU;IAChE,OAAO;QACL,QAAQ;QACR,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5E,GAAG,EAAE,EAAE;KACR,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,IAAmB;IAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAA8B,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAmB,EAAE,QAAqB;IAC1E,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,KAAK,GAAG,CAAC;IACvD,IAAI,KAAK,CAAC,EAAE,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9E,OAAO,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,QAAyB;IACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,CAAC,GAAG,IAAI;gBAAE,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE;QAAE,KAAK,IAAI,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAmB,EAAE,QAAqB;IACjE,IAAI,QAAQ,KAAK,UAAU;QAAE,OAAO,iBAAiB,CAAC;IACtD,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAyB,EACzB,IAAmB,EACnB,QAAqB;IAErB,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,EAAc,EAAE,KAAa,EAAE,EAAU;IACvE,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CACtC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CACnE,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,EAAc,EACd,KAAa,EACb,MAAc,EACd,EAAU;IAEV,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO;QACL,GAAG,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC;QACnC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,EAAc,EAAE,KAAa;IACvD,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CACtC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CACzE,CAAC;IACF,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;QAC/C,CAAC,CAAC,EAAE,CAAC,OAAO;QACZ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,EAAc,EAAE,KAAa,EAAE,EAAU;IAClE,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CACtC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CACnD,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,SAAS,CAAC,EAAc,EAAE,MAAc;IACtD,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,EAAc,EAAE,MAAc;IAC3D,OAAO,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,aAAa,CAAC,EAAc;IAC1C,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,eAAe,CAAC,EAAc;IAC5C,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,WAAW,CAAC,EAAc;IACxC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,MAAc;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC;IACzB,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC;IACxB,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAC/C,OAAO,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7E,CAAC","sourcesContent":["/**\n * Card-driven secondary-mission scoring, 10th-edition tactical model.\n *\n * Drawn secondaries are *held* in hand across rounds and **scored once**: the\n * player asserts which of a card's awards they achieved, the engine computes the\n * VP (clamped to the card's cap), records it against the current battle round,\n * and the card is then discarded. There is no multi-turn per-card accrual — a\n * card pays out exactly once.\n *\n * Why \"asserted\" rather than evaluated: there is no board-state model here, so\n * an award's `when` condition is a human-readable label (see\n * `translate/scoring.ts`'s `describeScoringCard`, which this module never\n * modifies), not something the engine checks. The player ticks the awards they\n * made; the engine does the arithmetic, the OR-tier resolution, the cumulative\n * sums, and the cap.\n *\n * Deck-level rules the card schema deliberately omits live here as constants —\n * chiefly the 5 VP-per-card ceiling of the Tactical approach. The Fixed approach\n * instead uses each award's printed `vp_max`.\n *\n * `PlayerGame` is a plain JSON-serializable object so a UI can persist a whole\n * match (two of them) to localStorage and rehydrate without a revival step.\n *\n * CONFORMANCE FOLLOW-UP: this engine is TypeScript-only for now. A Rust port\n * plus a `conformance/scoring` corpus area (and a `SPEC_VERSION` bump) are a\n * separate change; the public shapes below are the surface that port mirrors,\n * so keep them stable.\n */\n\nimport type { SecondaryCard } from \"../generated.js\";\nimport type { ScoringAward, ScoringMode } from \"../translate/scoring.js\";\n\n/** The Tactical approach caps a single secondary's score at this many VP. */\nexport const TACTICAL_CARD_CAP = 5;\n/** Battle rounds in a game. */\nexport const ROUNDS = 5;\n/** Per-player VP ceiling (WTC sheet: grand total out of 100). */\nexport const GAME_VP_CAP = 100;\n\n/** An award the player ticks when scoring, with a count for per-instance awards. */\nexport interface AssertedAward {\n award: ScoringAward;\n /** Instances achieved (for `vp_per` awards); defaults to 1. */\n count?: number;\n}\n\n/** VP recorded against a single battle round. */\nexport interface RoundCell {\n primary: number;\n secondary: number;\n}\n\n/** A scored secondary, kept so the record can be shown and undone. */\nexport interface ScoreEntry {\n cardId: string;\n /** Battle round (1-based) the card was scored in. */\n round: number;\n vp: number;\n}\n\n/** One player's whole-game scoring state. Plain data — safe to JSON round-trip. */\nexport interface PlayerGame {\n /** Scoring approach: filters `mode` awards and sets the per-score cap. */\n approach: ScoringMode;\n /** Drawn-but-unscored secondaries, by card id. Scoring removes a card from here. */\n handIds: string[];\n /** Per-round VP, index 0 = round 1. Always length {@link ROUNDS}. */\n rounds: RoundCell[];\n /** Log of scored secondaries, in scoring order — the editable record. */\n log: ScoreEntry[];\n}\n\n/** A fresh player game for the given approach (defaults to tactical). */\nexport function emptyPlayerGame(approach: ScoringMode = \"tactical\"): PlayerGame {\n return {\n approach,\n handIds: [],\n rounds: Array.from({ length: ROUNDS }, () => ({ primary: 0, secondary: 0 })),\n log: [],\n };\n}\n\n/** Read a card's `awards`, typed (the generated `SecondaryCard` leaves them opaque). */\nexport function awardsOf(card: SecondaryCard): ScoringAward[] {\n return (card.awards ?? []) as unknown as ScoringAward[];\n}\n\n/**\n * The awards a player scores under `approach`. An award with no `mode` is flat\n * (it scores the same either way); an award tagged `fixed`/`tactical` scores\n * only under the matching approach.\n */\nexport function awardsForApproach(card: SecondaryCard, approach: ScoringMode): ScoringAward[] {\n return awardsOf(card).filter((a) => a.mode == null || a.mode === approach);\n}\n\n/**\n * VP for a single asserted award. A flat `vp` ignores `count`; a `vp_per` award\n * scores `vp_per × count`, with `count` clamped to `per_max` when present.\n */\nexport function scoreAward(award: ScoringAward, count = 1): number {\n if (award.vp != null) return award.vp;\n if (award.vp_per != null) {\n const capped = award.per_max != null ? Math.min(count, award.per_max) : count;\n return award.vp_per * Math.max(0, capped);\n }\n return 0;\n}\n\n/**\n * VP from everything asserted in one scoring, before the card cap. Awards\n * sharing an `exclusive_group` resolve as \"only the highest scores\" (the card's\n * literal OR between tier rows); everything else, including `cumulative` \"+\"\n * rows, sums.\n */\nexport function scoreTurn(asserted: AssertedAward[]): number {\n const groupBest = new Map<string, number>();\n let total = 0;\n for (const { award, count } of asserted) {\n const v = scoreAward(award, count ?? 1);\n if (award.exclusive_group != null) {\n const prev = groupBest.get(award.exclusive_group) ?? 0;\n if (v > prev) groupBest.set(award.exclusive_group, v);\n } else {\n total += v;\n }\n }\n for (const v of groupBest.values()) total += v;\n return total;\n}\n\n/**\n * A card's per-score VP ceiling under `approach`. Tactical is the universal\n * {@link TACTICAL_CARD_CAP}. Fixed uses the largest `vp_max` printed on the\n * card's scorable awards, or `Infinity` when none is printed (uncapped).\n */\nexport function scoreCap(card: SecondaryCard, approach: ScoringMode): number {\n if (approach === \"tactical\") return TACTICAL_CARD_CAP;\n const caps = awardsForApproach(card, \"fixed\")\n .map((a) => a.vp_max)\n .filter((x): x is number => x != null);\n return caps.length > 0 ? Math.max(...caps) : Infinity;\n}\n\n/**\n * The VP a single scoring of `card` grants under `approach`: the asserted awards'\n * total, clamped to the card's cap. This is the amount banked when the card is\n * scored (and then discarded).\n */\nexport function scoreSecondaryEvent(\n asserted: AssertedAward[],\n card: SecondaryCard,\n approach: ScoringMode,\n): number {\n return Math.min(scoreTurn(asserted), scoreCap(card, approach));\n}\n\nfunction roundIndex(round: number): number {\n return Math.max(0, Math.min(ROUNDS - 1, Math.trunc(round) - 1));\n}\n\n/** Add secondary VP to a battle round (1-based). Pure — returns new state. */\nexport function recordSecondary(pg: PlayerGame, round: number, vp: number): PlayerGame {\n const i = roundIndex(round);\n const rounds = pg.rounds.map((c, idx) =>\n idx === i ? { ...c, secondary: c.secondary + Math.max(0, vp) } : c,\n );\n return { ...pg, rounds };\n}\n\n/**\n * Score a held secondary: add its VP to the round, append it to the log, and\n * discard it from hand. Pure. The caller computes `vp` via\n * {@link scoreSecondaryEvent}.\n */\nexport function scoreSecondary(\n pg: PlayerGame,\n round: number,\n cardId: string,\n vp: number,\n): PlayerGame {\n const banked = Math.max(0, vp);\n const recorded = recordSecondary(pg, round, banked);\n return {\n ...removeFromHand(recorded, cardId),\n log: [...pg.log, { cardId, round, vp: banked }],\n };\n}\n\n/**\n * Undo a logged scoring by index: subtract its VP from its round, drop the log\n * entry, and return the card to hand so it can be re-scored. Pure; a no-op for\n * an out-of-range index.\n */\nexport function removeScore(pg: PlayerGame, index: number): PlayerGame {\n const entry = pg.log[index];\n if (!entry) return pg;\n const i = roundIndex(entry.round);\n const rounds = pg.rounds.map((c, idx) =>\n idx === i ? { ...c, secondary: Math.max(0, c.secondary - entry.vp) } : c,\n );\n const log = pg.log.filter((_, idx) => idx !== index);\n const handIds = pg.handIds.includes(entry.cardId)\n ? pg.handIds\n : [...pg.handIds, entry.cardId];\n return { ...pg, rounds, log, handIds };\n}\n\n/** Set primary VP for a battle round (1-based) to a clamped value. Pure. */\nexport function setPrimary(pg: PlayerGame, round: number, vp: number): PlayerGame {\n const i = roundIndex(round);\n const rounds = pg.rounds.map((c, idx) =>\n idx === i ? { ...c, primary: Math.max(0, vp) } : c,\n );\n return { ...pg, rounds };\n}\n\n/** Put a drawn card in hand (no duplicates). Pure. */\nexport function addToHand(pg: PlayerGame, cardId: string): PlayerGame {\n if (pg.handIds.includes(cardId)) return pg;\n return { ...pg, handIds: [...pg.handIds, cardId] };\n}\n\n/** Remove a card from hand (e.g. on score or discard). Pure. */\nexport function removeFromHand(pg: PlayerGame, cardId: string): PlayerGame {\n return { ...pg, handIds: pg.handIds.filter((id) => id !== cardId) };\n}\n\n/** Total primary VP across the game. */\nexport function playerPrimary(pg: PlayerGame): number {\n return pg.rounds.reduce((sum, c) => sum + c.primary, 0);\n}\n\n/** Total secondary VP across the game. */\nexport function playerSecondary(pg: PlayerGame): number {\n return pg.rounds.reduce((sum, c) => sum + c.secondary, 0);\n}\n\n/** Grand total VP, capped at {@link GAME_VP_CAP}. */\nexport function playerTotal(pg: PlayerGame): number {\n return Math.min(GAME_VP_CAP, playerPrimary(pg) + playerSecondary(pg));\n}\n\n/**\n * The WTC 20-point result from two grand totals. The winner's margin maps onto\n * 11 bands (0-5 → 10-10 draw, 6-10 → 11-9, ... 51+ → 20-0); the loser gets the\n * complement. `a`/`b` correspond to the argument order.\n */\nexport function wtcResult(totalA: number, totalB: number): { a: number; b: number } {\n const diff = Math.abs(totalA - totalB);\n const band = diff <= 5 ? 0 : Math.min(10, Math.ceil((diff - 5) / 5));\n const winner = 10 + band;\n const loser = 10 - band;\n if (totalA === totalB) return { a: 10, b: 10 };\n return totalA > totalB ? { a: winner, b: loser } : { a: loser, b: winner };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../../src/translate/condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAWD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../../src/translate/condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAWD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAwItD"}
|
|
@@ -107,6 +107,10 @@ export function describeCondition(c) {
|
|
|
107
107
|
s += " while on an objective";
|
|
108
108
|
return s;
|
|
109
109
|
}
|
|
110
|
+
case "destroyed-in-tagged-terrain": {
|
|
111
|
+
const where = p.at_start_of_turn ? "that started the turn in" : "while in";
|
|
112
|
+
return `${negate}${count(p.count_min ?? 1, "enemy unit")} destroyed ${where} ${dekebab(str(p.tag))} terrain`;
|
|
113
|
+
}
|
|
110
114
|
case "action-completed": {
|
|
111
115
|
let s = `${negate}${count(p.count_min ?? 1, "action")} completed`;
|
|
112
116
|
if (p.action_id != null)
|