@johnmorrisdotca/houseki 0.3.0 → 0.4.1
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 +26 -1
- package/README.md +11 -11
- package/dist/colour-chains/content-data.js +64280 -6675
- package/dist/colour-chains/content-types.d.ts +46 -0
- package/dist/colour-chains.d.ts +1 -1
- package/dist/gem-swap/persistence.js +5 -3
- package/dist/gem-swap/practice.js +2 -2
- package/dist/magnetic-blocks/content-data.js +18415 -4175
- package/dist/magnetic-blocks/content-types.d.ts +35 -0
- package/package.json +2 -2
|
@@ -14,6 +14,21 @@ export interface ChainDifficultyMetrics {
|
|
|
14
14
|
readonly seededPlayoutVariablePrefixLength?: number;
|
|
15
15
|
/** Number of later witnessed placements held fixed in each seeded playout. */
|
|
16
16
|
readonly seededPlayoutFixedSuffixLength?: number;
|
|
17
|
+
readonly seededPlayoutPlacements?: number;
|
|
18
|
+
readonly fullPlanSuccessRate?: number;
|
|
19
|
+
readonly witnessedPlanPlacements?: number;
|
|
20
|
+
readonly singleStepDeviationProbes?: number;
|
|
21
|
+
readonly singleStepDeviationWins?: number;
|
|
22
|
+
readonly singleStepDeviationDeadEnds?: number;
|
|
23
|
+
readonly branchingDecisionPoints?: number;
|
|
24
|
+
readonly forcedSafeSteps?: number;
|
|
25
|
+
readonly forcedSafeShare?: number;
|
|
26
|
+
readonly branchingShare?: number;
|
|
27
|
+
readonly consequentialDecisionShare?: number;
|
|
28
|
+
readonly setupDeviationProbes?: number;
|
|
29
|
+
readonly setupDeviationLosses?: number;
|
|
30
|
+
readonly setupDeviationLossShare?: number;
|
|
31
|
+
readonly verifiedSetupDependencyShare?: number;
|
|
17
32
|
readonly seededPlayoutSuccesses: number;
|
|
18
33
|
readonly seededPlayoutSuccessRate: number;
|
|
19
34
|
readonly setupPairsBeforePayoff: number;
|
|
@@ -21,7 +36,27 @@ export interface ChainDifficultyMetrics {
|
|
|
21
36
|
readonly verifiedSetupDependencies: number;
|
|
22
37
|
/** Number of pre-payoff steps checked by exhaustive single-step deviations. */
|
|
23
38
|
readonly setupDependencyProbeSteps?: number;
|
|
39
|
+
/** A verified alternate far-side first placement followed by the witnessed recovery pair. */
|
|
40
|
+
readonly verifiedWrongFirstRecovery?: number;
|
|
41
|
+
readonly goalTargets?: number;
|
|
42
|
+
/** Number of distinct target-color components or explicitly required chain waves. */
|
|
43
|
+
readonly goalDependencyCount?: number;
|
|
44
|
+
readonly occupiedCells?: number;
|
|
45
|
+
readonly usableCells?: number;
|
|
46
|
+
readonly boardCoverage?: number;
|
|
47
|
+
readonly goalCoordinationShare?: number;
|
|
48
|
+
readonly cascadeShare?: number;
|
|
49
|
+
readonly weatherEventCount?: number;
|
|
50
|
+
readonly weatherDependency?: number;
|
|
51
|
+
readonly mechanicOffCounterfactualWon?: boolean;
|
|
52
|
+
readonly mechanicOffCounterfactualKind?: 'nature' | 'magnetism' | 'weather';
|
|
53
|
+
readonly mechanicOffCounterfactualPhase?: string;
|
|
54
|
+
readonly rawDifficultyScore?: number;
|
|
24
55
|
readonly requiredChainDepth: number;
|
|
56
|
+
/** Highest chain observed in the exact authored witness. */
|
|
57
|
+
readonly witnessedChainDepth?: number;
|
|
58
|
+
/** Highest chain seen in the bounded random-play sample; not a requirement claim. */
|
|
59
|
+
readonly observedPotentialChainDepth?: number;
|
|
25
60
|
readonly requiredRotations: number;
|
|
26
61
|
readonly requiredWallKicks: number;
|
|
27
62
|
readonly splitLandingDependencies: number;
|
|
@@ -52,12 +87,16 @@ export interface ChainCampaignLevel {
|
|
|
52
87
|
readonly gradingVersion: string;
|
|
53
88
|
readonly proofStatus: 'engine-witness-verified';
|
|
54
89
|
readonly reviewStatus: 'human-review-pending' | 'human-reviewed';
|
|
90
|
+
readonly band?: 'entry' | 'easy' | 'intermediate' | 'hard' | 'expert';
|
|
91
|
+
readonly rawDifficultyScore?: number;
|
|
92
|
+
readonly normalizationCategory?: string;
|
|
55
93
|
}
|
|
56
94
|
export interface NatureChainCampaignLevel extends ChainCampaignLevel {
|
|
57
95
|
readonly objective: LocalizedText;
|
|
58
96
|
readonly nature: true;
|
|
59
97
|
readonly weather?: 'frequent';
|
|
60
98
|
readonly magneticQueue?: readonly (readonly [boolean, boolean])[];
|
|
99
|
+
readonly weatherTrace?: readonly Readonly<Record<string, unknown>>[];
|
|
61
100
|
}
|
|
62
101
|
export interface ChainCampaignManifest {
|
|
63
102
|
readonly count: number;
|
|
@@ -72,8 +111,15 @@ export interface ChainCampaignManifest {
|
|
|
72
111
|
readonly checksum: string;
|
|
73
112
|
readonly levels: readonly ChainCampaignLevel[];
|
|
74
113
|
}
|
|
114
|
+
export interface NatureCampaignBand {
|
|
115
|
+
readonly id: 'entry' | 'easy' | 'intermediate' | 'hard' | 'expert';
|
|
116
|
+
readonly count: number;
|
|
117
|
+
readonly first: number;
|
|
118
|
+
readonly last: number;
|
|
119
|
+
}
|
|
75
120
|
export interface NatureChainCampaignManifest extends Omit<ChainCampaignManifest, 'levels'> {
|
|
76
121
|
readonly levels: readonly NatureChainCampaignLevel[];
|
|
122
|
+
readonly bands?: readonly NatureCampaignBand[];
|
|
77
123
|
}
|
|
78
124
|
export interface ChainTutorialStep {
|
|
79
125
|
readonly instruction: LocalizedText;
|
package/dist/colour-chains.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ export { createChallenge } from './colour-chains/challenge.js';
|
|
|
5
5
|
export { restartGame, encodeGame, decodeGame } from './colour-chains/persistence.js';
|
|
6
6
|
export { createInputScheduler, setHeldInput, queueInputEdge, releaseAllInput, actionsForTick, applyScheduledActions, processInputTick } from './colour-chains/input.js';
|
|
7
7
|
export { campaignManifest, levelManifest, tutorialManifest, getLevel, createLevel, getTutorial, shizenCampaignManifest, shizenLevelManifest, getShizenLevel, createShizenLevel, arashiCampaignManifest, arashiLevelManifest, getArashiLevel, createArashiLevel } from './colour-chains/content.js';
|
|
8
|
-
export type { LocalizedText, ChainDifficultyMetrics, ChainCampaignLevel, ChainCampaignManifest, NatureChainCampaignLevel, NatureChainCampaignManifest, ChainTutorialStep, ChainTutorialDefinition, ChainContentData } from './colour-chains/content-types.js';
|
|
8
|
+
export type { LocalizedText, ChainDifficultyMetrics, ChainCampaignLevel, ChainCampaignManifest, NatureChainCampaignLevel, NatureChainCampaignManifest, NatureCampaignBand, ChainTutorialStep, ChainTutorialDefinition, ChainContentData } from './colour-chains/content-types.js';
|
|
@@ -8,12 +8,14 @@ export class ReplayError extends TypeError {
|
|
|
8
8
|
code;
|
|
9
9
|
constructor(code, message) { super(message); this.name = 'ReplayError'; this.code = code; }
|
|
10
10
|
}
|
|
11
|
-
function canonical(value) {
|
|
11
|
+
function canonical(value, depth = 0) {
|
|
12
|
+
if (depth > 50)
|
|
13
|
+
throw new ReplayError('save-too-deep', 'Replay is nested too deeply');
|
|
12
14
|
if (Array.isArray(value))
|
|
13
|
-
return `[${value.map(canonical).join(',')}]`;
|
|
15
|
+
return `[${value.map(item => canonical(item, depth + 1)).join(',')}]`;
|
|
14
16
|
if (value && typeof value === 'object') {
|
|
15
17
|
const object = value;
|
|
16
|
-
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${canonical(object[key])}`).join(',')}}`;
|
|
18
|
+
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${canonical(object[key], depth + 1)}`).join(',')}}`;
|
|
17
19
|
}
|
|
18
20
|
return JSON.stringify(value);
|
|
19
21
|
}
|
|
@@ -35,7 +35,7 @@ export function reshuffleTransition(state) {
|
|
|
35
35
|
const finishedRelaxed = state.mode === 'relaxed' && state.phase === 'finished' && state.outcome === 'finished' && !findMatches(state.board, state.settings).length;
|
|
36
36
|
if (state.mode !== 'relaxed' || (!onReady(state) && !finishedRelaxed) || state.selectedTool)
|
|
37
37
|
return rejected(state, 'reshuffle-unavailable');
|
|
38
|
-
const gems = state.board.filter((item) => item !== null);
|
|
38
|
+
const gems = state.board.filter((item, index) => item !== null && index !== state.blackHole?.cell);
|
|
39
39
|
let randomState = state.randomState;
|
|
40
40
|
for (let attempt = 0; attempt < 128; attempt++) {
|
|
41
41
|
const shuffled = [...gems];
|
|
@@ -47,7 +47,7 @@ export function reshuffleTransition(state) {
|
|
|
47
47
|
const board = [...state.board];
|
|
48
48
|
let at = 0;
|
|
49
49
|
for (let index = 0; index < board.length; index++)
|
|
50
|
-
if (state.settings.mask[index])
|
|
50
|
+
if (state.settings.mask[index] && index !== state.blackHole?.cell)
|
|
51
51
|
board[index] = shuffled[at++];
|
|
52
52
|
if (!findMatches(board, state.settings).length && listLegalSwaps({ ...state, board }).length) {
|
|
53
53
|
return { state: Object.freeze({ ...state, board: Object.freeze(board), randomState, assisted: true, phase: 'ready', outcome: null, selectedTool: null, toolTarget: null, toolPreview: Object.freeze([]) }), events: Object.freeze([{ type: 'board-reshuffled', attempts: attempt + 1, assisted: true }]), accepted: true };
|