@datamoc/mw_games 0.23.0 → 0.24.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.
@@ -0,0 +1,143 @@
1
+ import { Generator } from '../core/Random.ts';
2
+ import type { NeuralModel, NeuralObservation } from '../ai/Neural.ts';
3
+ import type { SimulationRule, SimulationStep } from './Scenario.ts';
4
+ export interface TrainingRules<State, Command, Event> {
5
+ observationVersion: string;
6
+ initial(random: Generator): State;
7
+ /** Same rule used by the playable game; a command may advance a turn or fixed ticks. */
8
+ rule: SimulationRule<State, Command, Event, Generator>;
9
+ observe(state: State): readonly NeuralObservation[];
10
+ command(state: State, actions: readonly (number | null)[]): Command;
11
+ /** One reward per agent, in the observation's stable roster order. */
12
+ rewards(before: State, command: Command, outcome: SimulationStep<State, Event>): readonly number[];
13
+ /** Detect an already-terminal reset, without taking a dummy action. */
14
+ finished?(state: State): boolean;
15
+ }
16
+ export interface TrainingFrame {
17
+ observations: readonly NeuralObservation[];
18
+ rewards: readonly number[];
19
+ terminated: boolean;
20
+ truncated: boolean;
21
+ }
22
+ export interface TrainingSnapshot<State> {
23
+ version: 1;
24
+ observationVersion: string;
25
+ state: State;
26
+ seed: number;
27
+ random: readonly [number, number, number, number];
28
+ steps: number;
29
+ maxSteps: number;
30
+ terminated: boolean;
31
+ truncated: boolean;
32
+ }
33
+ /** A trainer persists its optimizer/exploration state alongside the environment and model. */
34
+ export interface TrainingCheckpoint<State, TrainerState> {
35
+ version: 1;
36
+ model: NeuralModel;
37
+ environment: TrainingSnapshot<State>;
38
+ trainerState: TrainerState;
39
+ }
40
+ /**
41
+ * Seeded, UI-free reset/step adapter over a game's existing SimulationRule.
42
+ * Observations and rewards use a fixed agent roster within each episode. A null
43
+ * action is legal only when all actions for that agent are masked. The rule owns
44
+ * idle semantics. No presentation events or command journal are retained.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { TrainingEnvironment } from '@datamoc/mw_games/simulation';
49
+ * const env = new TrainingEnvironment({ observationVersion: 'counter-v1',
50
+ * initial: () => ({ x: 0 }), observe: s => [{ input: [s.x], mask: [true] }],
51
+ * command: (_s, actions) => actions[0],
52
+ * rule: s => ({ state: { x: s.x + 1 }, events: [], status: 'ready' }),
53
+ * rewards: () => [1],
54
+ * }, { maxSteps: 10 });
55
+ * env.reset(7);
56
+ * const frame = env.step([0]);
57
+ * const checkpoint = env.snapshot();
58
+ * env.restore(checkpoint); // resumes state and RNG, without replaying reset
59
+ * ```
60
+ */
61
+ export declare class TrainingEnvironment<State, Command, Event> {
62
+ private state;
63
+ private random;
64
+ private steps;
65
+ private terminated;
66
+ private ready;
67
+ private agentCount;
68
+ readonly maxSteps: number;
69
+ readonly observationVersion: string;
70
+ private readonly rules;
71
+ private readonly Random;
72
+ private get truncated();
73
+ constructor(rules: TrainingRules<State, Command, Event>, options: {
74
+ maxSteps: number;
75
+ }, Random?: typeof Generator);
76
+ reset(seed: number): TrainingFrame;
77
+ step(actions: readonly (number | null)[]): TrainingFrame;
78
+ snapshot(): TrainingSnapshot<State>;
79
+ restore(snapshot: TrainingSnapshot<State>): TrainingFrame;
80
+ private observations;
81
+ }
82
+ export interface RolloutOptions {
83
+ seeds: readonly number[];
84
+ /** Sample softmax scores using a separate seeded stream, leaving game RNG unchanged. */
85
+ sample?: boolean;
86
+ /** First transitions per episode to keep; defaults to zero, at most 10000 total per batch. */
87
+ trajectoryLimit?: number;
88
+ signal?: AbortSignal;
89
+ }
90
+ export interface TrainingTransition {
91
+ before: TrainingFrame;
92
+ actions: readonly (number | null)[];
93
+ after: TrainingFrame;
94
+ }
95
+ export interface RolloutEpisode {
96
+ seed: number;
97
+ steps: number;
98
+ rewards: number[];
99
+ terminated: boolean;
100
+ truncated: boolean;
101
+ trajectory: TrainingTransition[];
102
+ }
103
+ /**
104
+ * Interactive rollouts at simulation speed, with a fresh seeded reset per episode.
105
+ * The evaluator is created once per batch and shares its buffers across agents.
106
+ * A synchronous signal is checked between steps; cancellation from another event
107
+ * on the same thread requires the async worker path.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * import { runRollouts, TrainingEnvironment } from '@datamoc/mw_games/simulation';
112
+ * import type { NeuralModel } from '@datamoc/mw_games/ai';
113
+ * declare const env: TrainingEnvironment<{ x: number }, number, never>;
114
+ * declare const model: NeuralModel;
115
+ * const episodes = runRollouts(env, model, { seeds: [1, 2, 3], trajectoryLimit: 2 });
116
+ * ```
117
+ */
118
+ export declare function runRollouts<State, Command, Event>(environment: TrainingEnvironment<State, Command, Event>, model: NeuralModel, options: RolloutOptions): RolloutEpisode[];
119
+ /** Factory must be self-contained, like threads.spawn; use the supplied constructor rather than imports. */
120
+ export type TrainingFactory<Config, State, Command, Event> = (tools: {
121
+ TrainingEnvironment: typeof TrainingEnvironment;
122
+ }, config: Config) => TrainingEnvironment<State, Command, Event>;
123
+ /**
124
+ * One worker per episode shard, with isolated environments and bounded concurrency.
125
+ * A model and environment stay loaded for the shard's whole batch. Returned episodes
126
+ * stay in seed order independent of worker completion order. Abort or failure kills
127
+ * every lane; no partial result is applied to a game. Keep the factory self-contained
128
+ * and pass structured-cloneable configuration, not closures or class instances.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * import { runRolloutsAsync, type TrainingFactory } from '@datamoc/mw_games/simulation';
133
+ * import type { NeuralModel } from '@datamoc/mw_games/ai';
134
+ * declare const factory: TrainingFactory<{ maxSteps: number }, { x: number }, number, never>;
135
+ * declare const model: NeuralModel;
136
+ * const episodes = await runRolloutsAsync(factory, { maxSteps: 20 }, model, { seeds: [1, 2], jobs: 2 });
137
+ * ```
138
+ */
139
+ export declare function runRolloutsAsync<Config, State, Command, Event>(factory: TrainingFactory<Config, State, Command, Event>, config: Config, model: NeuralModel, options: RolloutOptions & {
140
+ jobs?: number;
141
+ timeout?: number;
142
+ }): Promise<RolloutEpisode[]>;
143
+ //# sourceMappingURL=Training.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Training.d.ts","sourceRoot":"","sources":["../../src/simulation/Training.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,279 @@
1
+ import { Generator } from '../core/Random.js';
2
+ import { createNeuralEvaluator } from '../ai/Neural.js';
3
+ import { spawn } from '../threads/index.js';
4
+ /**
5
+ * Seeded, UI-free reset/step adapter over a game's existing SimulationRule.
6
+ * Observations and rewards use a fixed agent roster within each episode. A null
7
+ * action is legal only when all actions for that agent are masked. The rule owns
8
+ * idle semantics. No presentation events or command journal are retained.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { TrainingEnvironment } from '@datamoc/mw_games/simulation';
13
+ * const env = new TrainingEnvironment({ observationVersion: 'counter-v1',
14
+ * initial: () => ({ x: 0 }), observe: s => [{ input: [s.x], mask: [true] }],
15
+ * command: (_s, actions) => actions[0],
16
+ * rule: s => ({ state: { x: s.x + 1 }, events: [], status: 'ready' }),
17
+ * rewards: () => [1],
18
+ * }, { maxSteps: 10 });
19
+ * env.reset(7);
20
+ * const frame = env.step([0]);
21
+ * const checkpoint = env.snapshot();
22
+ * env.restore(checkpoint); // resumes state and RNG, without replaying reset
23
+ * ```
24
+ */
25
+ export class TrainingEnvironment {
26
+ get truncated() {
27
+ return !this.terminated && this.steps >= this.maxSteps;
28
+ }
29
+ constructor(rules, options, Random = Generator) {
30
+ this.steps = 0;
31
+ this.terminated = false;
32
+ this.ready = false;
33
+ this.agentCount = 0;
34
+ this.rules = rules;
35
+ this.Random = Random;
36
+ this.random = new this.Random(0);
37
+ if (!Number.isInteger(options.maxSteps) || options.maxSteps < 1 || options.maxSteps > 1_000_000)
38
+ throw new RangeError('training maxSteps must be in 1..1000000');
39
+ if (typeof rules.observationVersion !== 'string' || !rules.observationVersion.length)
40
+ throw new TypeError('training requires an observation version');
41
+ this.maxSteps = options.maxSteps;
42
+ this.observationVersion = rules.observationVersion;
43
+ }
44
+ reset(seed) {
45
+ if (!Number.isInteger(seed) || seed < 0 || seed > 0xffffffff)
46
+ throw new RangeError('training seed must be uint32');
47
+ this.random = new this.Random(seed);
48
+ this.state = this.rules.initial(this.random);
49
+ this.steps = 0;
50
+ this.terminated = this.rules.finished?.(this.state) ?? false;
51
+ this.ready = true;
52
+ const observations = this.observations();
53
+ this.agentCount = observations.length;
54
+ return { observations, rewards: observations.map(() => 0), terminated: this.terminated, truncated: false };
55
+ }
56
+ step(actions) {
57
+ if (!this.ready || this.terminated || this.truncated)
58
+ throw new Error('training episode needs reset before step');
59
+ const observations = this.observations();
60
+ if (actions.length !== this.agentCount)
61
+ throw new RangeError('training action count must match the agent roster');
62
+ for (let i = 0; i < actions.length; i++) {
63
+ const action = actions[i];
64
+ const mask = observations[i].mask;
65
+ if (action === null
66
+ ? !mask || mask.some(Boolean)
67
+ : !Number.isInteger(action) || action < 0 || (mask && (action >= mask.length || !mask[action])))
68
+ throw new RangeError('training action is not legal');
69
+ }
70
+ //Rewards can inspect a mutable rule's pre-transition state without keeping a history.
71
+ const before = structuredClone(this.state);
72
+ const command = this.rules.command(this.state, actions);
73
+ const outcome = this.rules.rule(this.state, command, this.random);
74
+ const rewards = Array.from(this.rules.rewards(before, command, outcome));
75
+ if (rewards.length !== this.agentCount || !rewards.every(Number.isFinite))
76
+ throw new TypeError('training rewards must be finite and match the agent roster');
77
+ this.state = outcome.state;
78
+ this.steps++;
79
+ this.terminated = outcome.status === 'finished';
80
+ const next = this.observations();
81
+ if (next.length !== this.agentCount)
82
+ throw new RangeError('training agent roster changed during an episode');
83
+ return { observations: next, rewards, terminated: this.terminated, truncated: this.truncated };
84
+ }
85
+ snapshot() {
86
+ if (!this.ready)
87
+ throw new Error('training environment needs reset before snapshot');
88
+ return structuredClone({
89
+ version: 1,
90
+ observationVersion: this.observationVersion,
91
+ state: this.state,
92
+ seed: this.random.seed,
93
+ random: this.random.getState().map((value) => value >>> 0),
94
+ steps: this.steps,
95
+ maxSteps: this.maxSteps,
96
+ terminated: this.terminated,
97
+ truncated: this.truncated,
98
+ });
99
+ }
100
+ restore(snapshot) {
101
+ if (snapshot.version !== 1 ||
102
+ snapshot.observationVersion !== this.observationVersion ||
103
+ snapshot.maxSteps !== this.maxSteps)
104
+ throw new TypeError('training snapshot version, schema or step limit does not match');
105
+ if (!Number.isInteger(snapshot.steps) ||
106
+ snapshot.steps < 0 ||
107
+ snapshot.steps > this.maxSteps ||
108
+ !Number.isInteger(snapshot.seed) ||
109
+ snapshot.seed < 0 ||
110
+ snapshot.seed > 0xffffffff ||
111
+ !Array.isArray(snapshot.random) ||
112
+ snapshot.random.length !== 4 ||
113
+ !snapshot.random.every((value) => Number.isInteger(value) && value >= 0 && value <= 0xffffffff) ||
114
+ !snapshot.random.some((value) => value !== 0) ||
115
+ typeof snapshot.terminated !== 'boolean' ||
116
+ typeof snapshot.truncated !== 'boolean' ||
117
+ (snapshot.terminated && snapshot.truncated) ||
118
+ snapshot.truncated !== (!snapshot.terminated && snapshot.steps === this.maxSteps))
119
+ throw new TypeError('invalid training snapshot');
120
+ this.state = structuredClone(snapshot.state);
121
+ this.random = new this.Random(snapshot.seed);
122
+ this.random.setState(snapshot.random);
123
+ this.steps = snapshot.steps;
124
+ this.terminated = snapshot.terminated;
125
+ this.ready = true;
126
+ const observations = this.observations();
127
+ this.agentCount = observations.length;
128
+ return {
129
+ observations,
130
+ rewards: observations.map(() => 0),
131
+ terminated: this.terminated,
132
+ truncated: this.truncated,
133
+ };
134
+ }
135
+ observations() {
136
+ const observations = structuredClone(Array.from(this.rules.observe(this.state)));
137
+ if (!observations.length || observations.length > 4096)
138
+ throw new RangeError('training requires 1..4096 agents');
139
+ for (const observation of observations) {
140
+ if (!observation.input.length ||
141
+ observation.input.length > 4096 ||
142
+ !Array.from(observation.input).every(Number.isFinite) ||
143
+ (observation.mask &&
144
+ (!observation.mask.length ||
145
+ observation.mask.length > 4096 ||
146
+ !Array.from(observation.mask).every((value) => typeof value === 'boolean'))))
147
+ throw new TypeError('invalid training observation');
148
+ }
149
+ return observations;
150
+ }
151
+ }
152
+ /**
153
+ * Interactive rollouts at simulation speed, with a fresh seeded reset per episode.
154
+ * The evaluator is created once per batch and shares its buffers across agents.
155
+ * A synchronous signal is checked between steps; cancellation from another event
156
+ * on the same thread requires the async worker path.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * import { runRollouts, TrainingEnvironment } from '@datamoc/mw_games/simulation';
161
+ * import type { NeuralModel } from '@datamoc/mw_games/ai';
162
+ * declare const env: TrainingEnvironment<{ x: number }, number, never>;
163
+ * declare const model: NeuralModel;
164
+ * const episodes = runRollouts(env, model, { seeds: [1, 2, 3], trajectoryLimit: 2 });
165
+ * ```
166
+ */
167
+ export function runRollouts(environment, model, options) {
168
+ validateRolloutOptions(options);
169
+ return rolloutKernel(environment, model, options, { Generator, createNeuralEvaluator });
170
+ }
171
+ function validateRolloutOptions(options) {
172
+ const limit = options.trajectoryLimit ?? 0;
173
+ if (!options.seeds.length ||
174
+ options.seeds.length > 10000 ||
175
+ !Array.from(options.seeds).every((seed) => Number.isInteger(seed) && seed >= 0 && seed <= 0xffffffff) ||
176
+ !Number.isInteger(limit) ||
177
+ limit < 0 ||
178
+ limit * options.seeds.length > 10000)
179
+ throw new RangeError('rollouts require 1..10000 uint32 seeds and at most 10000 stored transitions');
180
+ }
181
+ //Explicit dependencies survive identifier renaming in a bundled file:// game.
182
+ function rolloutKernel(environment, model, options, tools) {
183
+ if (model.observationVersion !== environment.observationVersion)
184
+ throw new TypeError('model observation schema does not match environment');
185
+ const limit = options.trajectoryLimit ?? 0;
186
+ const policy = tools.createNeuralEvaluator(model);
187
+ return Array.from(options.seeds, (seed) => {
188
+ if (options.signal?.aborted)
189
+ throw options.signal.reason;
190
+ const random = new tools.Generator((seed ^ 0x9e3779b9) >>> 0);
191
+ let frame = environment.reset(seed);
192
+ const rewards = frame.rewards.map(() => 0);
193
+ const trajectory = [];
194
+ let steps = 0;
195
+ while (!frame.terminated && !frame.truncated) {
196
+ if (options.signal?.aborted)
197
+ throw options.signal.reason;
198
+ const actions = frame.observations.map((observation) => policy.select(observation, options.sample ? () => random.float() : undefined));
199
+ const next = environment.step(actions);
200
+ for (let i = 0; i < rewards.length; i++) {
201
+ rewards[i] += next.rewards[i];
202
+ if (!Number.isFinite(rewards[i]))
203
+ throw new RangeError('training cumulative reward overflow');
204
+ }
205
+ if (trajectory.length < limit)
206
+ trajectory.push({ before: frame, actions, after: next });
207
+ frame = next;
208
+ steps++;
209
+ }
210
+ return { seed, steps, rewards, terminated: frame.terminated, truncated: frame.truncated, trajectory };
211
+ });
212
+ }
213
+ //Rehydrate the very same classes and runner, not a second implementation of simulation or inference.
214
+ function rolloutBatch(sources, config, model, options) {
215
+ const Generator = new Function(`return (${sources[0]});`)();
216
+ const createNeuralEvaluator = new Function(`return (${sources[1]});`)();
217
+ const Environment = new Function(`return (${sources[2]});`)();
218
+ //The serialized class's optional RNG default may be renamed by a bundler.
219
+ //Always inject it explicitly, so that expression is never evaluated in a worker.
220
+ const TrainingEnvironment = class extends Environment {
221
+ constructor(rules, options) {
222
+ super(rules, options, Generator);
223
+ }
224
+ };
225
+ const run = new Function(`return (${sources[3]});`)();
226
+ const factory = new Function(`return (${sources[4]});`)();
227
+ return run(factory({ TrainingEnvironment }, config), model, options, { Generator, createNeuralEvaluator });
228
+ }
229
+ /**
230
+ * One worker per episode shard, with isolated environments and bounded concurrency.
231
+ * A model and environment stay loaded for the shard's whole batch. Returned episodes
232
+ * stay in seed order independent of worker completion order. Abort or failure kills
233
+ * every lane; no partial result is applied to a game. Keep the factory self-contained
234
+ * and pass structured-cloneable configuration, not closures or class instances.
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * import { runRolloutsAsync, type TrainingFactory } from '@datamoc/mw_games/simulation';
239
+ * import type { NeuralModel } from '@datamoc/mw_games/ai';
240
+ * declare const factory: TrainingFactory<{ maxSteps: number }, { x: number }, number, never>;
241
+ * declare const model: NeuralModel;
242
+ * const episodes = await runRolloutsAsync(factory, { maxSteps: 20 }, model, { seeds: [1, 2], jobs: 2 });
243
+ * ```
244
+ */
245
+ export async function runRolloutsAsync(factory, config, model, options) {
246
+ const jobs = options.jobs ?? 4;
247
+ if (!Number.isInteger(jobs) || jobs < 1 || jobs > 64)
248
+ throw new RangeError('rollout jobs must be in 1..64');
249
+ if (options.signal?.aborted)
250
+ throw options.signal.reason;
251
+ //Validate and bound the whole batch before sharding, without taking a simulation step.
252
+ const limit = options.trajectoryLimit ?? 0;
253
+ validateRolloutOptions(options);
254
+ createNeuralEvaluator(model);
255
+ const abort = new AbortController();
256
+ const cancel = () => abort.abort(options.signal?.reason);
257
+ options.signal?.addEventListener('abort', cancel, { once: true });
258
+ const sources = [
259
+ Generator.toString(),
260
+ createNeuralEvaluator.toString(),
261
+ TrainingEnvironment.toString(),
262
+ rolloutKernel.toString(),
263
+ factory.toString(),
264
+ ];
265
+ const lanes = Math.min(jobs, options.seeds.length);
266
+ try {
267
+ return (await Promise.all(Array.from({ length: lanes }, (_, lane) => {
268
+ const start = Math.floor((lane * options.seeds.length) / lanes);
269
+ const end = Math.floor(((lane + 1) * options.seeds.length) / lanes);
270
+ const seeds = options.seeds.slice(start, end);
271
+ return spawn(rolloutBatch, [sources, config, model, { seeds, sample: options.sample, trajectoryLimit: limit }], { signal: abort.signal, timeout: options.timeout });
272
+ }))).flat();
273
+ }
274
+ finally {
275
+ abort.abort();
276
+ options.signal?.removeEventListener('abort', cancel);
277
+ }
278
+ }
279
+ //# sourceMappingURL=Training.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Training.js","sourceRoot":"","sources":["../../src/simulation/Training.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AA2C5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,mBAAmB;IAY/B,IAAY,SAAS;QACpB,OAAO,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC;IACxD,CAAC;IAED,YAAY,KAA2C,EAAE,OAA6B,EAAE,MAAM,GAAG,SAAS;QAblG,UAAK,GAAG,CAAC,CAAC;QACV,eAAU,GAAG,KAAK,CAAC;QACnB,UAAK,GAAG,KAAK,CAAC;QACd,eAAU,GAAG,CAAC,CAAC;QAWtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,SAAS;YAC9F,MAAM,IAAI,UAAU,CAAC,yCAAyC,CAAC,CAAC;QACjE,IAAI,OAAO,KAAK,CAAC,kBAAkB,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM;YACnF,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACjE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,IAAY;QACjB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,UAAU;YAC3D,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;QAC7D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;QACtC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC5G,CAAC;IAED,IAAI,CAAC,OAAmC;QACvC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS;YACnD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU;YACrC,MAAM,IAAI,UAAU,CAAC,mDAAmD,CAAC,CAAC;QAC3E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAClC,IACC,MAAM,KAAK,IAAI;gBACd,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC7B,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;gBAEhG,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;QACvD,CAAC;QACD,sFAAsF;QACtF,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACzE,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;YACxE,MAAM,IAAI,SAAS,CAAC,4DAA4D,CAAC,CAAC;QACnF,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,UAAU,CAAC,iDAAiD,CAAC,CAAC;QAC7G,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IAChG,CAAC;IAED,QAAQ;QACP,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACrF,OAAO,eAAe,CAAC;YACtB,OAAO,EAAE,CAAC;YACV,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAqC;YAC9F,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;SACzB,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,QAAiC;QACxC,IACC,QAAQ,CAAC,OAAO,KAAK,CAAC;YACtB,QAAQ,CAAC,kBAAkB,KAAK,IAAI,CAAC,kBAAkB;YACvD,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;YAEnC,MAAM,IAAI,SAAS,CAAC,gEAAgE,CAAC,CAAC;QACvF,IACC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YACjC,QAAQ,CAAC,KAAK,GAAG,CAAC;YAClB,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ;YAC9B,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;YAChC,QAAQ,CAAC,IAAI,GAAG,CAAC;YACjB,QAAQ,CAAC,IAAI,GAAG,UAAU;YAC1B,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC/B,QAAQ,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAC5B,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,UAAU,CAAC;YAC/F,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC;YAC7C,OAAO,QAAQ,CAAC,UAAU,KAAK,SAAS;YACxC,OAAO,QAAQ,CAAC,SAAS,KAAK,SAAS;YACvC,CAAC,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,SAAS,CAAC;YAC3C,QAAQ,CAAC,SAAS,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC;YAEjF,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;QACtC,OAAO;YACN,YAAY;YACZ,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAClC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;SACzB,CAAC;IACH,CAAC;IAEO,YAAY;QACnB,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjF,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,GAAG,IAAI;YACrD,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;QAC1D,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACxC,IACC,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM;gBACzB,WAAW,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI;gBAC/B,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACrD,CAAC,WAAW,CAAC,IAAI;oBAChB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM;wBACxB,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI;wBAC9B,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;gBAE9E,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,YAAY,CAAC;IACrB,CAAC;CACD;AA0BD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAC1B,WAAuD,EACvD,KAAkB,EAClB,OAAuB;IAEvB,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,aAAa,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAuB;IACtD,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,CAAC;IAC3C,IACC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM;QACrB,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK;QAC5B,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,UAAU,CAAC;QACrG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;QACxB,KAAK,GAAG,CAAC;QACT,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK;QAEpC,MAAM,IAAI,UAAU,CAAC,6EAA6E,CAAC,CAAC;AACtG,CAAC;AAED,8EAA8E;AAC9E,SAAS,aAAa,CACrB,WAAuD,EACvD,KAAkB,EAClB,OAAuB,EACvB,KAA2F;IAE3F,IAAI,KAAK,CAAC,kBAAkB,KAAK,WAAW,CAAC,kBAAkB;QAC9D,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE;QACzC,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,IAAI,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAyB,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YAC9C,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;gBAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YACzD,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CACtD,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAC7E,CAAC;YACF,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBAAE,MAAM,IAAI,UAAU,CAAC,qCAAqC,CAAC,CAAC;YAC/F,CAAC;YACD,IAAI,UAAU,CAAC,MAAM,GAAG,KAAK;gBAAE,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACxF,KAAK,GAAG,IAAI,CAAC;YACb,KAAK,EAAE,CAAC;QACT,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;IACvG,CAAC,CAAC,CAAC;AACJ,CAAC;AAQD,qGAAqG;AACrG,SAAS,YAAY,CACpB,OAAiB,EACjB,MAAe,EACf,KAAkB,EAClB,OAAuB;IAEvB,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5D,MAAM,qBAAqB,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACxE,MAAM,WAAW,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9D,0EAA0E;IAC1E,iFAAiF;IACjF,MAAM,mBAAmB,GAAG,KAAM,SAAQ,WAAW;QACpD,YAAY,KAAc,EAAE,OAAgB;YAC3C,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAClC,CAAC;KACD,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1D,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,mBAAmB,EAAE,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC,CAAC;AAC5G,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,OAAuD,EACvD,MAAc,EACd,KAAkB,EAClB,OAA6D;IAE7D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;IAC5G,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;QAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IACzD,uFAAuF;IACvF,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,CAAC;IAC3C,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,GAAS,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG;QACf,SAAS,CAAC,QAAQ,EAAE;QACpB,qBAAqB,CAAC,QAAQ,EAAE;QAChC,mBAAmB,CAAC,QAAQ,EAAE;QAC9B,aAAa,CAAC,QAAQ,EAAE;QACxB,OAAO,CAAC,QAAQ,EAAE;KAClB,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC;QACJ,OAAO,CACN,MAAM,OAAO,CAAC,GAAG,CAChB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;YAChE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;YACpE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,KAAK,CACX,YAAY,EACZ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,EACnF,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAClD,CAAC;QACH,CAAC,CAAC,CACF,CACD,CAAC,IAAI,EAAE,CAAC;IACV,CAAC;YAAS,CAAC;QACV,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;AACF,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export { advanceToInput } from './Turns.ts';
2
+ export { TrainingEnvironment, runRollouts, runRolloutsAsync } from './Training.ts';
3
+ export type { TrainingRules, TrainingFrame, TrainingSnapshot, TrainingCheckpoint, TrainingTransition, TrainingFactory, RolloutOptions, RolloutEpisode, } from './Training.ts';
2
4
  export type { ScheduledTurns, TurnRules, TurnResult } from './Turns.ts';
3
5
  export { runScenario } from './Scenario.ts';
4
6
  export type { SimulationStatus, SimulationStep, SimulationRule, Scenario, ScenarioResult } from './Scenario.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/simulation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC3E,YAAY,EACX,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,qBAAqB,EACrB,kBAAkB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE9E;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,YAAY,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/simulation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnF,YAAY,EACX,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC3E,YAAY,EACX,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,qBAAqB,EACrB,kBAAkB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE9E;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,YAAY,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export { advanceToInput } from './Turns.js';
2
+ export { TrainingEnvironment, runRollouts, runRolloutsAsync } from './Training.js';
2
3
  export { runScenario } from './Scenario.js';
3
4
  export { Campaign } from './Campaign.js';
4
5
  export { runHeadlessScenario } from './Harness.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/simulation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/simulation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAYnF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC"}
package/dist/version.d.ts CHANGED
@@ -9,5 +9,5 @@
9
9
  * this from `package.json` automatically, chosen because this project's own build already
10
10
  * has no step before `tsc`/`vite` that this would need to run ahead of.
11
11
  */
12
- export declare const version = "0.23.0";
12
+ export declare const version = "0.24.0";
13
13
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -9,5 +9,5 @@
9
9
  * this from `package.json` automatically, chosen because this project's own build already
10
10
  * has no step before `tsc`/`vite` that this would need to run ahead of.
11
11
  */
12
- export const version = '0.23.0';
12
+ export const version = '0.24.0';
13
13
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datamoc/mw_games",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "A local-file game framework: renderer-free game logic, drawn through PixiJS in 2D or Babylon.js in 3D, with mobile and desktop packaging.",
5
5
  "license": "MPL-2.0",
6
6
  "repository": {
@@ -306,6 +306,15 @@
306
306
  "example:event-system": "vite --config examples/event-system/vite.config.ts",
307
307
  "example:event-system:build": "vite build --config examples/event-system/vite.config.ts && node tools/emit-page.mjs examples/event-system --assets=examples/assets",
308
308
  "example:headless": "vite --config examples/headless/vite.config.ts",
309
+ "train:neural": "node tools/train-neural.ts",
310
+ "train:pacman": "node tools/train-pacman.ts",
311
+ "example:pacman": "vite --config examples/pacman/vite.config.ts",
312
+ "example:pacman:build": "vite build --config examples/pacman/vite.config.ts && node tools/emit-page.mjs examples/pacman --assets=examples/assets",
313
+ "pacman:browser:check": "npm run example:pacman:build && node tools/check-pacman-browser.mjs",
314
+ "benchmark:neural": "node tools/benchmark-neural.ts",
315
+ "example:neural": "vite --config examples/neural/vite.config.ts",
316
+ "example:neural:build": "vite build --config examples/neural/vite.config.ts && node tools/emit-page.mjs examples/neural --assets=examples/assets",
317
+ "neural:browser:check": "npm run example:neural:build && node tools/check-neural-browser.mjs",
309
318
  "example:headless:build": "vite build --config examples/headless/vite.config.ts && node tools/emit-page.mjs examples/headless --assets=examples/assets",
310
319
  "example:mwl-content": "vite --config examples/mwl-content/vite.config.ts",
311
320
  "example:mwl-content:build": "npm run mwl -- build examples/mwl-content/content -o examples/mwl-content/generated && vite build --config examples/mwl-content/vite.config.ts && node tools/emit-page.mjs examples/mwl-content --assets=examples/assets",
package/sbom.cdx.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.6",
4
- "serialNumber": "urn:uuid:522eeb00-0c91-5332-b303-253c17e5c306",
4
+ "serialNumber": "urn:uuid:0b78bec6-d201-57bb-b995-c6186ac389ce",
5
5
  "version": 1,
6
6
  "metadata": {
7
7
  "tools": {
@@ -10,16 +10,16 @@
10
10
  "type": "application",
11
11
  "group": "datamoc",
12
12
  "name": "tools/sbom.mjs",
13
- "version": "0.23.0"
13
+ "version": "0.24.0"
14
14
  }
15
15
  ]
16
16
  },
17
17
  "component": {
18
18
  "type": "library",
19
- "bom-ref": "pkg:npm/%40datamoc/mw_games@0.23.0",
19
+ "bom-ref": "pkg:npm/%40datamoc/mw_games@0.24.0",
20
20
  "name": "@datamoc/mw_games",
21
- "version": "0.23.0",
22
- "purl": "pkg:npm/%40datamoc/mw_games@0.23.0",
21
+ "version": "0.24.0",
22
+ "purl": "pkg:npm/%40datamoc/mw_games@0.24.0",
23
23
  "description": "A local-file game framework: renderer-free game logic, drawn through PixiJS in 2D or Babylon.js in 3D, with mobile and desktop packaging.",
24
24
  "licenses": [
25
25
  {
@@ -4601,7 +4601,7 @@
4601
4601
  ]
4602
4602
  },
4603
4603
  {
4604
- "ref": "pkg:npm/%40datamoc/mw_games@0.23.0",
4604
+ "ref": "pkg:npm/%40datamoc/mw_games@0.24.0",
4605
4605
  "dependsOn": [
4606
4606
  "pkg:npm/%40babylonjs/core@9.27.1",
4607
4607
  "pkg:npm/%40babylonjs/loaders@9.27.1",