@johnmorrisdotca/houseki 0.4.1 → 0.4.2

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +77 -95
  3. package/dist/colour-chains/challenge.d.ts +12 -1
  4. package/dist/colour-chains/challenge.js +12 -1
  5. package/dist/colour-chains/content-types.d.ts +112 -0
  6. package/dist/colour-chains/content.d.ts +140 -3
  7. package/dist/colour-chains/content.js +140 -3
  8. package/dist/colour-chains/engine.d.ts +85 -6
  9. package/dist/colour-chains/engine.js +85 -6
  10. package/dist/colour-chains/input.d.ts +97 -7
  11. package/dist/colour-chains/input.js +97 -7
  12. package/dist/colour-chains/persistence.d.ts +36 -3
  13. package/dist/colour-chains/persistence.js +36 -3
  14. package/dist/colour-chains/types.d.ts +291 -17
  15. package/dist/colour-chains/validation.d.ts +12 -1
  16. package/dist/colour-chains/validation.js +12 -1
  17. package/dist/falling-triplets/content-types.d.ts +69 -0
  18. package/dist/falling-triplets/content.d.ts +60 -3
  19. package/dist/falling-triplets/content.js +60 -3
  20. package/dist/falling-triplets/engine.d.ts +122 -10
  21. package/dist/falling-triplets/engine.js +122 -10
  22. package/dist/falling-triplets/input.d.ts +61 -5
  23. package/dist/falling-triplets/input.js +61 -5
  24. package/dist/falling-triplets/match.d.ts +26 -2
  25. package/dist/falling-triplets/match.js +26 -2
  26. package/dist/falling-triplets/random.d.ts +34 -3
  27. package/dist/falling-triplets/random.js +34 -3
  28. package/dist/falling-triplets/types.d.ts +227 -3
  29. package/dist/gem-swap/content.d.ts +116 -0
  30. package/dist/gem-swap/content.js +72 -0
  31. package/dist/gem-swap/engine.d.ts +124 -9
  32. package/dist/gem-swap/engine.js +124 -9
  33. package/dist/gem-swap/persistence.d.ts +60 -4
  34. package/dist/gem-swap/persistence.js +60 -4
  35. package/dist/gem-swap/types.d.ts +336 -3
  36. package/dist/magnetic-blocks/content-types.d.ts +56 -0
  37. package/dist/magnetic-blocks/content.d.ts +91 -5
  38. package/dist/magnetic-blocks/content.js +91 -5
  39. package/dist/magnetic-blocks/engine.d.ts +63 -5
  40. package/dist/magnetic-blocks/engine.js +63 -5
  41. package/dist/magnetic-blocks/persistence.d.ts +36 -3
  42. package/dist/magnetic-blocks/persistence.js +36 -3
  43. package/dist/magnetic-blocks/physics.d.ts +176 -6
  44. package/dist/magnetic-blocks/physics.js +176 -6
  45. package/dist/magnetic-blocks/types.d.ts +185 -1
  46. package/dist/magnetic-blocks/validation.d.ts +12 -0
  47. package/dist/magnetic-blocks/validation.js +12 -0
  48. package/dist/nature/attraction.d.ts +24 -2
  49. package/dist/nature/attraction.js +24 -2
  50. package/dist/nature/environment.d.ts +200 -7
  51. package/dist/nature/environment.js +88 -7
  52. package/dist/nature/marking.d.ts +13 -1
  53. package/dist/nature/marking.js +13 -1
  54. package/dist/nature/rebound.d.ts +30 -2
  55. package/dist/nature/rebound.js +30 -2
  56. package/dist/nature/state.d.ts +11 -0
  57. package/dist/nature/state.js +11 -0
  58. package/dist/nature/types.d.ts +194 -1
  59. package/dist/nature/validation.d.ts +12 -0
  60. package/dist/nature/validation.js +12 -0
  61. package/dist/stone-collapse/content-types.d.ts +69 -0
  62. package/dist/stone-collapse/content.d.ts +60 -3
  63. package/dist/stone-collapse/content.js +60 -3
  64. package/dist/stone-collapse/engine.d.ts +99 -8
  65. package/dist/stone-collapse/engine.js +99 -8
  66. package/dist/stone-collapse/persistence.d.ts +36 -3
  67. package/dist/stone-collapse/persistence.js +36 -3
  68. package/dist/stone-collapse/types.d.ts +220 -3
  69. package/dist/stone-collapse/validation.d.ts +12 -1
  70. package/dist/stone-collapse/validation.js +12 -1
  71. package/package.json +34 -26
@@ -1,19 +1,110 @@
1
1
  import type { Action, ChallengeOptions, CreateOptions, GameState, GameStatus, Stone, Transition } from './types.js';
2
2
  /** @internal Constructs the generator's bounded valid-pair fallback for direct invariant checks. */
3
3
  export declare function fallbackBoard(mask: readonly boolean[], width: number, height: number, colourCount: number): readonly (Stone | null)[];
4
- /** Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair. */
4
+ /** Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair.
5
+ *
6
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
7
+ * @returns Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair.
8
+ * @example
9
+ * ```ts
10
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
11
+ *
12
+ * console.log(createGame({seed:"docs"}).phase);
13
+ * ```
14
+ */
5
15
  export declare function createGame(options?: CreateOptions): GameState;
6
- /** Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group. */
16
+ /** Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group.
17
+ *
18
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
19
+ * @returns Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group.
20
+ * @example
21
+ * ```ts
22
+ * import { createChallenge, levelManifest } from "@johnmorrisdotca/houseki/stone-collapse";
23
+ *
24
+ * const level=levelManifest[0];
25
+ * console.log(createChallenge({id:level.id,seed:level.seed,width:level.width,height:level.height,colourCount:level.colourCount,initialBoard:level.board,goal:level.goal,moveLimit:level.moveLimit,witness:level.witness}).phase);
26
+ * ```
27
+ */
7
28
  export declare function createChallenge(options: ChallengeOptions): GameState;
8
- /** Applies a selection, confirmation, or cancellation without mutating its input. */
29
+ /** Applies a selection, confirmation, or cancellation without mutating its input.
30
+ *
31
+ * @param state - The immutable native state to read or transition; the input is retained.
32
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
33
+ * @returns Applies a selection, confirmation, or cancellation without mutating its input.
34
+ * @example
35
+ * ```ts
36
+ * import { applyAction, createGame } from "@johnmorrisdotca/houseki/stone-collapse";
37
+ * import type { Action } from "@johnmorrisdotca/houseki/stone-collapse";
38
+ *
39
+ * const state=createGame({seed:"docs"});
40
+ * const action: Action={kind:"hint"};
41
+ * console.log(applyAction(state,action).accepted);
42
+ * ```
43
+ */
9
44
  export declare function applyAction(state: GameState, action: Action): Transition;
10
- /** Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted. */
45
+ /** Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted.
46
+ *
47
+ * @param state - The immutable native state to read or transition; the input is retained.
48
+ * @returns Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted.
49
+ * @example
50
+ * ```ts
51
+ * import { createGame, requestHint } from "@johnmorrisdotca/houseki/stone-collapse";
52
+ *
53
+ * const state=createGame({seed:"docs"});
54
+ * console.log(requestHint(state).accepted);
55
+ * ```
56
+ */
11
57
  export declare function requestHint(state: GameState): Transition;
12
- /** Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted. */
58
+ /** Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted.
59
+ *
60
+ * @param state - The immutable native state to read or transition; the input is retained.
61
+ * @returns Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted.
62
+ * @example
63
+ * ```ts
64
+ * import { createGame, undo } from "@johnmorrisdotca/houseki/stone-collapse";
65
+ *
66
+ * const state=createGame({seed:"docs"});
67
+ * console.log(undo(state).accepted);
68
+ * ```
69
+ */
13
70
  export declare function undo(state: GameState): Transition;
14
- /** Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks. */
71
+ /** Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks.
72
+ *
73
+ * @param state - The immutable native state to read or transition; the input is retained.
74
+ * @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
75
+ * @returns Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks.
76
+ * @example
77
+ * ```ts
78
+ * import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/stone-collapse";
79
+ *
80
+ * const state=createGame({seed:"docs"});
81
+ * console.log(advanceTicks(state,1).state.phase);
82
+ * ```
83
+ */
15
84
  export declare function advanceTicks(state: GameState, ticks: number): Transition;
16
- /** Lists every selection and confirmation currently accepted by the rules. */
85
+ /** Lists every selection and confirmation currently accepted by the rules.
86
+ *
87
+ * @param state - The immutable native state to read or transition; the input is retained.
88
+ * @returns Lists every selection and confirmation currently accepted by the rules.
89
+ * @example
90
+ * ```ts
91
+ * import { createGame, legalActions } from "@johnmorrisdotca/houseki/stone-collapse";
92
+ *
93
+ * const state=createGame({seed:"docs"});
94
+ * console.log(legalActions(state).length);
95
+ * ```
96
+ */
17
97
  export declare function legalActions(state: GameState): readonly Action[];
18
- /** Returns the stable public game status and the remaining-stone count. */
98
+ /** Returns the stable public game status and the remaining-stone count.
99
+ *
100
+ * @param state - The immutable native state to read or transition; the input is retained.
101
+ * @returns Returns the stable public game status and the remaining-stone count.
102
+ * @example
103
+ * ```ts
104
+ * import { createGame, statusOf } from "@johnmorrisdotca/houseki/stone-collapse";
105
+ *
106
+ * const state=createGame({seed:"docs"});
107
+ * console.log(statusOf(state).phase);
108
+ * ```
109
+ */
19
110
  export declare function statusOf(state: GameState): GameStatus;
@@ -105,7 +105,17 @@ function baseState(settings, board, randomState, challenge, usedFallback = false
105
105
  selectedTool: null, toolTarget: null, toolPreview: Object.freeze([]),
106
106
  };
107
107
  }
108
- /** Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair. */
108
+ /** Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair.
109
+ *
110
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
111
+ * @returns Creates a seeded full board; an all-singleton draw retries before using a checked adjacent pair.
112
+ * @example
113
+ * ```ts
114
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
115
+ *
116
+ * console.log(createGame({seed:"docs"}).phase);
117
+ * ```
118
+ */
109
119
  export function createGame(options = {}) {
110
120
  const valid = optionsFor(options); // All settings are checked before drawing any random values.
111
121
  let randomState = hashSeed(`stone-collapse|${RULES}|${String(valid.seed)}`);
@@ -140,7 +150,18 @@ export function createGame(options = {}) {
140
150
  const state = baseState(settings, board, randomState, null, usedFallback);
141
151
  return { ...state, nextId };
142
152
  }
143
- /** Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group. */
153
+ /** Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group.
154
+ *
155
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
156
+ * @returns Creates a fixed witnessed challenge after validating its board, objective, move budget, and every witness group.
157
+ * @example
158
+ * ```ts
159
+ * import { createChallenge, levelManifest } from "@johnmorrisdotca/houseki/stone-collapse";
160
+ *
161
+ * const level=levelManifest[0];
162
+ * console.log(createChallenge({id:level.id,seed:level.seed,width:level.width,height:level.height,colourCount:level.colourCount,initialBoard:level.board,goal:level.goal,moveLimit:level.moveLimit,witness:level.witness}).phase);
163
+ * ```
164
+ */
144
165
  export function createChallenge(options) {
145
166
  if (!options || typeof options !== 'object' || Array.isArray(options))
146
167
  throw new StoneCollapseOptionsError('invalid-challenge', 'Challenge options must be an object');
@@ -466,13 +487,61 @@ function applyCore(state, action) {
466
487
  }
467
488
  return confirmSelected(state);
468
489
  }
469
- /** Applies a selection, confirmation, or cancellation without mutating its input. */
490
+ /** Applies a selection, confirmation, or cancellation without mutating its input.
491
+ *
492
+ * @param state - The immutable native state to read or transition; the input is retained.
493
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
494
+ * @returns Applies a selection, confirmation, or cancellation without mutating its input.
495
+ * @example
496
+ * ```ts
497
+ * import { applyAction, createGame } from "@johnmorrisdotca/houseki/stone-collapse";
498
+ * import type { Action } from "@johnmorrisdotca/houseki/stone-collapse";
499
+ *
500
+ * const state=createGame({seed:"docs"});
501
+ * const action: Action={kind:"hint"};
502
+ * console.log(applyAction(state,action).accepted);
503
+ * ```
504
+ */
470
505
  export function applyAction(state, action) { return applyCore(state, action); }
471
- /** Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted. */
506
+ /** Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted.
507
+ *
508
+ * @param state - The immutable native state to read or transition; the input is retained.
509
+ * @returns Selects the next supplied witness group only while the run still matches its path; accepted hints mark the run assisted.
510
+ * @example
511
+ * ```ts
512
+ * import { createGame, requestHint } from "@johnmorrisdotca/houseki/stone-collapse";
513
+ *
514
+ * const state=createGame({seed:"docs"});
515
+ * console.log(requestHint(state).accepted);
516
+ * ```
517
+ */
472
518
  export function requestHint(state) { return applyCore(state, { kind: 'hint' }); }
473
- /** Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted. */
519
+ /** Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted.
520
+ *
521
+ * @param state - The immutable native state to read or transition; the input is retained.
522
+ * @returns Restores the full pre-move state in Relaxed or Challenge practice and permanently marks the attempt assisted.
523
+ * @example
524
+ * ```ts
525
+ * import { createGame, undo } from "@johnmorrisdotca/houseki/stone-collapse";
526
+ *
527
+ * const state=createGame({seed:"docs"});
528
+ * console.log(undo(state).accepted);
529
+ * ```
530
+ */
474
531
  export function undo(state) { return undoCore(state); }
475
- /** Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks. */
532
+ /** Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks.
533
+ *
534
+ * @param state - The immutable native state to read or transition; the input is retained.
535
+ * @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
536
+ * @returns Advances the observable 7/6/9 tick removal and gravity stages, bounded to 3600 ticks.
537
+ * @example
538
+ * ```ts
539
+ * import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/stone-collapse";
540
+ *
541
+ * const state=createGame({seed:"docs"});
542
+ * console.log(advanceTicks(state,1).state.phase);
543
+ * ```
544
+ */
476
545
  export function advanceTicks(state, ticks) {
477
546
  if (!Number.isInteger(ticks) || ticks < 0 || ticks > 3600)
478
547
  throw new RangeError('ticks must be an integer from 0 to 3600');
@@ -521,7 +590,18 @@ export function advanceTicks(state, ticks) {
521
590
  }
522
591
  return { state: current, events: Object.freeze(events), accepted: true };
523
592
  }
524
- /** Lists every selection and confirmation currently accepted by the rules. */
593
+ /** Lists every selection and confirmation currently accepted by the rules.
594
+ *
595
+ * @param state - The immutable native state to read or transition; the input is retained.
596
+ * @returns Lists every selection and confirmation currently accepted by the rules.
597
+ * @example
598
+ * ```ts
599
+ * import { createGame, legalActions } from "@johnmorrisdotca/houseki/stone-collapse";
600
+ *
601
+ * const state=createGame({seed:"docs"});
602
+ * console.log(legalActions(state).length);
603
+ * ```
604
+ */
525
605
  export function legalActions(state) {
526
606
  if (state.phase === 'won' || state.phase === 'finished' || state.phase === 'lost')
527
607
  return canUndo(state) ? [{ kind: 'undo' }] : [];
@@ -564,7 +644,18 @@ export function legalActions(state) {
564
644
  actions.push({ kind: 'undo' });
565
645
  return actions;
566
646
  }
567
- /** Returns the stable public game status and the remaining-stone count. */
647
+ /** Returns the stable public game status and the remaining-stone count.
648
+ *
649
+ * @param state - The immutable native state to read or transition; the input is retained.
650
+ * @returns Returns the stable public game status and the remaining-stone count.
651
+ * @example
652
+ * ```ts
653
+ * import { createGame, statusOf } from "@johnmorrisdotca/houseki/stone-collapse";
654
+ *
655
+ * const state=createGame({seed:"docs"});
656
+ * console.log(statusOf(state).phase);
657
+ * ```
658
+ */
568
659
  export function statusOf(state) {
569
660
  return { mode: state.settings.mode, phase: state.phase, score: state.score, moves: state.moves, removed: state.removed, remaining: state.board.filter(Boolean).length, previewScore: state.previewScore, usedFallback: state.usedFallback, assisted: state.assisted, inventory: state.inventory, toolProgress: state.toolProgress, toolAwardCursor: state.toolAwardCursor, selectedTool: state.selectedTool, toolTarget: state.toolTarget, toolPreview: state.toolPreview, ...(state.settings.goal ? { goal: state.settings.goal } : {}), ...(state.reason ? { reason: state.reason } : {}) };
570
661
  }
@@ -1,7 +1,40 @@
1
1
  import type { GameState } from './types.js';
2
- /** Starts a fresh attempt from the identical seeded board or preserved challenge definition. */
2
+ /** Starts a fresh attempt from the identical seeded board or preserved challenge definition.
3
+ *
4
+ * @param state - The immutable native state to read or transition; the input is retained.
5
+ * @returns Starts a fresh attempt from the identical seeded board or preserved challenge definition.
6
+ * @example
7
+ * ```ts
8
+ * import { createGame, restartGame } from "@johnmorrisdotca/houseki/stone-collapse";
9
+ *
10
+ * const state=createGame({seed:"docs"});
11
+ * console.log(restartGame(state).phase);
12
+ * ```
13
+ */
3
14
  export declare function restartGame(state: GameState): GameState;
4
- /** Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint. */
15
+ /** Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint.
16
+ *
17
+ * @param state - The immutable native state to read or transition; the input is retained.
18
+ * @returns Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint.
19
+ * @example
20
+ * ```ts
21
+ * import { createGame, encodeGame } from "@johnmorrisdotca/houseki/stone-collapse";
22
+ *
23
+ * const state=createGame({seed:"docs"});
24
+ * console.log(encodeGame(state).length);
25
+ * ```
26
+ */
5
27
  export declare function encodeGame(state: GameState): string;
6
- /** Reconstructs and validates a bounded replay before accepting its checkpoint. */
28
+ /** Reconstructs and validates a bounded replay before accepting its checkpoint.
29
+ *
30
+ * @param text - A saved JSON recording from this entry’s encodeGame; malformed or inconsistent saves throw.
31
+ * @returns Reconstructs and validates a bounded replay before accepting its checkpoint.
32
+ * @example
33
+ * ```ts
34
+ * import { createGame, decodeGame, encodeGame } from "@johnmorrisdotca/houseki/stone-collapse";
35
+ *
36
+ * const state=createGame({seed:"docs"});
37
+ * console.log(decodeGame(encodeGame(state)).phase);
38
+ * ```
39
+ */
7
40
  export declare function decodeGame(text: string): GameState;
@@ -35,7 +35,18 @@ function groupAt(board, settings, start) {
35
35
  }
36
36
  return [...found].sort((a, b) => a - b);
37
37
  }
38
- /** Starts a fresh attempt from the identical seeded board or preserved challenge definition. */
38
+ /** Starts a fresh attempt from the identical seeded board or preserved challenge definition.
39
+ *
40
+ * @param state - The immutable native state to read or transition; the input is retained.
41
+ * @returns Starts a fresh attempt from the identical seeded board or preserved challenge definition.
42
+ * @example
43
+ * ```ts
44
+ * import { createGame, restartGame } from "@johnmorrisdotca/houseki/stone-collapse";
45
+ *
46
+ * const state=createGame({seed:"docs"});
47
+ * console.log(restartGame(state).phase);
48
+ * ```
49
+ */
39
50
  export function restartGame(state) {
40
51
  if (state.settings.mode === 'challenge')
41
52
  return createChallenge(state.challenge);
@@ -45,7 +56,18 @@ export function restartGame(state) {
45
56
  const mode = settings.mode === 'arcade' ? 'arcade' : 'relaxed';
46
57
  return createGame({ mode, colourCount: settings.colourCount, seed: settings.seed, tools: settings.tools, ...(settings.shape ? { shape: settings.shape } : { width: settings.width, height: settings.height, ...(settings.mask.every(Boolean) ? {} : { mask: settings.mask }) }) });
47
58
  }
48
- /** Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint. */
59
+ /** Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint.
60
+ *
61
+ * @param state - The immutable native state to read or transition; the input is retained.
62
+ * @returns Encodes the canonical initial configuration, accepted replay actions, and a derived checkpoint.
63
+ * @example
64
+ * ```ts
65
+ * import { createGame, encodeGame } from "@johnmorrisdotca/houseki/stone-collapse";
66
+ *
67
+ * const state=createGame({seed:"docs"});
68
+ * console.log(encodeGame(state).length);
69
+ * ```
70
+ */
49
71
  export function encodeGame(state) {
50
72
  // Undo frames are derived by replaying committed actions; storing their full board snapshots scales poorly on deep boards.
51
73
  const { history: _history, ...checkpoint } = state;
@@ -99,7 +121,18 @@ function stateFromInitial(settings, challenge) {
99
121
  throw new TypeError('Initial settings are not canonical');
100
122
  return state;
101
123
  }
102
- /** Reconstructs and validates a bounded replay before accepting its checkpoint. */
124
+ /** Reconstructs and validates a bounded replay before accepting its checkpoint.
125
+ *
126
+ * @param text - A saved JSON recording from this entry’s encodeGame; malformed or inconsistent saves throw.
127
+ * @returns Reconstructs and validates a bounded replay before accepting its checkpoint.
128
+ * @example
129
+ * ```ts
130
+ * import { createGame, decodeGame, encodeGame } from "@johnmorrisdotca/houseki/stone-collapse";
131
+ *
132
+ * const state=createGame({seed:"docs"});
133
+ * console.log(decodeGame(encodeGame(state)).phase);
134
+ * ```
135
+ */
103
136
  export function decodeGame(text) {
104
137
  if (typeof text !== 'string' || new TextEncoder().encode(text).length > 2 * 1024 * 1024)
105
138
  throw new RangeError('Save must be text no larger than 2 MiB');
@@ -1,19 +1,111 @@
1
- /** A colour used by a stone. */
1
+ /** A colour used by a stone.
2
+ *
3
+ * @example
4
+ * ```ts
5
+ * import type { StoneColour } from "@johnmorrisdotca/houseki/stone-collapse";
6
+ *
7
+ * const value: StoneColour = "red";
8
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
9
+ * ```
10
+ */
2
11
  export type StoneColour = 'red' | 'blue' | 'green' | 'gold' | 'purple' | 'teal';
3
- /** A stone keeps its run-local identity as it falls or changes column. */
12
+ /** A stone keeps its run-local identity as it falls or changes column.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import type { Stone } from "@johnmorrisdotca/houseki/stone-collapse";
17
+ *
18
+ * const value: Stone = {id:1,colour:"red"};
19
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
20
+ * ```
21
+ */
4
22
  export interface Stone {
5
23
  readonly id: number;
6
24
  readonly colour: StoneColour;
7
25
  }
26
+ /** A named native board geometry; custom dimensions remain a separate option.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import type { BoardPreset } from "@johnmorrisdotca/houseki/stone-collapse";
31
+ *
32
+ * const value: BoardPreset = "compact";
33
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
34
+ * ```
35
+ */
8
36
  export type BoardPreset = 'compact' | 'standard' | 'wide' | 'tall' | 'extraWide' | 'deep' | 'large';
37
+ /** A native shaped active-cell layout applied to the row-major board.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import type { BoardShape } from "@johnmorrisdotca/houseki/stone-collapse";
42
+ *
43
+ * const value: BoardShape = "heart";
44
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
45
+ * ```
46
+ */
9
47
  export type BoardShape = 'heart' | 'star' | 'hexagon';
48
+ /** The native free, timed, daily or authored-challenge game mode.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import type { GameMode } from "@johnmorrisdotca/houseki/stone-collapse";
53
+ *
54
+ * const value: GameMode = "relaxed";
55
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
56
+ * ```
57
+ */
10
58
  export type GameMode = 'relaxed' | 'arcade' | 'daily' | 'challenge';
59
+ /** A stored Stone Collapse tool selected from the native Bomb and Pick tray.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * import type { StoredTool } from "@johnmorrisdotca/houseki/stone-collapse";
64
+ *
65
+ * const value: StoredTool = "bomb";
66
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
67
+ * ```
68
+ */
11
69
  export type StoredTool = 'bomb' | 'pick';
70
+ /** The native remaining counts of stored tools.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
75
+ * import type { ToolInventory } from "@johnmorrisdotca/houseki/stone-collapse";
76
+ *
77
+ * const state=createGame({seed:"docs"});
78
+ * const value: ToolInventory = state.inventory;
79
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
80
+ * ```
81
+ */
12
82
  export interface ToolInventory {
13
83
  readonly bomb: number;
14
84
  readonly pick: number;
15
85
  }
86
+ /** The native ready, resolution and ending phases.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
91
+ * import type { GamePhase } from "@johnmorrisdotca/houseki/stone-collapse";
92
+ *
93
+ * const state=createGame({seed:"docs"});
94
+ * const value: GamePhase = state.phase;
95
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
96
+ * ```
97
+ */
16
98
  export type GamePhase = 'ready' | 'clear-mark' | 'clear-remove' | 'gravity' | 'won' | 'lost' | 'finished';
99
+ /** A native authored challenge objective; its discriminant selects target, chain, empty-board or score requirements.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import type { ChallengeGoal } from "@johnmorrisdotca/houseki/stone-collapse";
104
+ *
105
+ * const value: ChallengeGoal = {kind:"clear-all"};
106
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
107
+ * ```
108
+ */
17
109
  export type ChallengeGoal = {
18
110
  readonly kind: 'clear-all';
19
111
  } | {
@@ -23,6 +115,18 @@ export type ChallengeGoal = {
23
115
  readonly kind: 'score-target';
24
116
  readonly minimumScore: number;
25
117
  };
118
+ /** Validated settings fixed at native game creation.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
123
+ * import type { Settings } from "@johnmorrisdotca/houseki/stone-collapse";
124
+ *
125
+ * const state=createGame({seed:"docs"});
126
+ * const value: Settings = state.settings;
127
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
128
+ * ```
129
+ */
26
130
  export interface Settings {
27
131
  readonly mode: GameMode;
28
132
  readonly width: number;
@@ -37,6 +141,18 @@ export interface Settings {
37
141
  readonly moveLimit?: number;
38
142
  readonly tools: boolean;
39
143
  }
144
+ /** A validated Stone Collapse authored setup and stable-id group witness.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
149
+ * import type { ChallengeDefinition } from "@johnmorrisdotca/houseki/stone-collapse";
150
+ *
151
+ * const state=createGame({seed:"docs"});
152
+ * const value: ChallengeDefinition = {id:"docs",width:state.settings.width,height:state.settings.height,colourCount:4,seed:"docs",mask:state.settings.mask,initialBoard:state.board,goal:{kind:"clear-all"},witness:[]};
153
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
154
+ * ```
155
+ */
40
156
  export interface ChallengeDefinition {
41
157
  readonly id: string;
42
158
  readonly width: number;
@@ -50,7 +166,18 @@ export interface ChallengeDefinition {
50
166
  /** Each entry is the complete stable-ID set of the next witnessed group. */
51
167
  readonly witness: readonly (readonly number[])[];
52
168
  }
53
- /** Data sufficient to restore the complete game immediately before a committed move. */
169
+ /** Data sufficient to restore the complete game immediately before a committed move.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
174
+ * import type { UndoFrame } from "@johnmorrisdotca/houseki/stone-collapse";
175
+ *
176
+ * const state=createGame({seed:"docs"});
177
+ * const value: UndoFrame = {board:state.board,score:0,moves:0,removed:0,randomState:state.randomState,nextId:state.nextId,usedFallback:false,finishAdjustmentApplied:false,selectedId:null,selectedIds:[],previewScore:0,witnessIndex:0,inventory:state.inventory,toolProgress:0,toolAwardCursor:0,selectedTool:null,toolTarget:null,toolPreview:[]};
178
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
179
+ * ```
180
+ */
54
181
  export interface UndoFrame {
55
182
  readonly board: readonly (Stone | null)[];
56
183
  readonly score: number;
@@ -71,6 +198,16 @@ export interface UndoFrame {
71
198
  readonly toolTarget: number | null;
72
199
  readonly toolPreview: readonly number[];
73
200
  }
201
+ /** A native action recording with the logical position needed for deterministic replay.
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * import type { RecordedAction } from "@johnmorrisdotca/houseki/stone-collapse";
206
+ *
207
+ * const value: RecordedAction = {kind:"ticks",count:1};
208
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
209
+ * ```
210
+ */
74
211
  export type RecordedAction = {
75
212
  readonly kind: 'remove';
76
213
  readonly move: number;
@@ -96,6 +233,18 @@ export type RecordedAction = {
96
233
  readonly kind: 'ticks';
97
234
  readonly count: number;
98
235
  };
236
+ /** The immutable authoritative native game state, including its board, random state and recording.
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
241
+ * import type { GameState } from "@johnmorrisdotca/houseki/stone-collapse";
242
+ *
243
+ * const state=createGame({seed:"docs"});
244
+ * const value: GameState = state;
245
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
246
+ * ```
247
+ */
99
248
  export interface GameState {
100
249
  readonly game: 'stone-collapse';
101
250
  readonly rules: 'collapse-2';
@@ -136,6 +285,17 @@ export interface GameState {
136
285
  /** Exact row-major cells affected by the current target. */
137
286
  readonly toolPreview: readonly number[];
138
287
  }
288
+ /** A native player action accepted or rejected according to the current phase and rules.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * import type { Action } from "@johnmorrisdotca/houseki/stone-collapse";
293
+ *
294
+ * const action: Action={kind:"hint"};
295
+ * const value: Action = action;
296
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
297
+ * ```
298
+ */
139
299
  export type Action = {
140
300
  readonly kind: 'select';
141
301
  readonly stoneId: number;
@@ -158,16 +318,49 @@ export type Action = {
158
318
  } | {
159
319
  readonly kind: 'cancel-tool';
160
320
  };
321
+ /** An event emitted by one native transition; type selects the event’s additional fields.
322
+ *
323
+ * @example
324
+ * ```ts
325
+ * import type { GameEvent } from "@johnmorrisdotca/houseki/stone-collapse";
326
+ *
327
+ * const value: GameEvent = {type:"host-example"};
328
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
329
+ * ```
330
+ */
161
331
  export interface GameEvent {
162
332
  readonly type: string;
163
333
  readonly [key: string]: unknown;
164
334
  }
335
+ /** The resulting native state, emitted events and acceptance decision; rejected actions preserve the input.
336
+ *
337
+ * @example
338
+ * ```ts
339
+ * import { applyAction, createGame } from "@johnmorrisdotca/houseki/stone-collapse";
340
+ * import type { Action, Transition } from "@johnmorrisdotca/houseki/stone-collapse";
341
+ *
342
+ * const state=createGame({seed:"docs"});
343
+ * const action: Action={kind:"hint"};
344
+ * const value: Transition = applyAction(state,action);
345
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
346
+ * ```
347
+ */
165
348
  export interface Transition {
166
349
  readonly state: GameState;
167
350
  readonly events: readonly GameEvent[];
168
351
  readonly accepted: boolean;
169
352
  readonly reason?: string;
170
353
  }
354
+ /** Creation settings for this native engine; dimensions, mode, seed and optional mechanics are validated together.
355
+ *
356
+ * @example
357
+ * ```ts
358
+ * import type { CreateOptions } from "@johnmorrisdotca/houseki/stone-collapse";
359
+ *
360
+ * const value: CreateOptions = {seed:"docs"};
361
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
362
+ * ```
363
+ */
171
364
  export interface CreateOptions {
172
365
  readonly mode?: Exclude<GameMode, 'challenge'>;
173
366
  readonly preset?: BoardPreset;
@@ -183,6 +376,18 @@ export interface CreateOptions {
183
376
  /** Optional Bomb and Pick tray; available only in Relaxed and Arcade. */
184
377
  readonly tools?: boolean;
185
378
  }
379
+ /** Authored challenge inputs including the starting board, finite goal and supplied witness.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * import { createGame } from "@johnmorrisdotca/houseki/stone-collapse";
384
+ * import type { ChallengeOptions } from "@johnmorrisdotca/houseki/stone-collapse";
385
+ *
386
+ * const state=createGame({seed:"docs"});
387
+ * const value: ChallengeOptions = {id:"docs",width:6,height:6,colourCount:4,initialBoard:state.board,goal:{kind:"clear-all"},witness:[]};
388
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
389
+ * ```
390
+ */
186
391
  export interface ChallengeOptions {
187
392
  readonly id: string;
188
393
  readonly width: number;
@@ -195,6 +400,18 @@ export interface ChallengeOptions {
195
400
  readonly moveLimit?: number;
196
401
  readonly witness: readonly (readonly number[])[];
197
402
  }
403
+ /** A compact native status derived from the authoritative state for a host’s labels.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * import { createGame, statusOf } from "@johnmorrisdotca/houseki/stone-collapse";
408
+ * import type { GameStatus } from "@johnmorrisdotca/houseki/stone-collapse";
409
+ *
410
+ * const state=createGame({seed:"docs"});
411
+ * const value: GameStatus = statusOf(state);
412
+ * console.log(value == null ? value : typeof value === "object" ? Object.keys(value).slice(0,6) : value);
413
+ * ```
414
+ */
198
415
  export interface GameStatus {
199
416
  readonly mode: GameMode;
200
417
  readonly phase: GamePhase;