@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
@@ -8,20 +8,103 @@ function deepFreeze(value) {
8
8
  }
9
9
  return value;
10
10
  }
11
+ /** The frozen native campaign manifest with its ordering, revisions, checksum and measured levels.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { campaignManifest } from "@johnmorrisdotca/houseki/colour-chains";
16
+ *
17
+ * console.log(campaignManifest.count);
18
+ * ```
19
+ */
11
20
  export const campaignManifest = deepFreeze(contentData.campaign);
21
+ /** The frozen ordered native levels; array indices start at zero and display numbers start at one.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { levelManifest } from "@johnmorrisdotca/houseki/colour-chains";
26
+ *
27
+ * console.log(levelManifest.length);
28
+ * ```
29
+ */
12
30
  export const levelManifest = campaignManifest.levels;
31
+ /** The frozen native bilingual lessons and their authored teaching steps.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { tutorialManifest } from "@johnmorrisdotca/houseki/colour-chains";
36
+ *
37
+ * console.log(tutorialManifest.length);
38
+ * ```
39
+ */
13
40
  export const tutorialManifest = deepFreeze(contentData.tutorials);
41
+ /** The ordered native campaign, its generation/grading revisions, checksum and measured levels.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { shizenCampaignManifest } from "@johnmorrisdotca/houseki/colour-chains";
46
+ *
47
+ * console.log(shizenCampaignManifest.count);
48
+ * ```
49
+ */
14
50
  export const shizenCampaignManifest = deepFreeze((contentData.shizen ?? { ...contentData.campaign, count: 0, levels: [], checksum: '' }));
51
+ /** The frozen ordered native levels; array indices start at zero and display numbers start at one.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { shizenLevelManifest } from "@johnmorrisdotca/houseki/colour-chains";
56
+ *
57
+ * console.log(shizenLevelManifest.length);
58
+ * ```
59
+ */
15
60
  export const shizenLevelManifest = shizenCampaignManifest.levels;
61
+ /** The ordered native campaign, its generation/grading revisions, checksum and measured levels.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * import { arashiCampaignManifest } from "@johnmorrisdotca/houseki/colour-chains";
66
+ *
67
+ * console.log(arashiCampaignManifest.count);
68
+ * ```
69
+ */
16
70
  export const arashiCampaignManifest = deepFreeze((contentData.arashi ?? { ...contentData.campaign, count: 0, levels: [], checksum: '' }));
71
+ /** The frozen ordered native levels; array indices start at zero and display numbers start at one.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * import { arashiLevelManifest } from "@johnmorrisdotca/houseki/colour-chains";
76
+ *
77
+ * console.log(arashiLevelManifest.length);
78
+ * ```
79
+ */
17
80
  export const arashiLevelManifest = arashiCampaignManifest.levels;
18
- /** Find a campaign challenge by stable content ID or its current one-based number. */
81
+ /** Find a campaign challenge by stable content ID or its current one-based number.
82
+ *
83
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
84
+ * @returns Find a campaign challenge by stable content ID or its current one-based number. Returns undefined when the id or display number is absent.
85
+ * @example
86
+ * ```ts
87
+ * import { getLevel } from "@johnmorrisdotca/houseki/colour-chains";
88
+ *
89
+ * console.log(getLevel(1)?.id);
90
+ * ```
91
+ */
19
92
  export function getLevel(id) {
20
93
  if (typeof id === 'number')
21
94
  return Number.isInteger(id) ? levelManifest.find(level => level.number === id) : undefined;
22
95
  return levelManifest.find(level => level.id === id);
23
96
  }
24
- /** Create a fresh engine-validated challenge from a stable content ID or display number. */
97
+ /** Create a fresh engine-validated challenge from a stable content ID or display number.
98
+ *
99
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
100
+ * @returns Create a fresh engine-validated challenge from a stable content ID or display number.
101
+ * @example
102
+ * ```ts
103
+ * import { createLevel } from "@johnmorrisdotca/houseki/colour-chains";
104
+ *
105
+ * console.log(createLevel(1).phase);
106
+ * ```
107
+ */
25
108
  export function createLevel(id) {
26
109
  const level = getLevel(id);
27
110
  if (!level)
@@ -31,11 +114,65 @@ export function createLevel(id) {
31
114
  function createNatureLevel(level) {
32
115
  return createChallenge({ id: level.id, seed: level.seed, width: level.width, height: level.height, colourCount: level.colourCount, board: level.board, queue: level.queue, goal: level.goal, witness: level.witness, nature: true, ...(level.weather ? { weather: level.weather } : {}), ...(level.magneticQueue ? { magneticQueue: level.magneticQueue } : {}) });
33
116
  }
117
+ /** Find a native Shizen challenge by stable id or one-based display number.
118
+ *
119
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
120
+ * @returns Find a native Shizen challenge by stable id or one-based display number. Returns undefined when the id or display number is absent.
121
+ * @example
122
+ * ```ts
123
+ * import { getShizenLevel } from "@johnmorrisdotca/houseki/colour-chains";
124
+ *
125
+ * console.log(getShizenLevel(1)?.id);
126
+ * ```
127
+ */
34
128
  export function getShizenLevel(id) { return typeof id === 'number' ? shizenLevelManifest.find(level => level.number === id) : shizenLevelManifest.find(level => level.id === id); }
129
+ /** Create a validated native Shizen challenge using its stored setup and winning witness.
130
+ *
131
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
132
+ * @returns Create a validated native Shizen challenge using its stored setup and winning witness.
133
+ * @example
134
+ * ```ts
135
+ * import { createShizenLevel } from "@johnmorrisdotca/houseki/colour-chains";
136
+ *
137
+ * console.log(createShizenLevel(1).phase);
138
+ * ```
139
+ */
35
140
  export function createShizenLevel(id) { const level = getShizenLevel(id); if (!level)
36
141
  throw new RangeError(`Unknown Shizen Colour Chains level: ${String(id)}`); return createNatureLevel(level); }
142
+ /** Find a native Arashi challenge by stable id or one-based display number.
143
+ *
144
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
145
+ * @returns Find a native Arashi challenge by stable id or one-based display number. Returns undefined when the id or display number is absent.
146
+ * @example
147
+ * ```ts
148
+ * import { getArashiLevel } from "@johnmorrisdotca/houseki/colour-chains";
149
+ *
150
+ * console.log(getArashiLevel(1)?.id);
151
+ * ```
152
+ */
37
153
  export function getArashiLevel(id) { return typeof id === 'number' ? arashiLevelManifest.find(level => level.number === id) : arashiLevelManifest.find(level => level.id === id); }
154
+ /** Create a validated native Arashi challenge using its stored setup and winning witness.
155
+ *
156
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
157
+ * @returns Create a validated native Arashi challenge using its stored setup and winning witness.
158
+ * @example
159
+ * ```ts
160
+ * import { createArashiLevel } from "@johnmorrisdotca/houseki/colour-chains";
161
+ *
162
+ * console.log(createArashiLevel(1).phase);
163
+ * ```
164
+ */
38
165
  export function createArashiLevel(id) { const level = getArashiLevel(id); if (!level)
39
166
  throw new RangeError(`Unknown Arashi Colour Chains level: ${String(id)}`); return createNatureLevel(level); }
40
- /** Find a persistent interactive lesson by its stable ID. */
167
+ /** Find a persistent interactive lesson by its stable ID.
168
+ *
169
+ * @param id - A stable content id, or the one-based display number when numbers are accepted.
170
+ * @returns Find a persistent interactive lesson by its stable ID. Returns undefined when the id or display number is absent.
171
+ * @example
172
+ * ```ts
173
+ * import { getTutorial, tutorialManifest } from "@johnmorrisdotca/houseki/colour-chains";
174
+ *
175
+ * console.log(getTutorial(tutorialManifest[0].id)?.id);
176
+ * ```
177
+ */
41
178
  export function getTutorial(id) { return tutorialManifest.find(tutorial => tutorial.id === id); }
@@ -1,12 +1,60 @@
1
1
  import type { Action, ChainsPowerDropPreview, Colour, CreateOptions, GameState, GameStatus, Gem, Landing, Settings, Transition } from './types.js';
2
2
  export { StoneChainsOptionsError } from './validation.js';
3
- /** Applies one immutable accepted action and records its logical-tick position. */
3
+ /** Applies one immutable accepted action and records its logical-tick position.
4
+ *
5
+ * @param state - The immutable native state to read or transition; the input is retained.
6
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
7
+ * @returns Applies one immutable accepted action and records its logical-tick position.
8
+ * @example
9
+ * ```ts
10
+ * import { applyAction, createGame } from "@johnmorrisdotca/houseki/colour-chains";
11
+ * import type { Action } from "@johnmorrisdotca/houseki/colour-chains";
12
+ *
13
+ * const state=createGame({seed:"docs"});
14
+ * const action: Action={kind:"left"};
15
+ * console.log(applyAction(state,action).accepted);
16
+ * ```
17
+ */
4
18
  export declare function applyAction(state: GameState, action: Action): Transition;
5
- /** Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock. */
19
+ /** Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock.
20
+ *
21
+ * @param state - The immutable native state to read or transition; the input is retained.
22
+ * @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
23
+ * @returns Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock.
24
+ * @example
25
+ * ```ts
26
+ * import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/colour-chains";
27
+ *
28
+ * const state=createGame({seed:"docs"});
29
+ * console.log(advanceTicks(state,1).state.phase);
30
+ * ```
31
+ */
6
32
  export declare function advanceTicks(state: GameState, ticks: number): Transition;
7
- /** Lists only actions accepted by the current game state. */
33
+ /** Lists only actions accepted by the current game state.
34
+ *
35
+ * @param state - The immutable native state to read or transition; the input is retained.
36
+ * @returns Lists only actions accepted by the current game state.
37
+ * @example
38
+ * ```ts
39
+ * import { createGame, legalActions } from "@johnmorrisdotca/houseki/colour-chains";
40
+ *
41
+ * const state=createGame({seed:"docs"});
42
+ * console.log(legalActions(state).length);
43
+ * ```
44
+ */
8
45
  export declare function legalActions(state: GameState): readonly Action[];
9
- /** Returns the exact independent landing cells for the current rigid pair without consuming random values. */
46
+ /** Returns the exact independent landing cells for the current rigid pair without consuming random values.
47
+ *
48
+ * @param state - The immutable native state to read or transition; the input is retained.
49
+ * @returns Returns the exact independent landing cells for the current rigid pair without consuming random values. Returns null when there is no active piece or applicable preview.
50
+ * @example
51
+ * ```ts
52
+ * import { createGame, landingCells } from "@johnmorrisdotca/houseki/colour-chains";
53
+ *
54
+ * const state=createGame({seed:"docs"});
55
+ * console.log(landingCells(state));
56
+ * ```
57
+ */
10
58
  export declare function landingCells(state: GameState): Landing | null;
11
59
  /**
12
60
  * Returns the Shizen hard-drop landing and one-step rebound preview without changing state.
@@ -15,11 +63,42 @@ export declare function landingCells(state: GameState): Landing | null;
15
63
  * gap then fall, so `settledCells` is where each stone of the pair comes to rest in the board the hard drop commits,
16
64
  * before any clear: draw a ghost from it. Both carry the pair's stable stone ids, and both are checked against
17
65
  * `applyAction` with a `hard-drop` over many played boards.
66
+ *
67
+ * @param state - The immutable native state to read or transition; the input is retained.
68
+ * @returns Returns the Shizen hard-drop landing and one-step rebound preview without changing state. Returns null when there is no active piece or applicable preview.
69
+ * @example
70
+ * ```ts
71
+ * import { createGame, powerDropPreview } from "@johnmorrisdotca/houseki/colour-chains";
72
+ *
73
+ * const state=createGame({seed:"docs"});
74
+ * console.log(powerDropPreview(state));
75
+ * ```
18
76
  */
19
77
  export declare function powerDropPreview(state: GameState): ChainsPowerDropPreview | null;
20
- /** Returns score, mode, chain and completion fields derived from state. */
78
+ /** Returns score, mode, chain and completion fields derived from state.
79
+ *
80
+ * @param state - The immutable native state to read or transition; the input is retained.
81
+ * @returns Returns score, mode, chain and completion fields derived from state.
82
+ * @example
83
+ * ```ts
84
+ * import { createGame, statusOf } from "@johnmorrisdotca/houseki/colour-chains";
85
+ *
86
+ * const state=createGame({seed:"docs"});
87
+ * console.log(statusOf(state).phase);
88
+ * ```
89
+ */
21
90
  export declare function statusOf(state: GameState): GameStatus;
22
91
  /** Creates a base challenge state with a previously validated visible board and pair queue. @internal */
23
92
  export declare function initialChallengeState(settings: Settings, visibleBoard: readonly (Gem | null)[], queue: readonly (readonly [Colour, Colour])[]): GameState;
24
- /** Creates a deterministic seeded game with one active pair and three previews. */
93
+ /** Creates a deterministic seeded game with one active pair and three previews.
94
+ *
95
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
96
+ * @returns Creates a deterministic seeded game with one active pair and three previews.
97
+ * @example
98
+ * ```ts
99
+ * import { createGame } from "@johnmorrisdotca/houseki/colour-chains";
100
+ *
101
+ * console.log(createGame({seed:"docs"}).phase);
102
+ * ```
103
+ */
25
104
  export declare function createGame(options?: CreateOptions): GameState;
@@ -315,7 +315,21 @@ function applyCore(state, action) {
315
315
  }
316
316
  }
317
317
  }
318
- /** Applies one immutable accepted action and records its logical-tick position. */
318
+ /** Applies one immutable accepted action and records its logical-tick position.
319
+ *
320
+ * @param state - The immutable native state to read or transition; the input is retained.
321
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
322
+ * @returns Applies one immutable accepted action and records its logical-tick position.
323
+ * @example
324
+ * ```ts
325
+ * import { applyAction, createGame } from "@johnmorrisdotca/houseki/colour-chains";
326
+ * import type { Action } from "@johnmorrisdotca/houseki/colour-chains";
327
+ *
328
+ * const state=createGame({seed:"docs"});
329
+ * const action: Action={kind:"left"};
330
+ * console.log(applyAction(state,action).accepted);
331
+ * ```
332
+ */
319
333
  export function applyAction(state, action) {
320
334
  const result = applyCore(state, action);
321
335
  if (!result.accepted)
@@ -376,7 +390,19 @@ function advanceResolution(state) {
376
390
  function lockGrounded(state) {
377
391
  return lock(state, rigidLanding(state, state.active));
378
392
  }
379
- /** Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock. */
393
+ /** Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock.
394
+ *
395
+ * @param state - The immutable native state to read or transition; the input is retained.
396
+ * @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
397
+ * @returns Advances deterministic 60 Hz simulation and resolution; Relaxed and Challenges do not force a falling clock.
398
+ * @example
399
+ * ```ts
400
+ * import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/colour-chains";
401
+ *
402
+ * const state=createGame({seed:"docs"});
403
+ * console.log(advanceTicks(state,1).state.phase);
404
+ * ```
405
+ */
380
406
  export function advanceTicks(state, ticks) {
381
407
  if (!Number.isInteger(ticks) || ticks < 0 || ticks > 3600)
382
408
  throw new RangeError('ticks must be an integer from 0 to 3600');
@@ -420,7 +446,18 @@ export function advanceTicks(state, ticks) {
420
446
  }
421
447
  return { state: current, events, accepted: true };
422
448
  }
423
- /** Lists only actions accepted by the current game state. */
449
+ /** Lists only actions accepted by the current game state.
450
+ *
451
+ * @param state - The immutable native state to read or transition; the input is retained.
452
+ * @returns Lists only actions accepted by the current game state.
453
+ * @example
454
+ * ```ts
455
+ * import { createGame, legalActions } from "@johnmorrisdotca/houseki/colour-chains";
456
+ *
457
+ * const state=createGame({seed:"docs"});
458
+ * console.log(legalActions(state).length);
459
+ * ```
460
+ */
424
461
  export function legalActions(state) {
425
462
  if (state.phase === 'paused')
426
463
  return [{ kind: 'resume' }];
@@ -446,7 +483,18 @@ export function legalActions(state) {
446
483
  actions.push({ kind: 'pause' });
447
484
  return actions;
448
485
  }
449
- /** Returns the exact independent landing cells for the current rigid pair without consuming random values. */
486
+ /** Returns the exact independent landing cells for the current rigid pair without consuming random values.
487
+ *
488
+ * @param state - The immutable native state to read or transition; the input is retained.
489
+ * @returns Returns the exact independent landing cells for the current rigid pair without consuming random values. Returns null when there is no active piece or applicable preview.
490
+ * @example
491
+ * ```ts
492
+ * import { createGame, landingCells } from "@johnmorrisdotca/houseki/colour-chains";
493
+ *
494
+ * const state=createGame({seed:"docs"});
495
+ * console.log(landingCells(state));
496
+ * ```
497
+ */
450
498
  export function landingCells(state) {
451
499
  if (!state.active)
452
500
  return null;
@@ -464,6 +512,16 @@ export function landingCells(state) {
464
512
  * gap then fall, so `settledCells` is where each stone of the pair comes to rest in the board the hard drop commits,
465
513
  * before any clear: draw a ghost from it. Both carry the pair's stable stone ids, and both are checked against
466
514
  * `applyAction` with a `hard-drop` over many played boards.
515
+ *
516
+ * @param state - The immutable native state to read or transition; the input is retained.
517
+ * @returns Returns the Shizen hard-drop landing and one-step rebound preview without changing state. Returns null when there is no active piece or applicable preview.
518
+ * @example
519
+ * ```ts
520
+ * import { createGame, powerDropPreview } from "@johnmorrisdotca/houseki/colour-chains";
521
+ *
522
+ * const state=createGame({seed:"docs"});
523
+ * console.log(powerDropPreview(state));
524
+ * ```
467
525
  */
468
526
  export function powerDropPreview(state) {
469
527
  if (!state.settings.nature || state.settings.mode === 'relaxed' || !state.active)
@@ -478,7 +536,18 @@ export function powerDropPreview(state) {
478
536
  : preview.finalCells;
479
537
  return Object.freeze({ ...preview, settledCells: Object.freeze(settledCells) });
480
538
  }
481
- /** Returns score, mode, chain and completion fields derived from state. */
539
+ /** Returns score, mode, chain and completion fields derived from state.
540
+ *
541
+ * @param state - The immutable native state to read or transition; the input is retained.
542
+ * @returns Returns score, mode, chain and completion fields derived from state.
543
+ * @example
544
+ * ```ts
545
+ * import { createGame, statusOf } from "@johnmorrisdotca/houseki/colour-chains";
546
+ *
547
+ * const state=createGame({seed:"docs"});
548
+ * console.log(statusOf(state).phase);
549
+ * ```
550
+ */
482
551
  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 } : {}) }; }
483
552
  /** Creates a base challenge state with a previously validated visible board and pair queue. @internal */
484
553
  export function initialChallengeState(settings, visibleBoard, queue) {
@@ -491,7 +560,17 @@ export function initialChallengeState(settings, visibleBoard, queue) {
491
560
  const nextMagnetic = settings.nature ? queue.slice(1, 4).map((_, index) => settings.magneticQueue?.[index + 1] ?? [false, false]) : undefined;
492
561
  return { ...base, active, ...(nextMagnetic ? { nextMagnetic: Object.freeze(nextMagnetic) } : {}), nextId: maxId + 3 };
493
562
  }
494
- /** Creates a deterministic seeded game with one active pair and three previews. */
563
+ /** Creates a deterministic seeded game with one active pair and three previews.
564
+ *
565
+ * @param options - Validated native creation, authored challenge, or environment options described by this signature.
566
+ * @returns Creates a deterministic seeded game with one active pair and three previews.
567
+ * @example
568
+ * ```ts
569
+ * import { createGame } from "@johnmorrisdotca/houseki/colour-chains";
570
+ *
571
+ * console.log(createGame({seed:"docs"}).phase);
572
+ * ```
573
+ */
495
574
  export function createGame(options = {}) {
496
575
  const valid = normalizeOptions(options);
497
576
  let state = { game: 'colour-chains', rules: RULES, settings: valid, board: Array(valid.width * (valid.height + HIDDEN)).fill(null), phase: 'falling', active: null, next: [], bag: [], randomState: seedState(`colour-chains|${RULES}|${valid.seed}`), nextId: 1, score: 0, maxChain: 0, allClears: 0, completedPairs: 0, resolutionTick: 0, waves: [], clearCells: [], gravityBoard: null, resolutionHadClear: false, elapsedTicks: 0, assisted: false, witnessIndex: -1, recording: [], ...(valid.weather ? { weatherResolvedPairs: 0 } : {}) };
@@ -7,18 +7,108 @@ export interface InputSchedulerState {
7
7
  readonly held: Readonly<Partial<Record<HeldControl, number>>>;
8
8
  readonly queued: readonly EdgeAction[];
9
9
  }
10
- /** Creates an empty held-input scheduler. */
10
+ /** Creates an empty held-input scheduler.
11
+ *
12
+ * @returns Creates an empty held-input scheduler.
13
+ * @example
14
+ * ```ts
15
+ * import { createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
16
+ *
17
+ * console.log(Object.keys(createInputScheduler()));
18
+ * ```
19
+ */
11
20
  export declare function createInputScheduler(): InputSchedulerState;
12
- /** Starts or releases one held control. Repeated press edges do not reset its repeat counter. */
21
+ /** Starts or releases one held control. Repeated press edges do not reset its repeat counter.
22
+ *
23
+ * @param state - The immutable native state to read or transition; the input is retained.
24
+ * @param control - The native held-control name.
25
+ * @param pressed - Whether this control is currently pressed.
26
+ * @returns Starts or releases one held control. Repeated press edges do not reset its repeat counter.
27
+ * @example
28
+ * ```ts
29
+ * import { createInputScheduler, setHeldInput } from "@johnmorrisdotca/houseki/colour-chains";
30
+ *
31
+ * const input=createInputScheduler();
32
+ * console.log(setHeldInput(input,"left",true));
33
+ * ```
34
+ */
13
35
  export declare function setHeldInput(state: InputSchedulerState, control: HeldControl, pressed: boolean): InputSchedulerState;
14
- /** Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick. */
36
+ /** Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick.
37
+ *
38
+ * @param state - The immutable native state to read or transition; the input is retained.
39
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
40
+ * @returns Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick.
41
+ * @example
42
+ * ```ts
43
+ * import { createInputScheduler, queueInputEdge } from "@johnmorrisdotca/houseki/colour-chains";
44
+ *
45
+ * const input=createInputScheduler();
46
+ * console.log(queueInputEdge(input,{kind:"hard-drop"}));
47
+ * ```
48
+ */
15
49
  export declare function queueInputEdge(state: InputSchedulerState, action: EdgeAction): InputSchedulerState;
16
- /** Releases every held or queued control after focus loss, lock, resolution or pause. */
50
+ /** Releases every held or queued control after focus loss, lock, resolution or pause.
51
+ *
52
+ * @param state - The immutable native state to read or transition; the input is retained.
53
+ * @returns Releases every held or queued control after focus loss, lock, resolution or pause.
54
+ * @example
55
+ * ```ts
56
+ * import { createInputScheduler, releaseAllInput } from "@johnmorrisdotca/houseki/colour-chains";
57
+ *
58
+ * const input=createInputScheduler();
59
+ * console.log(releaseAllInput(input));
60
+ * ```
61
+ */
17
62
  export declare function releaseAllInput(state: InputSchedulerState): InputSchedulerState;
18
- /** Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order. */
63
+ /** Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order.
64
+ *
65
+ * @param game - The native game state used to resolve scheduled input.
66
+ * @param input - The held-input scheduler state for this logical tick.
67
+ * @returns Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order.
68
+ * @example
69
+ * ```ts
70
+ * import { actionsForTick, createGame, createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
71
+ *
72
+ * const state=createGame({seed:"docs"});
73
+ * const input=createInputScheduler();
74
+ * console.log(actionsForTick(state,input)[0]);
75
+ * ```
76
+ */
19
77
  export declare function actionsForTick(game: GameState, input: InputSchedulerState): readonly [readonly Action[], InputSchedulerState];
20
- /** Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine. */
78
+ /** Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine.
79
+ *
80
+ * @param game - The native game state used to resolve scheduled input.
81
+ * @param input - The held-input scheduler state for this logical tick.
82
+ * @param actions - Native actions in the scheduler’s canonical order.
83
+ * @param applyAction - The native applyAction function for this game.
84
+ * @returns Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine.
85
+ * @example
86
+ * ```ts
87
+ * import { applyAction, applyScheduledActions, createGame, createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
88
+ * import type { Action } from "@johnmorrisdotca/houseki/colour-chains";
89
+ *
90
+ * const state=createGame({seed:"docs"});
91
+ * const action: Action={kind:"left"};
92
+ * const input=createInputScheduler();
93
+ * console.log(applyScheduledActions(state,input,[action],applyAction)[0].phase);
94
+ * ```
95
+ */
21
96
  export declare function applyScheduledActions(game: GameState, input: InputSchedulerState, actions: readonly Action[], applyAction: (state: GameState, action: Action) => Transition): readonly [GameState, InputSchedulerState, readonly Transition[]];
22
- /** Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution. */
97
+ /** Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution.
98
+ *
99
+ * @param game - The native game state used to resolve scheduled input.
100
+ * @param input - The held-input scheduler state for this logical tick.
101
+ * @param apply - The native applyAction function for this game.
102
+ * @param tick - The native advanceTicks function for this game.
103
+ * @returns Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution.
104
+ * @example
105
+ * ```ts
106
+ * import { advanceTicks, applyAction, createGame, createInputScheduler, processInputTick } from "@johnmorrisdotca/houseki/colour-chains";
107
+ *
108
+ * const state=createGame({seed:"docs"});
109
+ * const input=createInputScheduler();
110
+ * console.log(processInputTick(state,input,applyAction,advanceTicks)[0].phase);
111
+ * ```
112
+ */
23
113
  export declare function processInputTick(game: GameState, input: InputSchedulerState, apply: (state: GameState, action: Action) => Transition, tick: (state: GameState, ticks: number) => Transition): readonly [GameState, InputSchedulerState, readonly Transition[]];
24
114
  export {};
@@ -1,6 +1,28 @@
1
- /** Creates an empty held-input scheduler. */
1
+ /** Creates an empty held-input scheduler.
2
+ *
3
+ * @returns Creates an empty held-input scheduler.
4
+ * @example
5
+ * ```ts
6
+ * import { createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
7
+ *
8
+ * console.log(Object.keys(createInputScheduler()));
9
+ * ```
10
+ */
2
11
  export function createInputScheduler() { return { held: Object.freeze({}), queued: Object.freeze([]) }; }
3
- /** Starts or releases one held control. Repeated press edges do not reset its repeat counter. */
12
+ /** Starts or releases one held control. Repeated press edges do not reset its repeat counter.
13
+ *
14
+ * @param state - The immutable native state to read or transition; the input is retained.
15
+ * @param control - The native held-control name.
16
+ * @param pressed - Whether this control is currently pressed.
17
+ * @returns Starts or releases one held control. Repeated press edges do not reset its repeat counter.
18
+ * @example
19
+ * ```ts
20
+ * import { createInputScheduler, setHeldInput } from "@johnmorrisdotca/houseki/colour-chains";
21
+ *
22
+ * const input=createInputScheduler();
23
+ * console.log(setHeldInput(input,"left",true));
24
+ * ```
25
+ */
4
26
  export function setHeldInput(state, control, pressed) {
5
27
  const held = { ...state.held };
6
28
  if (pressed) {
@@ -11,12 +33,48 @@ export function setHeldInput(state, control, pressed) {
11
33
  delete held[control];
12
34
  return { ...state, held: Object.freeze(held) };
13
35
  }
14
- /** Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick. */
36
+ /** Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick.
37
+ *
38
+ * @param state - The immutable native state to read or transition; the input is retained.
39
+ * @param action - One native action for this entry point; inspect accepted and reason on the result.
40
+ * @returns Queues a one-shot rotation, drop, Place, pause or resume edge for the next logical tick.
41
+ * @example
42
+ * ```ts
43
+ * import { createInputScheduler, queueInputEdge } from "@johnmorrisdotca/houseki/colour-chains";
44
+ *
45
+ * const input=createInputScheduler();
46
+ * console.log(queueInputEdge(input,{kind:"hard-drop"}));
47
+ * ```
48
+ */
15
49
  export function queueInputEdge(state, action) { return { ...state, queued: Object.freeze([...state.queued, action]) }; }
16
- /** Releases every held or queued control after focus loss, lock, resolution or pause. */
50
+ /** Releases every held or queued control after focus loss, lock, resolution or pause.
51
+ *
52
+ * @param state - The immutable native state to read or transition; the input is retained.
53
+ * @returns Releases every held or queued control after focus loss, lock, resolution or pause.
54
+ * @example
55
+ * ```ts
56
+ * import { createInputScheduler, releaseAllInput } from "@johnmorrisdotca/houseki/colour-chains";
57
+ *
58
+ * const input=createInputScheduler();
59
+ * console.log(releaseAllInput(input));
60
+ * ```
61
+ */
17
62
  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- the public signature takes the state a caller holds, though nothing of it is kept
18
63
  export function releaseAllInput(state) { return createInputScheduler(); }
19
- /** Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order. */
64
+ /** Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order.
65
+ *
66
+ * @param game - The native game state used to resolve scheduled input.
67
+ * @param input - The held-input scheduler state for this logical tick.
68
+ * @returns Resolves this tick's inputs in lateral, rotation, drop, soft-drop, pause order.
69
+ * @example
70
+ * ```ts
71
+ * import { actionsForTick, createGame, createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
72
+ *
73
+ * const state=createGame({seed:"docs"});
74
+ * const input=createInputScheduler();
75
+ * console.log(actionsForTick(state,input)[0]);
76
+ * ```
77
+ */
20
78
  export function actionsForTick(game, input) {
21
79
  if (game.phase === 'paused') {
22
80
  const resume = input.queued.filter(action => action.kind === 'resume');
@@ -45,7 +103,24 @@ export function actionsForTick(game, input) {
45
103
  held[control] = (held[control] ?? 0) + 1;
46
104
  return [actions, { held: Object.freeze(held), queued: Object.freeze([]) }];
47
105
  }
48
- /** Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine. */
106
+ /** Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine.
107
+ *
108
+ * @param game - The native game state used to resolve scheduled input.
109
+ * @param input - The held-input scheduler state for this logical tick.
110
+ * @param actions - Native actions in the scheduler’s canonical order.
111
+ * @param applyAction - The native applyAction function for this game.
112
+ * @returns Applies a scheduler batch until the pair locks or the run pauses; accepted actions are recorded by the engine.
113
+ * @example
114
+ * ```ts
115
+ * import { applyAction, applyScheduledActions, createGame, createInputScheduler } from "@johnmorrisdotca/houseki/colour-chains";
116
+ * import type { Action } from "@johnmorrisdotca/houseki/colour-chains";
117
+ *
118
+ * const state=createGame({seed:"docs"});
119
+ * const action: Action={kind:"left"};
120
+ * const input=createInputScheduler();
121
+ * console.log(applyScheduledActions(state,input,[action],applyAction)[0].phase);
122
+ * ```
123
+ */
49
124
  export function applyScheduledActions(game, input, actions, applyAction) {
50
125
  let state = game;
51
126
  const transitions = [];
@@ -64,7 +139,22 @@ export function applyScheduledActions(game, input, actions, applyAction) {
64
139
  const lockedOrPaused = transitions.some(result => result.events.some(event => event.type === 'pair-locked' || event.type === 'paused')) || state.phase !== 'falling';
65
140
  return [state, lockedOrPaused ? createInputScheduler() : input, transitions];
66
141
  }
67
- /** Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution. */
142
+ /** Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution.
143
+ *
144
+ * @param game - The native game state used to resolve scheduled input.
145
+ * @param input - The held-input scheduler state for this logical tick.
146
+ * @param apply - The native applyAction function for this game.
147
+ * @param tick - The native advanceTicks function for this game.
148
+ * @returns Applies a complete deterministic held-input and simulation tick, releasing controls on lock or resolution.
149
+ * @example
150
+ * ```ts
151
+ * import { advanceTicks, applyAction, createGame, createInputScheduler, processInputTick } from "@johnmorrisdotca/houseki/colour-chains";
152
+ *
153
+ * const state=createGame({seed:"docs"});
154
+ * const input=createInputScheduler();
155
+ * console.log(processInputTick(state,input,applyAction,advanceTicks)[0].phase);
156
+ * ```
157
+ */
68
158
  export function processInputTick(game, input, apply, tick) {
69
159
  const [actions, scheduled] = actionsForTick(game, input);
70
160
  const [afterInput, retained, transitions] = applyScheduledActions(game, scheduled, actions, apply);