@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.
- package/CHANGELOG.md +19 -1
- package/README.md +77 -95
- package/dist/colour-chains/challenge.d.ts +12 -1
- package/dist/colour-chains/challenge.js +12 -1
- package/dist/colour-chains/content-types.d.ts +112 -0
- package/dist/colour-chains/content.d.ts +140 -3
- package/dist/colour-chains/content.js +140 -3
- package/dist/colour-chains/engine.d.ts +85 -6
- package/dist/colour-chains/engine.js +85 -6
- package/dist/colour-chains/input.d.ts +97 -7
- package/dist/colour-chains/input.js +97 -7
- package/dist/colour-chains/persistence.d.ts +36 -3
- package/dist/colour-chains/persistence.js +36 -3
- package/dist/colour-chains/types.d.ts +291 -17
- package/dist/colour-chains/validation.d.ts +12 -1
- package/dist/colour-chains/validation.js +12 -1
- package/dist/falling-triplets/content-types.d.ts +69 -0
- package/dist/falling-triplets/content.d.ts +60 -3
- package/dist/falling-triplets/content.js +60 -3
- package/dist/falling-triplets/engine.d.ts +122 -10
- package/dist/falling-triplets/engine.js +122 -10
- package/dist/falling-triplets/input.d.ts +61 -5
- package/dist/falling-triplets/input.js +61 -5
- package/dist/falling-triplets/match.d.ts +26 -2
- package/dist/falling-triplets/match.js +26 -2
- package/dist/falling-triplets/random.d.ts +34 -3
- package/dist/falling-triplets/random.js +34 -3
- package/dist/falling-triplets/types.d.ts +227 -3
- package/dist/gem-swap/content.d.ts +116 -0
- package/dist/gem-swap/content.js +72 -0
- package/dist/gem-swap/engine.d.ts +124 -9
- package/dist/gem-swap/engine.js +124 -9
- package/dist/gem-swap/persistence.d.ts +60 -4
- package/dist/gem-swap/persistence.js +60 -4
- package/dist/gem-swap/types.d.ts +336 -3
- package/dist/magnetic-blocks/content-types.d.ts +56 -0
- package/dist/magnetic-blocks/content.d.ts +91 -5
- package/dist/magnetic-blocks/content.js +91 -5
- package/dist/magnetic-blocks/engine.d.ts +63 -5
- package/dist/magnetic-blocks/engine.js +63 -5
- package/dist/magnetic-blocks/persistence.d.ts +36 -3
- package/dist/magnetic-blocks/persistence.js +36 -3
- package/dist/magnetic-blocks/physics.d.ts +176 -6
- package/dist/magnetic-blocks/physics.js +176 -6
- package/dist/magnetic-blocks/types.d.ts +185 -1
- package/dist/magnetic-blocks/validation.d.ts +12 -0
- package/dist/magnetic-blocks/validation.js +12 -0
- package/dist/nature/attraction.d.ts +24 -2
- package/dist/nature/attraction.js +24 -2
- package/dist/nature/environment.d.ts +200 -7
- package/dist/nature/environment.js +88 -7
- package/dist/nature/marking.d.ts +13 -1
- package/dist/nature/marking.js +13 -1
- package/dist/nature/rebound.d.ts +30 -2
- package/dist/nature/rebound.js +30 -2
- package/dist/nature/state.d.ts +11 -0
- package/dist/nature/state.js +11 -0
- package/dist/nature/types.d.ts +194 -1
- package/dist/nature/validation.d.ts +12 -0
- package/dist/nature/validation.js +12 -0
- package/dist/stone-collapse/content-types.d.ts +69 -0
- package/dist/stone-collapse/content.d.ts +60 -3
- package/dist/stone-collapse/content.js +60 -3
- package/dist/stone-collapse/engine.d.ts +99 -8
- package/dist/stone-collapse/engine.js +99 -8
- package/dist/stone-collapse/persistence.d.ts +36 -3
- package/dist/stone-collapse/persistence.js +36 -3
- package/dist/stone-collapse/types.d.ts +220 -3
- package/dist/stone-collapse/validation.d.ts +12 -1
- package/dist/stone-collapse/validation.js +12 -1
- package/package.json +34 -26
|
@@ -8,28 +8,114 @@ 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/magnetic-blocks";
|
|
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/magnetic-blocks";
|
|
26
|
+
*
|
|
27
|
+
* console.log(levelManifest.length);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
12
30
|
export const levelManifest = campaignManifest.levels;
|
|
13
|
-
/** Alias kept alongside other Houseki campaign lesson APIs.
|
|
31
|
+
/** Alias kept alongside other Houseki campaign lesson APIs.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { tutorialManifest } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
36
|
+
*
|
|
37
|
+
* console.log(tutorialManifest.length);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
14
40
|
export const tutorialManifest = deepFreeze(contentData.lessons);
|
|
41
|
+
/** The frozen native bilingual lessons and their authored teaching steps.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { lessonManifest } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
46
|
+
*
|
|
47
|
+
* console.log(lessonManifest.length);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
15
50
|
export const lessonManifest = tutorialManifest;
|
|
16
|
-
/** Finds a Magnetic Blocks campaign level by stable ID or one-based display number.
|
|
51
|
+
/** Finds a Magnetic Blocks campaign level by stable ID or one-based display number.
|
|
52
|
+
*
|
|
53
|
+
* @param id - A stable content id, or the one-based display number when numbers are accepted.
|
|
54
|
+
* @returns Finds a Magnetic Blocks campaign level by stable ID or one-based display number. Returns undefined when the id or display number is absent.
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { getLevel } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
58
|
+
*
|
|
59
|
+
* console.log(getLevel(1)?.id);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
17
62
|
export function getLevel(id) {
|
|
18
63
|
if (typeof id === 'number')
|
|
19
64
|
return Number.isInteger(id) ? levelManifest.find(level => level.number === id) : undefined;
|
|
20
65
|
return levelManifest.find(level => level.id === id);
|
|
21
66
|
}
|
|
22
|
-
/** Creates a fresh game with the authored rules, board, queue, and finite move budget.
|
|
67
|
+
/** Creates a fresh game with the authored rules, board, queue, and finite move budget.
|
|
68
|
+
*
|
|
69
|
+
* @param id - A stable content id, or the one-based display number when numbers are accepted.
|
|
70
|
+
* @returns Creates a fresh game with the authored rules, board, queue, and finite move budget.
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* import { createLevel } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
74
|
+
*
|
|
75
|
+
* console.log(createLevel(1).phase);
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
23
78
|
export function createLevel(id) {
|
|
24
79
|
const level = getLevel(id);
|
|
25
80
|
if (!level)
|
|
26
81
|
throw new RangeError(`Unknown Magnetic Blocks level: ${String(id)}`);
|
|
27
82
|
return createGame(level.options);
|
|
28
83
|
}
|
|
29
|
-
/** Finds one of the three bilingual rules lessons by stable ID.
|
|
84
|
+
/** Finds one of the three bilingual rules lessons by stable ID.
|
|
85
|
+
*
|
|
86
|
+
* @param id - A stable content id, or the one-based display number when numbers are accepted.
|
|
87
|
+
* @returns Finds one of the three bilingual rules lessons by stable ID. Returns undefined when the id or display number is absent.
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { getLesson, lessonManifest } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
91
|
+
*
|
|
92
|
+
* console.log(getLesson(lessonManifest[0].id)?.id);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
30
95
|
export function getLesson(id) { return tutorialManifest.find(lesson => lesson.id === id); }
|
|
96
|
+
/** Find a magnetic-block lesson by stable id; returns undefined when no lesson has that id.
|
|
97
|
+
*
|
|
98
|
+
* @param id - A stable content id, or the one-based display number when numbers are accepted.
|
|
99
|
+
* @returns Find a magnetic-block lesson by stable id; returns undefined when no lesson has that id. Returns undefined when the id or display number is absent.
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import { getTutorial, lessonManifest } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
103
|
+
*
|
|
104
|
+
* console.log(getTutorial(lessonManifest[0].id)?.id);
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
31
107
|
export const getTutorial = getLesson;
|
|
32
|
-
/** Creates a fresh lesson game with its authored setup and queue.
|
|
108
|
+
/** Creates a fresh lesson game with its authored setup and queue.
|
|
109
|
+
*
|
|
110
|
+
* @param id - A stable content id, or the one-based display number when numbers are accepted.
|
|
111
|
+
* @returns Creates a fresh lesson game with its authored setup and queue.
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { createLesson, lessonManifest } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
115
|
+
*
|
|
116
|
+
* console.log(createLesson(lessonManifest[0].id).phase);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
33
119
|
export function createLesson(id) {
|
|
34
120
|
const lesson = getLesson(id);
|
|
35
121
|
if (!lesson)
|
|
@@ -1,11 +1,69 @@
|
|
|
1
1
|
import type { Action, GameState, GameStatus, Transition } from './types.js';
|
|
2
|
-
/** Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
2
|
+
/** Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
3
|
+
*
|
|
4
|
+
* @param options - Validated native creation, authored challenge, or environment options described by this signature.
|
|
5
|
+
* @returns Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
9
|
+
*
|
|
10
|
+
* console.log(createGame({seed:"docs"}).phase);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
3
13
|
export declare function createGame(options?: import('./types.js').CreateOptions): GameState;
|
|
4
|
-
/** Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
14
|
+
/** Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
15
|
+
*
|
|
16
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
17
|
+
* @param action - One native action for this entry point; inspect accepted and reason on the result.
|
|
18
|
+
* @returns Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { applyAction, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
22
|
+
* import type { Action } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
23
|
+
*
|
|
24
|
+
* const state=createGame({seed:"docs"});
|
|
25
|
+
* const action: Action={kind:"left"};
|
|
26
|
+
* console.log(applyAction(state,action).accepted);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
5
29
|
export declare function applyAction(state: GameState, action: Action): Transition;
|
|
6
|
-
/** Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
30
|
+
/** Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
31
|
+
*
|
|
32
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
33
|
+
* @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
|
|
34
|
+
* @returns Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
38
|
+
*
|
|
39
|
+
* const state=createGame({seed:"docs"});
|
|
40
|
+
* console.log(advanceTicks(state,1).state.phase);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
7
43
|
export declare function advanceTicks(state: GameState, ticks: number): Transition;
|
|
8
|
-
/** Lists accepted controls for the current falling or resolution phase.
|
|
44
|
+
/** Lists accepted controls for the current falling or resolution phase.
|
|
45
|
+
*
|
|
46
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
47
|
+
* @returns Lists accepted controls for the current falling or resolution phase.
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { createGame, legalActions } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
51
|
+
*
|
|
52
|
+
* const state=createGame({seed:"docs"});
|
|
53
|
+
* console.log(legalActions(state).length);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
9
56
|
export declare function legalActions(state: GameState): readonly Action[];
|
|
10
|
-
/** Returns a compact immutable status including current and upcoming floor state.
|
|
57
|
+
/** Returns a compact immutable status including current and upcoming floor state.
|
|
58
|
+
*
|
|
59
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
60
|
+
* @returns Returns a compact immutable status including current and upcoming floor state.
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { createGame, statusOf } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
64
|
+
*
|
|
65
|
+
* const state=createGame({seed:"docs"});
|
|
66
|
+
* console.log(statusOf(state).phase);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
11
69
|
export declare function statusOf(state: GameState): GameStatus;
|
|
@@ -154,7 +154,17 @@ function core(state, action) {
|
|
|
154
154
|
const reset = state.settings.mode === 'arcade' && grounded && active.lockResets < 8;
|
|
155
155
|
return { state: { ...state, active: freezeBlock({ ...rotated, lockTicks: reset ? 0 : active.lockTicks, lockResets: active.lockResets + (reset ? 1 : 0), lockStarted: reset ? true : active.lockStarted }) }, events: [{ type: 'piece-rotated', orientation, ids: rotated.gems.map(gem => gem.id), cells: blockCells(rotated, width).map(item => item.index) }], accepted: true };
|
|
156
156
|
}
|
|
157
|
-
/** Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
157
|
+
/** Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
158
|
+
*
|
|
159
|
+
* @param options - Validated native creation, authored challenge, or environment options described by this signature.
|
|
160
|
+
* @returns Creates an immutable seeded 2×2-block game with a fixed queue and explicit floor schedule.
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* import { createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
164
|
+
*
|
|
165
|
+
* console.log(createGame({seed:"docs"}).phase);
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
158
168
|
export function createGame(options = {}) {
|
|
159
169
|
const valid = validateOptions(options);
|
|
160
170
|
let randomState, queue;
|
|
@@ -175,7 +185,21 @@ export function createGame(options = {}) {
|
|
|
175
185
|
const [started] = spawn(state);
|
|
176
186
|
return freezeState(started);
|
|
177
187
|
}
|
|
178
|
-
/** Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
188
|
+
/** Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
189
|
+
*
|
|
190
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
191
|
+
* @param action - One native action for this entry point; inspect accepted and reason on the result.
|
|
192
|
+
* @returns Applies one movement, rotation, floor-switch or placement action without mutation.
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import { applyAction, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
196
|
+
* import type { Action } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
197
|
+
*
|
|
198
|
+
* const state=createGame({seed:"docs"});
|
|
199
|
+
* const action: Action={kind:"left"};
|
|
200
|
+
* console.log(applyAction(state,action).accepted);
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
179
203
|
export function applyAction(state, action) {
|
|
180
204
|
const result = core(state, action);
|
|
181
205
|
if (!result.accepted)
|
|
@@ -186,7 +210,19 @@ export function applyAction(state, action) {
|
|
|
186
210
|
const next = freezeState({ ...result.state, recording: Object.freeze([...state.recording, recorded]) });
|
|
187
211
|
return { ...result, state: next };
|
|
188
212
|
}
|
|
189
|
-
/** Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
213
|
+
/** Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
214
|
+
*
|
|
215
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
216
|
+
* @param ticks - The nonnegative number of fixed 60 Hz logical ticks to advance.
|
|
217
|
+
* @returns Advances fixed 60 Hz time, resolving phases in all modes and falling/locking only in Arcade.
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import { advanceTicks, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
221
|
+
*
|
|
222
|
+
* const state=createGame({seed:"docs"});
|
|
223
|
+
* console.log(advanceTicks(state,1).state.phase);
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
190
226
|
export function advanceTicks(state, ticks) {
|
|
191
227
|
if (!Number.isInteger(ticks) || ticks < 0 || ticks > 3600)
|
|
192
228
|
throw new RangeError('ticks must be an integer from 0 to 3600');
|
|
@@ -245,7 +281,18 @@ export function advanceTicks(state, ticks) {
|
|
|
245
281
|
}
|
|
246
282
|
return { state: freezeState(current), events: Object.freeze(events), accepted: true };
|
|
247
283
|
}
|
|
248
|
-
/** Lists accepted controls for the current falling or resolution phase.
|
|
284
|
+
/** Lists accepted controls for the current falling or resolution phase.
|
|
285
|
+
*
|
|
286
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
287
|
+
* @returns Lists accepted controls for the current falling or resolution phase.
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* import { createGame, legalActions } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
291
|
+
*
|
|
292
|
+
* const state=createGame({seed:"docs"});
|
|
293
|
+
* console.log(legalActions(state).length);
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
249
296
|
export function legalActions(state) {
|
|
250
297
|
if (state.phase === 'paused')
|
|
251
298
|
return Object.freeze([{ kind: 'resume' }]);
|
|
@@ -261,5 +308,16 @@ export function legalActions(state) {
|
|
|
261
308
|
]);
|
|
262
309
|
return Object.freeze([]);
|
|
263
310
|
}
|
|
264
|
-
/** Returns a compact immutable status including current and upcoming floor state.
|
|
311
|
+
/** Returns a compact immutable status including current and upcoming floor state.
|
|
312
|
+
*
|
|
313
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
314
|
+
* @returns Returns a compact immutable status including current and upcoming floor state.
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* import { createGame, statusOf } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
318
|
+
*
|
|
319
|
+
* const state=createGame({seed:"docs"});
|
|
320
|
+
* console.log(statusOf(state).phase);
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
265
323
|
export function statusOf(state) { return Object.freeze({ phase: state.phase, score: state.score, moves: state.moves, placements: state.placements, floor: state.pendingFloorOverride ?? state.floor, nextFloor: state.nextFloor, floorSwitchCharges: state.floorSwitchCharges, pendingFloorOverride: state.pendingFloorOverride, maxChain: state.maxChain, ...(state.reason ? { reason: state.reason } : {}) }); }
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import type { GameState } from './types.js';
|
|
2
|
-
/** Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
2
|
+
/** Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
3
|
+
*
|
|
4
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
5
|
+
* @returns Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createGame, restartGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
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 canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
15
|
+
/** Encodes canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
16
|
+
*
|
|
17
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
18
|
+
* @returns Encodes canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { createGame, encodeGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
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
|
-
/** Replays bounded canonical input and verifies every saved checkpoint field.
|
|
28
|
+
/** Replays bounded canonical input and verifies every saved checkpoint field.
|
|
29
|
+
*
|
|
30
|
+
* @param text - A saved JSON recording from this entry’s encodeGame; malformed or inconsistent saves throw.
|
|
31
|
+
* @returns Replays bounded canonical input and verifies every saved checkpoint field.
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { createGame, decodeGame, encodeGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
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;
|
|
@@ -68,9 +68,31 @@ function replay(settings, actions, elapsedTicks) {
|
|
|
68
68
|
}
|
|
69
69
|
return state;
|
|
70
70
|
}
|
|
71
|
-
/** Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
71
|
+
/** Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
72
|
+
*
|
|
73
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
74
|
+
* @returns Restarts the same seed, custom starting board, fixed queue, rules and floor options.
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { createGame, restartGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
78
|
+
*
|
|
79
|
+
* const state=createGame({seed:"docs"});
|
|
80
|
+
* console.log(restartGame(state).phase);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
72
83
|
export function restartGame(state) { return createFromSettings(state.settings); }
|
|
73
|
-
/** Encodes canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
84
|
+
/** Encodes canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
85
|
+
*
|
|
86
|
+
* @param state - The immutable native state to read or transition; the input is retained.
|
|
87
|
+
* @returns Encodes canonical settings, accepted tick-stamped actions and a verified replay checkpoint.
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { createGame, encodeGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
91
|
+
*
|
|
92
|
+
* const state=createGame({seed:"docs"});
|
|
93
|
+
* console.log(encodeGame(state).length);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
74
96
|
export function encodeGame(state) {
|
|
75
97
|
if (!Number.isSafeInteger(state.elapsedTicks) || state.elapsedTicks < 0 || state.elapsedTicks > MAX_TICKS || state.recording.length > MAX_ACTIONS)
|
|
76
98
|
throw new RangeError('Run exceeds replay limits');
|
|
@@ -82,7 +104,18 @@ export function encodeGame(state) {
|
|
|
82
104
|
throw new RangeError('Save exceeds 2 MiB');
|
|
83
105
|
return text;
|
|
84
106
|
}
|
|
85
|
-
/** Replays bounded canonical input and verifies every saved checkpoint field.
|
|
107
|
+
/** Replays bounded canonical input and verifies every saved checkpoint field.
|
|
108
|
+
*
|
|
109
|
+
* @param text - A saved JSON recording from this entry’s encodeGame; malformed or inconsistent saves throw.
|
|
110
|
+
* @returns Replays bounded canonical input and verifies every saved checkpoint field.
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* import { createGame, decodeGame, encodeGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
114
|
+
*
|
|
115
|
+
* const state=createGame({seed:"docs"});
|
|
116
|
+
* console.log(decodeGame(encodeGame(state)).phase);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
86
119
|
export function decodeGame(text) {
|
|
87
120
|
if (typeof text !== 'string' || new TextEncoder().encode(text).byteLength > MAX_SAVE_BYTES)
|
|
88
121
|
throw new RangeError('Save must be text no larger than 2 MiB');
|
|
@@ -1,30 +1,200 @@
|
|
|
1
1
|
import type { Block, Bond, Floor, Gem } from './types.js';
|
|
2
2
|
export declare const HIDDEN_ROWS = 0;
|
|
3
|
-
|
|
3
|
+
/** The fixed 60 Hz ticks showing the magnetic-block match mark phase.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { MARK_TICKS } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
8
|
+
*
|
|
9
|
+
* console.log(MARK_TICKS);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const MARK_TICKS = 7;
|
|
13
|
+
/** Fixed 60 Hz ticks in the magnetic-block removal phase.
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { REMOVE_TICKS } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
17
|
+
* console.log(REMOVE_TICKS);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const REMOVE_TICKS = 6;
|
|
21
|
+
/** Fixed 60 Hz ticks in the magnetic-block gravity phase.
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { GRAVITY_TICKS } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
25
|
+
* console.log(GRAVITY_TICKS);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare const GRAVITY_TICKS = 9;
|
|
4
29
|
export declare const cell: (x: number, y: number, width: number) => number;
|
|
5
|
-
/** Returns stable-gem addresses after rotating the square block around its centre.
|
|
30
|
+
/** Returns stable-gem addresses after rotating the square block around its centre.
|
|
31
|
+
*
|
|
32
|
+
* @param block - The native active 2×2 block and its stable gem ids.
|
|
33
|
+
* @param width - The native board width in cells.
|
|
34
|
+
* @returns Returns stable-gem addresses after rotating the square block around its centre.
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { blockCells, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
38
|
+
*
|
|
39
|
+
* const state=createGame({seed:"docs"});
|
|
40
|
+
* console.log(blockCells(state.active!,state.settings.width).length);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
6
43
|
export declare function blockCells(block: Block, width: number): readonly {
|
|
7
44
|
readonly index: number;
|
|
8
45
|
readonly gem: Gem;
|
|
9
46
|
}[];
|
|
47
|
+
/** Test whether the whole native block fits passable empty board cells.
|
|
48
|
+
*
|
|
49
|
+
* @param block - The native active 2×2 block and its stable gem ids.
|
|
50
|
+
* @param board - The row-major native board; null cells are empty or masked.
|
|
51
|
+
* @param width - The native board width in cells.
|
|
52
|
+
* @param height - The native board height in cells.
|
|
53
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
54
|
+
* @returns Test whether the whole native block fits passable empty board cells.
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { canPlace, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
58
|
+
*
|
|
59
|
+
* const state=createGame({seed:"docs"});
|
|
60
|
+
* console.log(canPlace(state.active!,state.board,state.settings.width,state.settings.height,state.settings.mask));
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
10
63
|
export declare function canPlace(block: Block, board: readonly (Gem | null)[], width: number, height: number, mask: readonly boolean[]): boolean;
|
|
64
|
+
/** Find the last legal block row before downward collision.
|
|
65
|
+
*
|
|
66
|
+
* @param block - The native active 2×2 block and its stable gem ids.
|
|
67
|
+
* @param board - The row-major native board; null cells are empty or masked.
|
|
68
|
+
* @param width - The native board width in cells.
|
|
69
|
+
* @param height - The native board height in cells.
|
|
70
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
71
|
+
* @returns Find the last legal block row before downward collision.
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { createGame, landingY } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
75
|
+
*
|
|
76
|
+
* const state=createGame({seed:"docs"});
|
|
77
|
+
* console.log(landingY(state.active!,state.board,state.settings.width,state.settings.height,state.settings.mask));
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
11
80
|
export declare function landingY(block: Block, board: readonly (Gem | null)[], width: number, height: number, mask: readonly boolean[]): number;
|
|
12
|
-
/** Computes deterministic orthogonal colour components of at least four gems.
|
|
81
|
+
/** Computes deterministic orthogonal colour components of at least four gems.
|
|
82
|
+
*
|
|
83
|
+
* @param board - The row-major native board; null cells are empty or masked.
|
|
84
|
+
* @param width - The native board width in cells.
|
|
85
|
+
* @param height - The native board height in cells.
|
|
86
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
87
|
+
* @returns Computes deterministic orthogonal colour components of at least four gems.
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { createGame, matchGroups } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
91
|
+
*
|
|
92
|
+
* const state=createGame({seed:"docs"});
|
|
93
|
+
* console.log(matchGroups(state.board,state.settings.width,state.settings.height,state.settings.mask).length);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
13
96
|
export declare function matchGroups(board: readonly (Gem | null)[], width: number, height: number, mask: readonly boolean[]): readonly (readonly number[])[];
|
|
14
97
|
export declare function allMatchedCells(groups: readonly (readonly number[])[]): readonly number[];
|
|
98
|
+
/** Remove the selected native cell indices and discard bonds whose endpoint gems were removed.
|
|
99
|
+
*
|
|
100
|
+
* @param board - The row-major native board; null cells are empty or masked.
|
|
101
|
+
* @param bonds - Native stable-id bonds connecting surviving gems.
|
|
102
|
+
* @param indices - Row-major cell indices selected for removal.
|
|
103
|
+
* @returns Remove the selected native cell indices and discard bonds whose endpoint gems were removed. Nested null values denote empty board cells, absent active pieces, unselected tools or outcomes not yet reached; optional undefined fields are absent until applicable.
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { createGame, removeIds } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
107
|
+
*
|
|
108
|
+
* const state=createGame({seed:"docs"});
|
|
109
|
+
* console.log(removeIds(state.board,state.bonds,[]).ids.length);
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
15
112
|
export declare function removeIds(board: readonly (Gem | null)[], bonds: readonly Bond[], indices: readonly number[]): {
|
|
16
113
|
readonly board: readonly (Gem | null)[];
|
|
17
114
|
readonly bonds: readonly Bond[];
|
|
18
115
|
readonly ids: readonly number[];
|
|
19
116
|
};
|
|
20
|
-
/** Settles bonded connected components one cell per deterministic bottom/ID priority step.
|
|
117
|
+
/** Settles bonded connected components one cell per deterministic bottom/ID priority step.
|
|
118
|
+
*
|
|
119
|
+
* @param initial - The row-major starting board for gravity settlement.
|
|
120
|
+
* @param bonds - Native stable-id bonds connecting surviving gems.
|
|
121
|
+
* @param width - The native board width in cells.
|
|
122
|
+
* @param height - The native board height in cells.
|
|
123
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
124
|
+
* @returns Settles bonded connected components one cell per deterministic bottom/ID priority step. Nested null values denote empty board cells, absent active pieces, unselected tools or outcomes not yet reached; optional undefined fields are absent until applicable.
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* import { calmGravity, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
128
|
+
*
|
|
129
|
+
* const state=createGame({seed:"docs"});
|
|
130
|
+
* console.log(calmGravity(state.board,state.bonds,state.settings.width,state.settings.height,state.settings.mask).length);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
21
133
|
export declare function calmGravity(initial: readonly (Gem | null)[], bonds: readonly Bond[], width: number, height: number, mask: readonly boolean[]): readonly (Gem | null)[];
|
|
22
|
-
/** Magnetic floor removes all bonds and settles each column segment independently.
|
|
134
|
+
/** Magnetic floor removes all bonds and settles each column segment independently.
|
|
135
|
+
*
|
|
136
|
+
* @param initial - The row-major starting board for gravity settlement.
|
|
137
|
+
* @param width - The native board width in cells.
|
|
138
|
+
* @param height - The native board height in cells.
|
|
139
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
140
|
+
* @returns Magnetic floor removes all bonds and settles each column segment independently. Nested null values denote empty board cells, absent active pieces, unselected tools or outcomes not yet reached; optional undefined fields are absent until applicable.
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { createGame, magneticGravity } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
144
|
+
*
|
|
145
|
+
* const state=createGame({seed:"docs"});
|
|
146
|
+
* console.log(magneticGravity(state.board,state.settings.width,state.settings.height,state.settings.mask).length);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
23
149
|
export declare function magneticGravity(initial: readonly (Gem | null)[], width: number, height: number, mask: readonly boolean[]): readonly (Gem | null)[];
|
|
150
|
+
/** Settle surviving gems with the chosen floor rule and retain valid stable-id bonds.
|
|
151
|
+
*
|
|
152
|
+
* @param initial - The row-major starting board for gravity settlement.
|
|
153
|
+
* @param bonds - Native stable-id bonds connecting surviving gems.
|
|
154
|
+
* @param floor - The native calm or magnetic floor rule to apply.
|
|
155
|
+
* @param width - The native board width in cells.
|
|
156
|
+
* @param height - The native board height in cells.
|
|
157
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
158
|
+
* @returns Settle surviving gems with the chosen floor rule and retain valid stable-id bonds. Nested null values denote empty board cells, absent active pieces, unselected tools or outcomes not yet reached; optional undefined fields are absent until applicable.
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* import { createGame, settle } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
162
|
+
*
|
|
163
|
+
* const state=createGame({seed:"docs"});
|
|
164
|
+
* console.log(settle(state.board,state.bonds,"calm",state.settings.width,state.settings.height,state.settings.mask).board.length);
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
24
167
|
export declare function settle(initial: readonly (Gem | null)[], bonds: readonly Bond[], floor: Floor, width: number, height: number, mask: readonly boolean[]): {
|
|
25
168
|
readonly board: readonly (Gem | null)[];
|
|
26
169
|
readonly bonds: readonly Bond[];
|
|
27
170
|
};
|
|
28
|
-
/** Collects the occupied one-cell support layer under both block columns at first contact.
|
|
171
|
+
/** Collects the occupied one-cell support layer under both block columns at first contact.
|
|
172
|
+
*
|
|
173
|
+
* @param block - The native active 2×2 block and its stable gem ids.
|
|
174
|
+
* @param board - The row-major native board; null cells are empty or masked.
|
|
175
|
+
* @param width - The native board width in cells.
|
|
176
|
+
* @param height - The native board height in cells.
|
|
177
|
+
* @param mask - The row-major active-cell mask; false cells cannot hold gems.
|
|
178
|
+
* @returns Collects the occupied one-cell support layer under both block columns at first contact.
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* import { createGame, impactSupportIds } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
182
|
+
*
|
|
183
|
+
* const state=createGame({seed:"docs"});
|
|
184
|
+
* console.log(impactSupportIds(state.active!,state.board,state.settings.width,state.settings.height,state.settings.mask).length);
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
29
187
|
export declare function impactSupportIds(block: Block, board: readonly (Gem | null)[], width: number, height: number, mask: readonly boolean[]): readonly number[];
|
|
188
|
+
/** List the native stable-id bonds connecting adjacent gems in the active block.
|
|
189
|
+
*
|
|
190
|
+
* @param block - The native active 2×2 block and its stable gem ids.
|
|
191
|
+
* @returns List the native stable-id bonds connecting adjacent gems in the active block.
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* import { blockBonds, createGame } from "@johnmorrisdotca/houseki/magnetic-blocks";
|
|
195
|
+
*
|
|
196
|
+
* const state=createGame({seed:"docs"});
|
|
197
|
+
* console.log(blockBonds(state.active!).length);
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
30
200
|
export declare function blockBonds(block: Block): readonly Bond[];
|