@johnmorrisdotca/houseki 0.2.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.
@@ -14,6 +14,21 @@ export interface ChainDifficultyMetrics {
14
14
  readonly seededPlayoutVariablePrefixLength?: number;
15
15
  /** Number of later witnessed placements held fixed in each seeded playout. */
16
16
  readonly seededPlayoutFixedSuffixLength?: number;
17
+ readonly seededPlayoutPlacements?: number;
18
+ readonly fullPlanSuccessRate?: number;
19
+ readonly witnessedPlanPlacements?: number;
20
+ readonly singleStepDeviationProbes?: number;
21
+ readonly singleStepDeviationWins?: number;
22
+ readonly singleStepDeviationDeadEnds?: number;
23
+ readonly branchingDecisionPoints?: number;
24
+ readonly forcedSafeSteps?: number;
25
+ readonly forcedSafeShare?: number;
26
+ readonly branchingShare?: number;
27
+ readonly consequentialDecisionShare?: number;
28
+ readonly setupDeviationProbes?: number;
29
+ readonly setupDeviationLosses?: number;
30
+ readonly setupDeviationLossShare?: number;
31
+ readonly verifiedSetupDependencyShare?: number;
17
32
  readonly seededPlayoutSuccesses: number;
18
33
  readonly seededPlayoutSuccessRate: number;
19
34
  readonly setupPairsBeforePayoff: number;
@@ -21,7 +36,27 @@ export interface ChainDifficultyMetrics {
21
36
  readonly verifiedSetupDependencies: number;
22
37
  /** Number of pre-payoff steps checked by exhaustive single-step deviations. */
23
38
  readonly setupDependencyProbeSteps?: number;
39
+ /** A verified alternate far-side first placement followed by the witnessed recovery pair. */
40
+ readonly verifiedWrongFirstRecovery?: number;
41
+ readonly goalTargets?: number;
42
+ /** Number of distinct target-color components or explicitly required chain waves. */
43
+ readonly goalDependencyCount?: number;
44
+ readonly occupiedCells?: number;
45
+ readonly usableCells?: number;
46
+ readonly boardCoverage?: number;
47
+ readonly goalCoordinationShare?: number;
48
+ readonly cascadeShare?: number;
49
+ readonly weatherEventCount?: number;
50
+ readonly weatherDependency?: number;
51
+ readonly mechanicOffCounterfactualWon?: boolean;
52
+ readonly mechanicOffCounterfactualKind?: 'nature' | 'magnetism' | 'weather';
53
+ readonly mechanicOffCounterfactualPhase?: string;
54
+ readonly rawDifficultyScore?: number;
24
55
  readonly requiredChainDepth: number;
56
+ /** Highest chain observed in the exact authored witness. */
57
+ readonly witnessedChainDepth?: number;
58
+ /** Highest chain seen in the bounded random-play sample; not a requirement claim. */
59
+ readonly observedPotentialChainDepth?: number;
25
60
  readonly requiredRotations: number;
26
61
  readonly requiredWallKicks: number;
27
62
  readonly splitLandingDependencies: number;
@@ -52,12 +87,16 @@ export interface ChainCampaignLevel {
52
87
  readonly gradingVersion: string;
53
88
  readonly proofStatus: 'engine-witness-verified';
54
89
  readonly reviewStatus: 'human-review-pending' | 'human-reviewed';
90
+ readonly band?: 'entry' | 'easy' | 'intermediate' | 'hard' | 'expert';
91
+ readonly rawDifficultyScore?: number;
92
+ readonly normalizationCategory?: string;
55
93
  }
56
94
  export interface NatureChainCampaignLevel extends ChainCampaignLevel {
57
95
  readonly objective: LocalizedText;
58
96
  readonly nature: true;
59
97
  readonly weather?: 'frequent';
60
98
  readonly magneticQueue?: readonly (readonly [boolean, boolean])[];
99
+ readonly weatherTrace?: readonly Readonly<Record<string, unknown>>[];
61
100
  }
62
101
  export interface ChainCampaignManifest {
63
102
  readonly count: number;
@@ -72,8 +111,15 @@ export interface ChainCampaignManifest {
72
111
  readonly checksum: string;
73
112
  readonly levels: readonly ChainCampaignLevel[];
74
113
  }
114
+ export interface NatureCampaignBand {
115
+ readonly id: 'entry' | 'easy' | 'intermediate' | 'hard' | 'expert';
116
+ readonly count: number;
117
+ readonly first: number;
118
+ readonly last: number;
119
+ }
75
120
  export interface NatureChainCampaignManifest extends Omit<ChainCampaignManifest, 'levels'> {
76
121
  readonly levels: readonly NatureChainCampaignLevel[];
122
+ readonly bands?: readonly NatureCampaignBand[];
77
123
  }
78
124
  export interface ChainTutorialStep {
79
125
  readonly instruction: LocalizedText;
@@ -1,5 +1,4 @@
1
- import type { PowerDropPreview } from '../nature/types.js';
2
- import type { Action, Colour, CreateOptions, GameState, GameStatus, Gem, Landing, Settings, Transition } from './types.js';
1
+ import type { Action, ChainsPowerDropPreview, Colour, CreateOptions, GameState, GameStatus, Gem, Landing, Settings, Transition } from './types.js';
3
2
  export { StoneChainsOptionsError } from './validation.js';
4
3
  /** Applies one immutable accepted action and records its logical-tick position. */
5
4
  export declare function applyAction(state: GameState, action: Action): Transition;
@@ -9,8 +8,15 @@ export declare function advanceTicks(state: GameState, ticks: number): Transitio
9
8
  export declare function legalActions(state: GameState): readonly Action[];
10
9
  /** Returns the exact independent landing cells for the current rigid pair without consuming random values. */
11
10
  export declare function landingCells(state: GameState): Landing | null;
12
- /** Returns the Shizen hard-drop landing and one-step rebound preview without changing state. */
13
- export declare function powerDropPreview(state: GameState): PowerDropPreview | null;
11
+ /**
12
+ * Returns the Shizen hard-drop landing and one-step rebound preview without changing state.
13
+ *
14
+ * `finalCells` is where the pair locks after any rebound, the cells of the `power-drop-landed` event. Stones above a
15
+ * gap then fall, so `settledCells` is where each stone of the pair comes to rest in the board the hard drop commits,
16
+ * before any clear: draw a ghost from it. Both carry the pair's stable stone ids, and both are checked against
17
+ * `applyAction` with a `hard-drop` over many played boards.
18
+ */
19
+ export declare function powerDropPreview(state: GameState): ChainsPowerDropPreview | null;
14
20
  /** Returns score, mode, chain and completion fields derived from state. */
15
21
  export declare function statusOf(state: GameState): GameStatus;
16
22
  /** Creates a base challenge state with a previously validated visible board and pair queue. @internal */
@@ -457,11 +457,26 @@ export function landingCells(state) {
457
457
  const settled = compactBoard(board, state.settings.width, state.settings.height + HIDDEN);
458
458
  return pair.gems.map(gem => { const index = settled.findIndex(cell => cell?.id === gem.id); return { x: index % state.settings.width, y: Math.floor(index / state.settings.width) - HIDDEN }; });
459
459
  }
460
- /** Returns the Shizen hard-drop landing and one-step rebound preview without changing state. */
460
+ /**
461
+ * Returns the Shizen hard-drop landing and one-step rebound preview without changing state.
462
+ *
463
+ * `finalCells` is where the pair locks after any rebound, the cells of the `power-drop-landed` event. Stones above a
464
+ * gap then fall, so `settledCells` is where each stone of the pair comes to rest in the board the hard drop commits,
465
+ * before any clear: draw a ghost from it. Both carry the pair's stable stone ids, and both are checked against
466
+ * `applyAction` with a `hard-drop` over many played boards.
467
+ */
461
468
  export function powerDropPreview(state) {
462
469
  if (!state.settings.nature || state.settings.mode === 'relaxed' || !state.active)
463
470
  return null;
464
- return rebound(state, state.active)?.preview ?? null;
471
+ const preview = rebound(state, state.active)?.preview;
472
+ if (!preview)
473
+ return null;
474
+ const dropped = applyAction(state, { kind: 'hard-drop' });
475
+ const board = dropped.accepted ? (dropped.state.gravityBoard ?? dropped.state.board) : null;
476
+ const settledCells = board
477
+ ? state.active.gems.flatMap(gem => { const index = board.findIndex(cell => cell?.id === gem.id); return index < 0 ? [] : [{ ...(preview.finalCells.find(cell => cell.id === gem.id) ?? { id: gem.id, kind: 'stone', colour: gem.colour }), x: index % state.settings.width, y: Math.floor(index / state.settings.width) - HIDDEN }]; })
478
+ : preview.finalCells;
479
+ return Object.freeze({ ...preview, settledCells: Object.freeze(settledCells) });
465
480
  }
466
481
  /** Returns score, mode, chain and completion fields derived from state. */
467
482
  export function statusOf(state) { return { mode: state.settings.mode, phase: state.phase, score: state.score, maxChain: state.maxChain, allClears: state.allClears, completedPairs: state.completedPairs, assisted: state.assisted, ...(state.reason ? { reason: state.reason } : {}) }; }
@@ -1,3 +1,4 @@
1
+ import type { NaturePieceCell, PowerDropPreview } from '../nature/types.js';
1
2
  /** A gem colour used by Colour Chains. */
2
3
  export type Colour = 'red' | 'blue' | 'green' | 'gold' | 'purple' | 'teal';
3
4
  /** A settled or active stone with a stable run-local identity. */
@@ -193,3 +194,7 @@ export interface GameStatus {
193
194
  }
194
195
  /** Destination cells for the two independently settled ghost stones. */
195
196
  export type Landing = readonly [Cell, Cell];
197
+ /** The Shizen hard-drop preview: the one-step rebound and where the pair locks (`finalCells`), and where each stone of the pair comes to rest once the committed drop's gravity has run (`settledCells`). */
198
+ export interface ChainsPowerDropPreview extends PowerDropPreview {
199
+ readonly settledCells: readonly NaturePieceCell[];
200
+ }
@@ -5,4 +5,4 @@ export { createChallenge } from './colour-chains/challenge.js';
5
5
  export { restartGame, encodeGame, decodeGame } from './colour-chains/persistence.js';
6
6
  export { createInputScheduler, setHeldInput, queueInputEdge, releaseAllInput, actionsForTick, applyScheduledActions, processInputTick } from './colour-chains/input.js';
7
7
  export { campaignManifest, levelManifest, tutorialManifest, getLevel, createLevel, getTutorial, shizenCampaignManifest, shizenLevelManifest, getShizenLevel, createShizenLevel, arashiCampaignManifest, arashiLevelManifest, getArashiLevel, createArashiLevel } from './colour-chains/content.js';
8
- export type { LocalizedText, ChainDifficultyMetrics, ChainCampaignLevel, ChainCampaignManifest, NatureChainCampaignLevel, NatureChainCampaignManifest, ChainTutorialStep, ChainTutorialDefinition, ChainContentData } from './colour-chains/content-types.js';
8
+ export type { LocalizedText, ChainDifficultyMetrics, ChainCampaignLevel, ChainCampaignManifest, NatureChainCampaignLevel, NatureChainCampaignManifest, NatureCampaignBand, ChainTutorialStep, ChainTutorialDefinition, ChainContentData } from './colour-chains/content-types.js';