motely-wasm 23.1.1 → 23.3.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/README.md CHANGED
@@ -1,7 +1,172 @@
1
- # Motely
1
+ # motely-wasm
2
2
 
3
- Motely is a fast Balatro seed searching library. It utilizes your CPU's 512-bit registers along with SIMD to search 8 seeds at once per thread.
4
- It performs very well comapred to current GPU-based balatro seed searches (better in a lot of systems), and is the fastest general purpose CPU based searcher to my knowlegde.
3
+ `motely-wasm` is the Bootsharp/WebAssembly package for MotelyJAML: the production Balatro seed-search engine, JAML loader, JAMLyzer analyzer, JUMMY one-line parser, and selected seed utilities exposed to JavaScript.
5
4
 
6
- Thank you so much to [@OptimusPi](https://github.com/OptimusPi/) for commissioning the development of this library. It started out as a personal projects, but
7
- would not have the capibilities it has today without his support.
5
+ JAML is Jimbo's Ante Markup Language. YAML and JSON are the concrete syntaxes; both load to the same typed `JamlConfig` that the engine executes.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install motely-wasm
11
+ ```
12
+
13
+ ## Boot
14
+
15
+ Bootsharp exports a default runtime object plus named API namespaces. Subscribe to exported events and bind imports before `boot()`.
16
+
17
+ ```js
18
+ import bootsharp, {
19
+ MotelyJaml,
20
+ MotelyJamlyzer,
21
+ MotelySearch,
22
+ Jimmolate,
23
+ } from "motely-wasm";
24
+
25
+ MotelySearch.onProgress.subscribe((p) => {
26
+ console.log(`searched=${p.seedsSearched} matches=${p.matchingSeeds}`);
27
+ });
28
+
29
+ MotelySearch.onSeedMatch.subscribe((seed) => console.log(seed));
30
+ MotelySearch.onScoredResult.subscribe((result) => console.log(result.seed, result.score));
31
+
32
+ Jimmolate.filter = (inst) => true;
33
+
34
+ await bootsharp.boot();
35
+ ```
36
+
37
+ ## Parse and validate JAML
38
+
39
+ Use `fromYaml` or `fromJson` once, then pass the returned `JamlConfig` to analyzer/search calls. Invalid filters fail loudly; unknown keys are not silently ignored.
40
+
41
+ ```js
42
+ const jaml = MotelyJaml.fromYaml(`
43
+ name: example
44
+ deck: Red
45
+ stake: White
46
+ seeds: [AAAAAAAA, BBBBBBBB]
47
+ must:
48
+ - voucher: Overstock
49
+ antes: [1]
50
+ `);
51
+
52
+ const error = MotelyJaml.validate("must: [");
53
+ if (error) console.error(error);
54
+ ```
55
+
56
+ ## Analyze seeds with JAMLyzer
57
+
58
+ ```js
59
+ const results = MotelyJamlyzer.analyzeSeeds(jaml);
60
+ for (const result of results) {
61
+ console.log(result.seed, result.antes[0].voucher, result.antes[0].packs.length);
62
+ }
63
+ ```
64
+
65
+ Scrollable analysis uses the `streamStates` object returned by a previous page. The state is seed-specific, so resume with a single-seed `JamlConfig`.
66
+
67
+ ```js
68
+ const first = MotelyJamlyzer.analyzeSeedsPaged(jaml, 10)[0];
69
+ const next = MotelyJamlyzer.resumeSeeds(jaml, first.streamStates, 10)[0];
70
+ ```
71
+
72
+ ## Search
73
+
74
+ Call it, await it, use it — the promise resolves with the scored results:
75
+
76
+ ```js
77
+ const results = await MotelySearch.searchList(jaml);
78
+ for (const r of results) console.log(r.seed, r.score, r.tallies);
79
+ ```
80
+
81
+ Each result is a `MotelyScoredSeedResult`: `seed` (string), `score` (number), and `tallies` — the raw per-clause hit counts, one per should-clause in JAML order. Tallies cross the boundary as an `Int32Array`; call `Array.from(r.tallies)` when a plain array matters.
82
+
83
+ Events stream alongside for live UIs: `onProgress` ticks while the search runs,
84
+ `onSeedMatch` delivers each bare seed as it's found, `onScoredResult` delivers each typed
85
+ result incrementally.
86
+
87
+ Available modes:
88
+
89
+ ```js
90
+ const fromList = await MotelySearch.searchList(jaml);
91
+ const fromRandom = await MotelySearch.searchRandom(jaml, 1000);
92
+ const fromWalk = await MotelySearch.searchSequential(jaml, 0n, 1n, 1);
93
+ ```
94
+
95
+ `searchSequential` uses bigint batch indices because the C# parameters are `long`.
96
+
97
+ ## Jimmolate
98
+
99
+ Jimmolate is a JS-authored seed filter in the engine filter chain, speaking the real Immolate `.cl` contract: `filter(inst) => score` — a number, and the host sets the bar with a score cutoff. Returning `true`/`false` also works for convenience; booleans coerce to 1/0. The filter receives the live `MotelySingleSearchContext` as an interop instance, so it can drive every query a native C# filter can. Bind it before `boot()`; keep-all (`(inst) => 1`) is the neutral binding.
100
+
101
+ The ante-1 fingerprint filter from the C# unit tests, authored in JS — real voucher and boss queries pulling one needle out of the decoys:
102
+
103
+ ```js
104
+ Jimmolate.filter = (inst) => {
105
+ if (inst.getAnteFirstVoucher(1) !== MotelyVoucher.MagicTrick) return 0;
106
+ const result = inst.getBossForAnteWithState(1, inst.newRunState());
107
+ return result.boss === MotelyBossBlind.TheWindow ? 1 : 0;
108
+ };
109
+ await MotelySearch.searchList(jaml);
110
+ ```
111
+
112
+ A JAML with zero must/should/mustNot clauses (deck, stake, seeds only — the real Immolate shape) is a first-class search: the Jimmolate filter carries the whole decision.
113
+
114
+ Stream walkers that thread `ref` state are C#-only shapes; their state-threaded twins (value in, value out) are the JS-facing equivalents.
115
+
116
+ ## JUMMY
117
+
118
+ JUMMY is one human line per JAML criterion — the terse spelling of a JAML clause, so it lives on `MotelyJaml`. Both calls delegate to the engine's `JummyLine` parser/formatter so packed item identity stays canonical.
119
+
120
+ ```js
121
+ MotelyJaml.validateLine("Eternal Blueprint in antes 1 or 2"); // null
122
+ MotelyJaml.canonicalizeLine("Showman in antes 1, 2"); // "Showman in antes 1 or 2"
123
+ ```
124
+
125
+ ## Vocabulary
126
+
127
+ `MotelyJaml.listItems(kind, query)` serves the real engine vocabulary — jokers, vouchers, tags, bosses, and the rest — for autocomplete and agent grounding. Names come straight from the engine enums, so nothing hand-maintained can drift.
128
+
129
+ ```js
130
+ MotelyJaml.listItems("joker", "lucky"); // ["LuckyCat", ...] — case-insensitive substring match
131
+ ```
132
+
133
+ ## Utilities
134
+
135
+ `MotelyUtilities` exposes seed math and keyword sequence helpers used by the CLI/provider modes.
136
+
137
+ ```js
138
+ MotelyUtilities.seedToTotalIndex("11111111"); // 66231629136n
139
+ MotelyUtilities.totalIndexToSeed(66231629136n); // "11111111"
140
+ MotelyUtilities.searchIndexToSeed(0n, 8); // "11111111"
141
+ MotelyUtilities.repeatCharKeywords(3)[0]; // "AAA"
142
+ ```
143
+
144
+ ## Local development
145
+
146
+ From `Motely.Wasm/`:
147
+
148
+ ```sh
149
+ npm test # publishes the Release build, then runs the Node suite against dist/index.mjs
150
+ npm run test:ui # Playwright drives the real test UI in Chromium against the same artifact
151
+ npm run serve # hand-drive the test UI at http://127.0.0.1:4173/
152
+ npm run pack:check
153
+ ```
154
+
155
+ The test UI (`testui/index.html`) is a plain ES-module page with a CodeMirror 6 editor: live engine-driven lint and completion while you type, a Jimmolate filter box compiled straight into the browser search, and a results table — feedback is continuous, so there is no validate button. The Playwright specs in `tests-ui/` prove the package where UX lives: a real browser.
156
+
157
+ Releasing, from `Motely.Wasm/`: sync `"version"` in `package.json` to `<MotelyVersion>` in the repo-root `Directory.Packages.props`, run `npm test` and `npm run test:ui` green, then `npm publish`.
158
+
159
+ ## Current coverage focus
160
+
161
+ The package test suite mirrors the C# behavior tests that are meaningful through the public WASM surface:
162
+
163
+ - boot/runtime and version export
164
+ - JAML YAML/JSON parse and validation strictness
165
+ - JAMLyzer ante structure, event windows, score-by-analysis, and stream-state resume
166
+ - real list/random/sequential searches
167
+ - Jimmolate accept/reject predicate behavior against the live context
168
+ - AND scoring, default source fallback, Hieroglyph pack-slot reachability, and luck-source regressions
169
+ - JUMMY canonicalization
170
+ - seed math and keyword utility parity
171
+
172
+ Corpus-file loading and live ref-struct seed-router introspection remain native test concerns rather than JavaScript package behavior.