@johnmorrisdotca/houseki 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -2
- package/README.md +28 -8
- package/dist/colour-chains/challenge.js +18 -4
- package/dist/colour-chains/content-data.js +19582 -2
- package/dist/colour-chains/content-types.d.ts +21 -0
- package/dist/colour-chains/content.d.ts +9 -1
- package/dist/colour-chains/content.js +13 -0
- package/dist/colour-chains/engine.js +8 -4
- package/dist/colour-chains/persistence.js +1 -1
- package/dist/colour-chains/types.d.ts +6 -2
- package/dist/colour-chains.d.ts +2 -2
- package/dist/colour-chains.js +1 -1
- package/dist/magnetic-blocks/content-data.d.ts +3 -0
- package/dist/magnetic-blocks/content-data.js +11781 -0
- package/dist/magnetic-blocks/content-types.d.ts +66 -0
- package/dist/magnetic-blocks/content-types.js +1 -0
- package/dist/magnetic-blocks/content.d.ts +16 -0
- package/dist/magnetic-blocks/content.js +38 -0
- package/dist/magnetic-blocks/engine.js +4 -2
- package/dist/magnetic-blocks.d.ts +2 -0
- package/dist/magnetic-blocks.js +1 -0
- package/package.json +6 -3
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Action, Colour, CreateOptions, Floor, GameState, Gem } from './types.js';
|
|
2
|
+
export interface LocalizedText {
|
|
3
|
+
readonly en: string;
|
|
4
|
+
readonly ja: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MagneticDifficultyMetrics {
|
|
7
|
+
readonly legalPlacementChoices: number;
|
|
8
|
+
readonly setupPlacementChoices: number;
|
|
9
|
+
readonly winningPlacementChoices: number;
|
|
10
|
+
readonly availableFloorChoices: number;
|
|
11
|
+
readonly witnessPlacements: number;
|
|
12
|
+
readonly witnessFloorDecisions: number;
|
|
13
|
+
readonly difficultyScore: number;
|
|
14
|
+
}
|
|
15
|
+
export interface MagneticCampaignLevel {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly number: number;
|
|
18
|
+
readonly title: LocalizedText;
|
|
19
|
+
readonly objective: LocalizedText;
|
|
20
|
+
readonly options: CreateOptions;
|
|
21
|
+
readonly witness: readonly Action[];
|
|
22
|
+
readonly witnessResult: 'won';
|
|
23
|
+
readonly metrics: MagneticDifficultyMetrics;
|
|
24
|
+
readonly marks: 1 | 2 | 3 | 4 | 5;
|
|
25
|
+
readonly tags: readonly string[];
|
|
26
|
+
readonly canonicalKey: string;
|
|
27
|
+
readonly canonicalKeyHash: string;
|
|
28
|
+
readonly score: number;
|
|
29
|
+
readonly gradingVersion: string;
|
|
30
|
+
readonly proofStatus: 'engine-witness-verified';
|
|
31
|
+
readonly reviewStatus: 'human-review-pending' | 'human-reviewed';
|
|
32
|
+
readonly counterfactual?: {
|
|
33
|
+
readonly kind: 'floor-choice' | 'floor-schedule' | 'floor-switch';
|
|
34
|
+
readonly alternative: string;
|
|
35
|
+
readonly result: 'won' | 'lost' | 'finished';
|
|
36
|
+
};
|
|
37
|
+
readonly impactEvidence?: {
|
|
38
|
+
readonly removedSupportCount: number;
|
|
39
|
+
readonly disabledImpactResult: 'won';
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface MagneticCampaignManifest {
|
|
43
|
+
readonly count: number;
|
|
44
|
+
readonly candidateCount: number;
|
|
45
|
+
readonly generationRevision: string;
|
|
46
|
+
readonly gradingVersion: string;
|
|
47
|
+
readonly difficultyFormula: string;
|
|
48
|
+
readonly normalization: string;
|
|
49
|
+
readonly marksFormula: string;
|
|
50
|
+
readonly checksum: string;
|
|
51
|
+
readonly orderingPolicy: string;
|
|
52
|
+
readonly levels: readonly MagneticCampaignLevel[];
|
|
53
|
+
}
|
|
54
|
+
export interface MagneticLesson {
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly title: LocalizedText;
|
|
57
|
+
readonly objective: LocalizedText;
|
|
58
|
+
readonly options: CreateOptions;
|
|
59
|
+
readonly witness: readonly Action[];
|
|
60
|
+
readonly instruction: readonly LocalizedText[];
|
|
61
|
+
}
|
|
62
|
+
export interface MagneticContentData {
|
|
63
|
+
readonly campaign: MagneticCampaignManifest;
|
|
64
|
+
readonly lessons: readonly MagneticLesson[];
|
|
65
|
+
}
|
|
66
|
+
export type { Action, Colour, CreateOptions, Floor, GameState, Gem };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MagneticCampaignLevel, MagneticCampaignManifest, MagneticLesson } from './content-types.js';
|
|
2
|
+
import type { GameState } from './types.js';
|
|
3
|
+
export declare const campaignManifest: MagneticCampaignManifest;
|
|
4
|
+
export declare const levelManifest: readonly MagneticCampaignLevel[];
|
|
5
|
+
/** Alias kept alongside other Houseki campaign lesson APIs. */
|
|
6
|
+
export declare const tutorialManifest: readonly MagneticLesson[];
|
|
7
|
+
export declare const lessonManifest: readonly MagneticLesson[];
|
|
8
|
+
/** Finds a Magnetic Blocks campaign level by stable ID or one-based display number. */
|
|
9
|
+
export declare function getLevel(id: string | number): MagneticCampaignLevel | undefined;
|
|
10
|
+
/** Creates a fresh game with the authored rules, board, queue, and finite move budget. */
|
|
11
|
+
export declare function createLevel(id: string | number): GameState;
|
|
12
|
+
/** Finds one of the three bilingual rules lessons by stable ID. */
|
|
13
|
+
export declare function getLesson(id: string): MagneticLesson | undefined;
|
|
14
|
+
export declare const getTutorial: typeof getLesson;
|
|
15
|
+
/** Creates a fresh lesson game with its authored setup and queue. */
|
|
16
|
+
export declare function createLesson(id: string): GameState;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { contentData } from './content-data.js';
|
|
2
|
+
import { createGame } from './engine.js';
|
|
3
|
+
function deepFreeze(value) {
|
|
4
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
5
|
+
Object.freeze(value);
|
|
6
|
+
for (const child of Object.values(value))
|
|
7
|
+
deepFreeze(child);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
export const campaignManifest = deepFreeze(contentData.campaign);
|
|
12
|
+
export const levelManifest = campaignManifest.levels;
|
|
13
|
+
/** Alias kept alongside other Houseki campaign lesson APIs. */
|
|
14
|
+
export const tutorialManifest = deepFreeze(contentData.lessons);
|
|
15
|
+
export const lessonManifest = tutorialManifest;
|
|
16
|
+
/** Finds a Magnetic Blocks campaign level by stable ID or one-based display number. */
|
|
17
|
+
export function getLevel(id) {
|
|
18
|
+
if (typeof id === 'number')
|
|
19
|
+
return Number.isInteger(id) ? levelManifest.find(level => level.number === id) : undefined;
|
|
20
|
+
return levelManifest.find(level => level.id === id);
|
|
21
|
+
}
|
|
22
|
+
/** Creates a fresh game with the authored rules, board, queue, and finite move budget. */
|
|
23
|
+
export function createLevel(id) {
|
|
24
|
+
const level = getLevel(id);
|
|
25
|
+
if (!level)
|
|
26
|
+
throw new RangeError(`Unknown Magnetic Blocks level: ${String(id)}`);
|
|
27
|
+
return createGame(level.options);
|
|
28
|
+
}
|
|
29
|
+
/** Finds one of the three bilingual rules lessons by stable ID. */
|
|
30
|
+
export function getLesson(id) { return tutorialManifest.find(lesson => lesson.id === id); }
|
|
31
|
+
export const getTutorial = getLesson;
|
|
32
|
+
/** Creates a fresh lesson game with its authored setup and queue. */
|
|
33
|
+
export function createLesson(id) {
|
|
34
|
+
const lesson = getLesson(id);
|
|
35
|
+
if (!lesson)
|
|
36
|
+
throw new RangeError(`Unknown Magnetic Blocks lesson: ${String(id)}`);
|
|
37
|
+
return createGame(lesson.options);
|
|
38
|
+
}
|
|
@@ -38,8 +38,10 @@ function completeGoal(state) {
|
|
|
38
38
|
function spawn(state) {
|
|
39
39
|
if (completeGoal(state))
|
|
40
40
|
return [{ ...state, phase: 'won', active: null, reason: 'goal-complete' }, [{ type: 'run-ended', result: 'won', reason: 'goal-complete', score: state.score }]];
|
|
41
|
-
if (state.placements >= state.settings.pieceLimit || !state.queue.length)
|
|
42
|
-
|
|
41
|
+
if (state.placements >= state.settings.pieceLimit || !state.queue.length) {
|
|
42
|
+
const result = state.settings.goal ? 'lost' : 'finished';
|
|
43
|
+
return [{ ...state, phase: result, active: null, reason: 'queue-exhausted' }, [{ type: 'run-ended', result, reason: 'queue-exhausted', score: state.score }]];
|
|
44
|
+
}
|
|
43
45
|
const [colours, ...rest] = state.queue, gems = colours.map((colour, index) => ({ id: state.nextId + index, colour }));
|
|
44
46
|
const block = freezeBlock({ x: Math.floor(state.settings.width / 2) - 1, y: 0, orientation: 0, gems, descent: 0, lockTicks: 0, lockResets: 0, lockStarted: false });
|
|
45
47
|
const floor = floorAt(state.settings.schedule, state.placements + 1);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { MagneticBlocksOptionsError } from './magnetic-blocks/validation.js';
|
|
2
2
|
export { createGame, applyAction, advanceTicks, legalActions, statusOf } from './magnetic-blocks/engine.js';
|
|
3
3
|
export { encodeGame, decodeGame, restartGame } from './magnetic-blocks/persistence.js';
|
|
4
|
+
export { campaignManifest, levelManifest, tutorialManifest, lessonManifest, getLevel, createLevel, getLesson, getTutorial, createLesson } from './magnetic-blocks/content.js';
|
|
4
5
|
export { blockCells, canPlace, landingY, matchGroups, removeIds, calmGravity, magneticGravity, settle, impactSupportIds, blockBonds, MARK_TICKS, REMOVE_TICKS, GRAVITY_TICKS } from './magnetic-blocks/physics.js';
|
|
5
6
|
export type { Action, Block, Bond, Colour, CreateOptions, Floor, FloorSchedule, GameEvent, GameState, GameStatus, Gem, Goal, Mode, Phase, RecordedAction, Settings, Transition } from './magnetic-blocks/types.js';
|
|
7
|
+
export type { LocalizedText, MagneticCampaignLevel, MagneticCampaignManifest, MagneticDifficultyMetrics, MagneticLesson } from './magnetic-blocks/content-types.js';
|
package/dist/magnetic-blocks.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { MagneticBlocksOptionsError } from './magnetic-blocks/validation.js';
|
|
2
2
|
export { createGame, applyAction, advanceTicks, legalActions, statusOf } from './magnetic-blocks/engine.js';
|
|
3
3
|
export { encodeGame, decodeGame, restartGame } from './magnetic-blocks/persistence.js';
|
|
4
|
+
export { campaignManifest, levelManifest, tutorialManifest, lessonManifest, getLevel, createLevel, getLesson, getTutorial, createLesson } from './magnetic-blocks/content.js';
|
|
4
5
|
export { blockCells, canPlace, landingY, matchGroups, removeIds, calmGravity, magneticGravity, settle, impactSupportIds, blockBonds, MARK_TICKS, REMOVE_TICKS, GRAVITY_TICKS } from './magnetic-blocks/physics.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/houseki",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Houseki
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Houseki 宝石: five original gem and stone puzzle engines, 450 graded challenges, bilingual lessons, deterministic saves, magnetic floors, Shizen and Arashi campaigns. TypeScript. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"puzzle",
|
|
7
7
|
"puzzle-game",
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
"zero-dependencies",
|
|
29
29
|
"browser",
|
|
30
30
|
"node",
|
|
31
|
-
"itsutsu"
|
|
31
|
+
"itsutsu",
|
|
32
|
+
"shizen",
|
|
33
|
+
"arashi",
|
|
34
|
+
"campaign"
|
|
32
35
|
],
|
|
33
36
|
"homepage": "https://johnmorrisdotca.github.io/houseki/",
|
|
34
37
|
"repository": {
|