@datamoc/mw_games 0.7.0 → 0.7.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.
Files changed (121) hide show
  1. package/CHANGELOG.md +964 -0
  2. package/README.md +43 -3
  3. package/dist/actors/Affix.d.ts +7 -1
  4. package/dist/actors/Affix.d.ts.map +1 -1
  5. package/dist/actors/Affix.js +4 -2
  6. package/dist/actors/Affix.js.map +1 -1
  7. package/dist/actors/StatBlock.d.ts +20 -0
  8. package/dist/actors/StatBlock.d.ts.map +1 -1
  9. package/dist/actors/StatBlock.js +14 -3
  10. package/dist/actors/StatBlock.js.map +1 -1
  11. package/dist/actors/index.d.ts +2 -2
  12. package/dist/actors/index.d.ts.map +1 -1
  13. package/dist/actors/index.js +1 -1
  14. package/dist/actors/index.js.map +1 -1
  15. package/dist/ai/index.d.ts +118 -0
  16. package/dist/ai/index.d.ts.map +1 -0
  17. package/dist/ai/index.js +203 -0
  18. package/dist/ai/index.js.map +1 -0
  19. package/dist/ai/lua.d.ts +47 -0
  20. package/dist/ai/lua.d.ts.map +1 -0
  21. package/dist/ai/lua.js +195 -0
  22. package/dist/ai/lua.js.map +1 -0
  23. package/dist/ai/search.d.ts +59 -0
  24. package/dist/ai/search.d.ts.map +1 -0
  25. package/dist/ai/search.js +100 -0
  26. package/dist/ai/search.js.map +1 -0
  27. package/dist/board/Engine.d.ts +14 -0
  28. package/dist/board/Engine.d.ts.map +1 -1
  29. package/dist/board/Engine.js +33 -45
  30. package/dist/board/Engine.js.map +1 -1
  31. package/dist/board/index.d.ts +1 -1
  32. package/dist/board/index.d.ts.map +1 -1
  33. package/dist/board/index.js +1 -1
  34. package/dist/board/index.js.map +1 -1
  35. package/dist/core/Csv.d.ts +10 -0
  36. package/dist/core/Csv.d.ts.map +1 -1
  37. package/dist/core/Csv.js +34 -3
  38. package/dist/core/Csv.js.map +1 -1
  39. package/dist/core/Entity.d.ts +2 -2
  40. package/dist/core/Entity.d.ts.map +1 -1
  41. package/dist/core/Entity.js +18 -4
  42. package/dist/core/Entity.js.map +1 -1
  43. package/dist/index.d.ts +1 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/mw_games.global.js +97 -97
  48. package/dist/mwl/actors.d.ts +3 -1
  49. package/dist/mwl/actors.d.ts.map +1 -1
  50. package/dist/mwl/actors.js +15 -2
  51. package/dist/mwl/actors.js.map +1 -1
  52. package/dist/mwl/catalog.d.ts.map +1 -1
  53. package/dist/mwl/catalog.js +16 -9
  54. package/dist/mwl/catalog.js.map +1 -1
  55. package/dist/mwl/compiler.d.ts +20 -0
  56. package/dist/mwl/compiler.d.ts.map +1 -1
  57. package/dist/mwl/compiler.js +76 -3
  58. package/dist/mwl/compiler.js.map +1 -1
  59. package/dist/mwl/conditions.d.ts +9 -0
  60. package/dist/mwl/conditions.d.ts.map +1 -0
  61. package/dist/mwl/conditions.js +162 -0
  62. package/dist/mwl/conditions.js.map +1 -0
  63. package/dist/mwl/content.d.ts +61 -0
  64. package/dist/mwl/content.d.ts.map +1 -1
  65. package/dist/mwl/content.js +95 -34
  66. package/dist/mwl/content.js.map +1 -1
  67. package/dist/mwl/expression.d.ts.map +1 -1
  68. package/dist/mwl/expression.js +16 -6
  69. package/dist/mwl/expression.js.map +1 -1
  70. package/dist/mwl/fengari.d.ts +8 -0
  71. package/dist/mwl/fengari.d.ts.map +1 -0
  72. package/dist/mwl/fengari.js +136 -0
  73. package/dist/mwl/fengari.js.map +1 -0
  74. package/dist/mwl/hooks.d.ts +1 -1
  75. package/dist/mwl/hooks.d.ts.map +1 -1
  76. package/dist/mwl/hooks.js.map +1 -1
  77. package/dist/mwl/index.d.ts +16 -7
  78. package/dist/mwl/index.d.ts.map +1 -1
  79. package/dist/mwl/index.js +7 -3
  80. package/dist/mwl/index.js.map +1 -1
  81. package/dist/mwl/persistence.d.ts.map +1 -1
  82. package/dist/mwl/persistence.js +10 -2
  83. package/dist/mwl/persistence.js.map +1 -1
  84. package/dist/mwl/readers.d.ts +18 -0
  85. package/dist/mwl/readers.d.ts.map +1 -0
  86. package/dist/mwl/readers.js +58 -0
  87. package/dist/mwl/readers.js.map +1 -0
  88. package/dist/mwl/report.d.ts +9 -0
  89. package/dist/mwl/report.d.ts.map +1 -0
  90. package/dist/mwl/report.js +36 -0
  91. package/dist/mwl/report.js.map +1 -0
  92. package/dist/mwl/runtime.d.ts +65 -2
  93. package/dist/mwl/runtime.d.ts.map +1 -1
  94. package/dist/mwl/runtime.js +245 -26
  95. package/dist/mwl/runtime.js.map +1 -1
  96. package/dist/mwl/schema.d.ts +13 -1
  97. package/dist/mwl/schema.d.ts.map +1 -1
  98. package/dist/mwl/schema.js +222 -7
  99. package/dist/mwl/schema.js.map +1 -1
  100. package/dist/mwl/scripts.d.ts +15 -0
  101. package/dist/mwl/scripts.d.ts.map +1 -0
  102. package/dist/mwl/scripts.js +23 -0
  103. package/dist/mwl/scripts.js.map +1 -0
  104. package/dist/mwl/utils.d.ts +8 -0
  105. package/dist/mwl/utils.d.ts.map +1 -0
  106. package/dist/mwl/utils.js +37 -0
  107. package/dist/mwl/utils.js.map +1 -0
  108. package/dist/two-d/render/Types2D.d.ts +19 -4
  109. package/dist/two-d/render/Types2D.d.ts.map +1 -1
  110. package/dist/two-d/render/Types2D.js +25 -0
  111. package/dist/two-d/render/Types2D.js.map +1 -1
  112. package/dist/two-d/render/index.d.ts +2 -2
  113. package/dist/two-d/render/index.d.ts.map +1 -1
  114. package/dist/two-d/render/index.js +1 -1
  115. package/dist/two-d/render/index.js.map +1 -1
  116. package/dist/version.d.ts +1 -1
  117. package/dist/version.js +1 -1
  118. package/package.json +27 -6
  119. package/tools/extract-html.d.mts +18 -0
  120. package/tools/extract-html.mjs +235 -0
  121. package/tools/mwl.mjs +86 -16
@@ -0,0 +1,47 @@
1
+ import { type FengariScriptHostOptions } from '../mwl/fengari.ts';
2
+ import type { ScriptHost } from '../mwl/scripts.ts';
3
+ import { type AIDecision, type AIDecisionInput, type AIStateEnvelope } from './index.ts';
4
+ import { type AlphaBetaOptions, type AlphaBetaResult, type LuaAlphaBetaFunctions } from './search.ts';
5
+ export interface LuaAIAgentDefinition {
6
+ readonly id: string;
7
+ readonly source: string;
8
+ readonly functionName?: string;
9
+ readonly search?: LuaAlphaBetaFunctions;
10
+ }
11
+ export interface LuaAIOptions extends FengariScriptHostOptions {
12
+ readonly host?: ScriptHost;
13
+ readonly maxSteps?: number;
14
+ readonly maxMilliseconds?: number;
15
+ readonly seed?: number;
16
+ readonly onDecision?: (decision: AIDecision) => void;
17
+ }
18
+ /**
19
+ * Optional Lua provider with the same decision shape as `JavaScriptAI`.
20
+ *
21
+ * A Lua function receives `(perception, state)` and returns either an action
22
+ * table or `{ action = action_table, state = state_table, events = {...} }`.
23
+ * The host is supplied so games can choose their own VM policy and tests can
24
+ * inject a fake without loading Fengari.
25
+ */
26
+ export declare class LuaAI {
27
+ private readonly host;
28
+ private readonly agents;
29
+ private readonly states;
30
+ private readonly options;
31
+ private readonly loaded;
32
+ constructor(options?: LuaAIOptions);
33
+ register(agent: LuaAIAgentDefinition): void;
34
+ decide(agentId: string, input: AIDecisionInput): AIDecision;
35
+ /**
36
+ * Search a game whose state and operations are exposed by named Lua functions.
37
+ * Defaults are `current_player`, `legal_moves`, `apply_move`, `is_terminal` and
38
+ * `evaluate`, each receiving the state and, for `apply_move`, the move as arguments.
39
+ */
40
+ search(agentId: string, state: import('./index.ts').AIValue, options: AlphaBetaOptions): AlphaBetaResult<import('./index.ts').AIValue, import('./index.ts').AIValue>;
41
+ exportState(): AIStateEnvelope;
42
+ importState(envelope: AIStateEnvelope): void;
43
+ dispose(): void;
44
+ }
45
+ export declare function createLuaAI(options?: LuaAIOptions): LuaAI;
46
+ export type { AIAgentDefinition, AIDecision, AIDecisionInput, AIStateEnvelope } from './index.ts';
47
+ //# sourceMappingURL=lua.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lua.d.ts","sourceRoot":"","sources":["../../src/ai/lua.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAmB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED,MAAM,WAAW,YAAa,SAAQ,wBAAwB;IAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;GAOG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmE;IAC1F,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAE5C,YAAY,OAAO,GAAE,YAAiB,EAQrC;IAED,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAK1C;IAED,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,UAAU,CAkD1D;IAED;;;;OAIG;IACH,MAAM,CACL,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,YAAY,EAAE,OAAO,EACnC,OAAO,EAAE,gBAAgB,GACvB,eAAe,CAAC,OAAO,YAAY,EAAE,OAAO,EAAE,OAAO,YAAY,EAAE,OAAO,CAAC,CA4B7E;IAED,WAAW,IAAI,eAAe,CAE7B;IAED,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAM3C;IAED,OAAO,IAAI,IAAI,CAKd;CACD;AA0ED,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB,GAAG,KAAK,CAE7D;AAED,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
package/dist/ai/lua.js ADDED
@@ -0,0 +1,195 @@
1
+ import { createFengariScriptHost } from '../mwl/fengari.js';
2
+ import {} from './index.js';
3
+ import { alphaBetaSearch } from './search.js';
4
+ /**
5
+ * Optional Lua provider with the same decision shape as `JavaScriptAI`.
6
+ *
7
+ * A Lua function receives `(perception, state)` and returns either an action
8
+ * table or `{ action = action_table, state = state_table, events = {...} }`.
9
+ * The host is supplied so games can choose their own VM policy and tests can
10
+ * inject a fake without loading Fengari.
11
+ */
12
+ export class LuaAI {
13
+ constructor(options = {}) {
14
+ this.agents = new Map();
15
+ this.states = new Map();
16
+ this.loaded = new Set();
17
+ this.options = options;
18
+ this.host =
19
+ options.host ??
20
+ createFengariScriptHost({
21
+ instructionLimit: options.maxSteps ?? options.instructionLimit,
22
+ seed: options.seed,
23
+ });
24
+ }
25
+ register(agent) {
26
+ if (this.agents.has(agent.id))
27
+ throw new Error(`Lua AI agent already registered: ${agent.id}`);
28
+ if (!agent.source.trim())
29
+ throw new Error(`Lua AI agent has empty source: ${agent.id}`);
30
+ this.agents.set(agent.id, agent);
31
+ this.states.set(agent.id, {});
32
+ }
33
+ decide(agentId, input) {
34
+ const agent = this.agents.get(agentId);
35
+ if (!agent)
36
+ throw new Error(`unknown Lua AI agent: ${agentId}`);
37
+ if (input.signal?.aborted) {
38
+ return {
39
+ agent: agentId,
40
+ action: null,
41
+ state: this.states.get(agentId) ?? {},
42
+ status: 'cancelled',
43
+ steps: 0,
44
+ events: [],
45
+ };
46
+ }
47
+ if (!this.loaded.has(agentId)) {
48
+ this.host.execute(agent.source);
49
+ this.loaded.add(agentId);
50
+ }
51
+ const functionName = agent.functionName ?? 'decide';
52
+ const state = input.state ?? this.states.get(agentId) ?? {};
53
+ try {
54
+ const result = this.host.call(functionName, [input.perception, state], {
55
+ mwg_seed: input.seed ?? this.options.seed ?? 0x6d7767,
56
+ });
57
+ const normalized = normalizeResult(agentId, result, state);
58
+ this.states.set(agentId, normalized.state);
59
+ const decision = {
60
+ agent: agentId,
61
+ action: normalized.action,
62
+ state: normalized.state,
63
+ status: normalized.action ? 'action' : 'idle',
64
+ steps: 1,
65
+ events: normalized.events,
66
+ };
67
+ this.options.onDecision?.(decision);
68
+ return decision;
69
+ }
70
+ catch (error) {
71
+ if (/instruction limit exceeded/i.test(String(error))) {
72
+ const decision = {
73
+ agent: agentId,
74
+ action: null,
75
+ state: state,
76
+ status: 'budget-exceeded',
77
+ steps: input.maxSteps ?? this.options.maxSteps ?? 0,
78
+ events: [],
79
+ };
80
+ this.options.onDecision?.(decision);
81
+ return decision;
82
+ }
83
+ throw error;
84
+ }
85
+ }
86
+ /**
87
+ * Search a game whose state and operations are exposed by named Lua functions.
88
+ * Defaults are `current_player`, `legal_moves`, `apply_move`, `is_terminal` and
89
+ * `evaluate`, each receiving the state and, for `apply_move`, the move as arguments.
90
+ */
91
+ search(agentId, state, options) {
92
+ const agent = this.agents.get(agentId);
93
+ if (!agent)
94
+ throw new Error(`unknown Lua AI agent: ${agentId}`);
95
+ if (!this.loaded.has(agentId)) {
96
+ this.host.execute(agent.source);
97
+ this.loaded.add(agentId);
98
+ }
99
+ const names = {
100
+ player: agent.search?.player ?? 'current_player',
101
+ moves: agent.search?.moves ?? 'legal_moves',
102
+ apply: agent.search?.apply ?? 'apply_move',
103
+ terminal: agent.search?.terminal ?? 'is_terminal',
104
+ evaluate: agent.search?.evaluate ?? 'evaluate',
105
+ };
106
+ const call = (name, args) => this.host.call(name, args, { mwg_seed: this.options.seed ?? 0x6d7767 });
107
+ return alphaBetaSearch({
108
+ currentPlayer: (current) => toNumber(call(names.player, [current]), `Lua AI ${agentId} player`),
109
+ moves: (current) => toMoves(call(names.moves, [current]), agentId),
110
+ apply: (current, move) => call(names.apply, [current, move]),
111
+ isTerminal: (current) => toBoolean(call(names.terminal, [current]), `Lua AI ${agentId} terminal`),
112
+ evaluate: (current, perspective) => toNumber(call(names.evaluate, [current, perspective]), `Lua AI ${agentId} evaluation`),
113
+ }, state, options);
114
+ }
115
+ exportState() {
116
+ return { version: 1, agents: Object.fromEntries([...this.states].map(([id, state]) => [id, clone(state)])) };
117
+ }
118
+ importState(envelope) {
119
+ if (envelope.version !== 1)
120
+ throw new Error(`unsupported AI state version: ${envelope.version}`);
121
+ for (const [id, state] of Object.entries(envelope.agents)) {
122
+ if (!this.agents.has(id))
123
+ throw new Error(`AI state names unknown agent: ${id}`);
124
+ this.states.set(id, clone(state));
125
+ }
126
+ }
127
+ dispose() {
128
+ this.host.dispose();
129
+ this.agents.clear();
130
+ this.states.clear();
131
+ this.loaded.clear();
132
+ }
133
+ }
134
+ function normalizeResult(agent, result, initialState) {
135
+ if (result === null)
136
+ return { action: null, state: clone(initialState), events: [] };
137
+ if (typeof result !== 'object' || Array.isArray(result))
138
+ throw new Error(`Lua AI ${agent} must return an action table`);
139
+ const value = result;
140
+ const hasEnvelope = 'action' in value || 'state' in value || 'events' in value;
141
+ const action = (hasEnvelope ? value.action : value);
142
+ if (action !== null &&
143
+ action !== undefined &&
144
+ (typeof action !== 'object' || Array.isArray(action) || typeof action.type !== 'string')) {
145
+ throw new Error(`Lua AI ${agent} returned an invalid action`);
146
+ }
147
+ const events = hasEnvelope && value.events && typeof value.events === 'object'
148
+ ? tableEntries(value.events).map((entry) => {
149
+ if (typeof entry !== 'object' ||
150
+ entry === null ||
151
+ Array.isArray(entry) ||
152
+ typeof entry.name !== 'string') {
153
+ throw new Error(`Lua AI ${agent} returned an invalid event`);
154
+ }
155
+ return entry;
156
+ })
157
+ : [];
158
+ const state = hasEnvelope && value.state && typeof value.state === 'object' && !Array.isArray(value.state)
159
+ ? value.state
160
+ : initialState;
161
+ return { action: action ?? null, state: clone(state), events };
162
+ }
163
+ function tableEntries(value) {
164
+ if (Array.isArray(value))
165
+ return value;
166
+ if (value === null || typeof value !== 'object')
167
+ return [];
168
+ return Object.keys(value)
169
+ .filter((key) => /^\d+$/.test(key))
170
+ .sort((a, b) => Number(a) - Number(b))
171
+ .map((key) => value[key]);
172
+ }
173
+ function toMoves(value, agent) {
174
+ const moves = tableEntries(value);
175
+ if (value !== null && typeof value !== 'object')
176
+ throw new Error(`Lua AI ${agent} legal moves must be a table`);
177
+ return moves;
178
+ }
179
+ function toBoolean(value, name) {
180
+ if (typeof value !== 'boolean')
181
+ throw new Error(`${name} must return a boolean`);
182
+ return value;
183
+ }
184
+ function toNumber(value, name) {
185
+ if (typeof value !== 'number' || !Number.isFinite(value))
186
+ throw new Error(`${name} must return a finite number`);
187
+ return value;
188
+ }
189
+ function clone(value) {
190
+ return JSON.parse(JSON.stringify(value));
191
+ }
192
+ export function createLuaAI(options = {}) {
193
+ return new LuaAI(options);
194
+ }
195
+ //# sourceMappingURL=lua.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lua.js","sourceRoot":"","sources":["../../src/ai/lua.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { AIValue } from './index.ts';
2
+ export interface AlphaBetaGame<State, Move> {
3
+ /** The side whose turn it is. Alpha-beta assumes a two-player zero-sum game. */
4
+ readonly currentPlayer: (state: State) => number;
5
+ /** Legal moves from this state, in the game's preferred stable order. */
6
+ readonly moves: (state: State) => readonly Move[];
7
+ /** Apply a move and return the next state. Do not mutate the input state. */
8
+ readonly apply: (state: State, move: Move) => State;
9
+ readonly isTerminal: (state: State) => boolean;
10
+ /** Score from the perspective of the root player. Higher is better. */
11
+ readonly evaluate: (state: State, rootPlayer: number) => number;
12
+ }
13
+ export interface AlphaBetaOptions {
14
+ readonly depth: number;
15
+ readonly maxNodes?: number;
16
+ readonly signal?: AbortSignal;
17
+ readonly onNode?: (depth: number, maximizing: boolean) => void;
18
+ }
19
+ export interface AlphaBetaResult<State, Move> {
20
+ readonly move: Move | null;
21
+ readonly score: number;
22
+ readonly depth: number;
23
+ readonly nodes: number;
24
+ readonly cutoffs: number;
25
+ readonly status: 'complete' | 'cancelled' | 'budget-exceeded';
26
+ readonly state: State;
27
+ }
28
+ /**
29
+ * Deterministic minimax with alpha-beta pruning for a game-owned state adapter.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { alphaBetaSearch } from '@datamoc/mw_games/ai';
34
+ *
35
+ * const result = alphaBetaSearch({
36
+ * currentPlayer: () => 1,
37
+ * moves: (state: number) => state < 2 ? [1] : [],
38
+ * apply: (state: number, move: number) => state + move,
39
+ * isTerminal: (state: number) => state >= 2,
40
+ * evaluate: (state: number) => state,
41
+ * }, 0, { depth: 2 });
42
+ * console.log(result.move); // 1
43
+ * ```
44
+ */
45
+ export declare function alphaBetaSearch<State, Move>(game: AlphaBetaGame<State, Move>, state: State, options: AlphaBetaOptions): AlphaBetaResult<State, Move>;
46
+ export interface LuaAlphaBetaFunctions {
47
+ readonly player?: string;
48
+ readonly moves?: string;
49
+ readonly apply?: string;
50
+ readonly terminal?: string;
51
+ readonly evaluate?: string;
52
+ }
53
+ export interface LuaSearchValueAdapter {
54
+ readonly toMoves: (value: AIValue) => readonly AIValue[];
55
+ readonly toBoolean: (value: AIValue) => boolean;
56
+ readonly toNumber: (value: AIValue) => number;
57
+ readonly toPlayer: (value: AIValue) => number;
58
+ }
59
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/ai/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,IAAI;IACzC,gFAAgF;IAChF,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IACjD,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,IAAI,EAAE,CAAC;IAClD,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC;IACpD,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;CAChE;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,IAAI;IAC3C,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,iBAAiB,CAAC;IAC9D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACtB;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAC1C,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,gBAAgB,GACvB,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAwE9B;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,OAAO,EAAE,CAAC;IACzD,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CAC9C"}
@@ -0,0 +1,100 @@
1
+ const DEFAULT_MAX_NODES = 100_000;
2
+ /**
3
+ * Deterministic minimax with alpha-beta pruning for a game-owned state adapter.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { alphaBetaSearch } from '@datamoc/mw_games/ai';
8
+ *
9
+ * const result = alphaBetaSearch({
10
+ * currentPlayer: () => 1,
11
+ * moves: (state: number) => state < 2 ? [1] : [],
12
+ * apply: (state: number, move: number) => state + move,
13
+ * isTerminal: (state: number) => state >= 2,
14
+ * evaluate: (state: number) => state,
15
+ * }, 0, { depth: 2 });
16
+ * console.log(result.move); // 1
17
+ * ```
18
+ */
19
+ export function alphaBetaSearch(game, state, options) {
20
+ if (!Number.isInteger(options.depth) || options.depth < 1)
21
+ throw new RangeError('depth must be a positive integer');
22
+ const maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;
23
+ if (!Number.isInteger(maxNodes) || maxNodes < 1)
24
+ throw new RangeError('maxNodes must be a positive integer');
25
+ const rootPlayer = game.currentPlayer(state);
26
+ let nodes = 0;
27
+ let cutoffs = 0;
28
+ let stopped;
29
+ const visit = (current, remaining, alpha, beta) => {
30
+ if (options.signal?.aborted) {
31
+ stopped = 'cancelled';
32
+ return 0;
33
+ }
34
+ if (++nodes > maxNodes) {
35
+ stopped = 'budget-exceeded';
36
+ return 0;
37
+ }
38
+ const maximizing = game.currentPlayer(current) === rootPlayer;
39
+ options.onNode?.(remaining, maximizing);
40
+ if (remaining === 0 || game.isTerminal(current))
41
+ return game.evaluate(current, rootPlayer);
42
+ const moves = game.moves(current);
43
+ if (!moves.length)
44
+ return game.evaluate(current, rootPlayer);
45
+ let best = maximizing ? -Infinity : Infinity;
46
+ for (const move of moves) {
47
+ const score = visit(game.apply(current, move), remaining - 1, alpha, beta);
48
+ if (stopped)
49
+ return score;
50
+ if (maximizing) {
51
+ best = Math.max(best, score);
52
+ alpha = Math.max(alpha, best);
53
+ }
54
+ else {
55
+ best = Math.min(best, score);
56
+ beta = Math.min(beta, best);
57
+ }
58
+ if (beta <= alpha) {
59
+ cutoffs++;
60
+ break;
61
+ }
62
+ }
63
+ return best;
64
+ };
65
+ const rootMoves = game.moves(state);
66
+ let chosen = null;
67
+ let score = game.evaluate(state, rootPlayer);
68
+ if (!game.isTerminal(state) && rootMoves.length) {
69
+ const maximizing = game.currentPlayer(state) === rootPlayer;
70
+ let bestScore = maximizing ? -Infinity : Infinity;
71
+ let alpha = -Infinity;
72
+ let beta = Infinity;
73
+ for (const move of rootMoves) {
74
+ const child = game.apply(state, move);
75
+ const candidate = visit(child, options.depth - 1, alpha, beta);
76
+ if (stopped)
77
+ break;
78
+ if (chosen === null || (maximizing ? candidate > bestScore : candidate < bestScore)) {
79
+ chosen = move;
80
+ bestScore = candidate;
81
+ }
82
+ if (maximizing)
83
+ alpha = Math.max(alpha, bestScore);
84
+ else
85
+ beta = Math.min(beta, bestScore);
86
+ }
87
+ if (chosen !== null)
88
+ score = bestScore;
89
+ }
90
+ return {
91
+ move: stopped ? null : chosen,
92
+ score,
93
+ depth: options.depth,
94
+ nodes,
95
+ cutoffs,
96
+ status: stopped ?? 'complete',
97
+ state,
98
+ };
99
+ }
100
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/ai/search.ts"],"names":[],"mappings":"AA+BA,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAC9B,IAAgC,EAChC,KAAY,EACZ,OAAyB;IAEzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;IACpH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,qCAAqC,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAA2D,CAAC;IAEhE,MAAM,KAAK,GAAG,CAAC,OAAc,EAAE,SAAiB,EAAE,KAAa,EAAE,IAAY,EAAU,EAAE;QACxF,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YAC7B,OAAO,GAAG,WAAW,CAAC;YACtB,OAAO,CAAC,CAAC;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,CAAC;YACxB,OAAO,GAAG,iBAAiB,CAAC;YAC5B,OAAO,CAAC,CAAC;QACV,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,UAAU,CAAC;QAC9D,OAAO,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACxC,IAAI,SAAS,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC3F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YAC3E,IAAI,OAAO;gBAAE,OAAO,KAAK,CAAC;YAC1B,IAAI,UAAU,EAAE,CAAC;gBAChB,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC7B,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACP,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC7B,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC7B,CAAC;YACD,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;gBACnB,OAAO,EAAE,CAAC;gBACV,MAAM;YACP,CAAC;QACF,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,MAAM,GAAgB,IAAI,CAAC;IAC/B,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC;QAC5D,IAAI,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAClD,IAAI,KAAK,GAAG,CAAC,QAAQ,CAAC;QACtB,IAAI,IAAI,GAAG,QAAQ,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACtC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YAC/D,IAAI,OAAO;gBAAE,MAAM;YACnB,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,CAAC;gBACrF,MAAM,GAAG,IAAI,CAAC;gBACd,SAAS,GAAG,SAAS,CAAC;YACvB,CAAC;YACD,IAAI,UAAU;gBAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;;gBAC9C,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,MAAM,KAAK,IAAI;YAAE,KAAK,GAAG,SAAS,CAAC;IACxC,CAAC;IACD,OAAO;QACN,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;QAC7B,KAAK;QACL,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK;QACL,OAAO;QACP,MAAM,EAAE,OAAO,IAAI,UAAU;QAC7B,KAAK;KACL,CAAC;AACH,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type AlphaBetaGame } from '../ai/search.ts';
1
2
  import { type ChessMove, type ChessState } from './chess.ts';
2
3
  export interface ChessEngineOptions {
3
4
  /** plies to search; three is a useful small browser default */
@@ -43,4 +44,17 @@ export declare function chooseMove(state: ChessState, options?: ChessEngineOptio
43
44
  * ```
44
45
  */
45
46
  export declare function search(state: ChessState, options?: ChessEngineOptions): ChessSearchResult;
47
+ /**
48
+ * The chess rules adapter consumed by the shared `ai.alphaBetaSearch` primitive.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import { chessGame, startingChess } from '@datamoc/mw_games/board';
53
+ * import { alphaBetaSearch } from '@datamoc/mw_games/ai';
54
+ *
55
+ * const result = alphaBetaSearch(chessGame, startingChess(), { depth: 2 });
56
+ * console.log(result.move !== null); // true
57
+ * ```
58
+ */
59
+ export declare const chessGame: AlphaBetaGame<ChessState, ChessMove>;
46
60
  //# sourceMappingURL=Engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/board/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAMN,KAAK,SAAS,EAEd,KAAK,UAAU,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IAClC,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,kBAAuB,GAAG,SAAS,GAAG,IAAI,CAEhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CAwC7F"}
1
+ {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/board/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAMN,KAAK,SAAS,EAEd,KAAK,UAAU,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IAClC,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,kBAAuB,GAAG,SAAS,GAAG,IAAI,CAEhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CAK7F;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,EAAE,aAAa,CAAC,UAAU,EAAE,SAAS,CAW1D,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { alphaBetaSearch } from '../ai/search.js';
1
2
  import { applyMove, cloneChess, gameResult, inCheck, legalMoves, } from './chess.js';
2
3
  const MATE = 100_000;
3
4
  const PIECE_VALUE = {
@@ -44,60 +45,47 @@ export function chooseMove(state, options = {}) {
44
45
  */
45
46
  export function search(state, options = {}) {
46
47
  const depth = Math.max(1, Math.floor(options.depth ?? 3));
47
- const maxNodes = options.maxNodes === undefined ? Infinity : Math.max(1, Math.floor(options.maxNodes));
48
- const moves = orderedMoves(state, legalMoves(state));
49
- if (moves.length === 0)
50
- return { move: null, score: terminalScore(state, 0), nodes: 1 };
51
- let nodes = 0;
52
- let bestMove = moves[0];
53
- let bestScore = -Infinity;
54
- let alpha = -Infinity;
55
- for (const move of moves) {
56
- if (nodes >= maxNodes)
57
- break;
48
+ const maxNodes = options.maxNodes === undefined ? 100_000 : Math.max(1, Math.floor(options.maxNodes));
49
+ const result = alphaBetaSearch(chessGame, state, { depth, maxNodes });
50
+ return { move: result.move, score: result.score, nodes: result.nodes };
51
+ }
52
+ /**
53
+ * The chess rules adapter consumed by the shared `ai.alphaBetaSearch` primitive.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { chessGame, startingChess } from '@datamoc/mw_games/board';
58
+ * import { alphaBetaSearch } from '@datamoc/mw_games/ai';
59
+ *
60
+ * const result = alphaBetaSearch(chessGame, startingChess(), { depth: 2 });
61
+ * console.log(result.move !== null); // true
62
+ * ```
63
+ */
64
+ export const chessGame = {
65
+ currentPlayer: (state) => (state.turn === 'white' ? 1 : -1),
66
+ moves: (state) => orderedMoves(state, legalMoves(state)),
67
+ apply: (state, move) => {
58
68
  const next = cloneChess(state);
59
69
  applyMove(next, move);
60
- const score = -negamax(next, depth - 1, -Infinity, -alpha, 1);
61
- if (score > bestScore) {
62
- bestScore = score;
63
- bestMove = move;
64
- }
65
- alpha = Math.max(alpha, score);
66
- }
67
- return { move: bestMove, score: bestScore, nodes };
68
- function negamax(position, remaining, low, high, ply) {
69
- if (nodes >= maxNodes)
70
- return evaluate(position);
71
- nodes++;
72
- const result = gameResult(position);
73
- if (result !== 'ongoing')
74
- return terminalScore(position, ply);
75
- if (remaining === 0)
76
- return evaluate(position);
77
- let value = -Infinity;
78
- for (const move of orderedMoves(position, legalMoves(position))) {
79
- const next = cloneChess(position);
80
- applyMove(next, move);
81
- value = Math.max(value, -negamax(next, remaining - 1, -high, -low, ply + 1));
82
- low = Math.max(low, value);
83
- if (low >= high)
84
- break;
85
- }
86
- return value;
87
- }
88
- }
89
- function evaluate(state) {
70
+ return next;
71
+ },
72
+ isTerminal: (state) => gameResult(state) !== 'ongoing',
73
+ evaluate: (state, rootPlayer) => gameResult(state) === 'ongoing' ? evaluate(state, rootPlayer) : terminalScore(state, rootPlayer),
74
+ };
75
+ function evaluate(state, rootPlayer) {
90
76
  let score = 0;
91
77
  for (const piece of state.board) {
92
78
  if (piece)
93
79
  score += (piece.side === 'white' ? 1 : -1) * PIECE_VALUE[piece.kind];
94
80
  }
95
- return state.turn === 'white' ? score : -score;
81
+ return rootPlayer === 1 ? score : -score;
96
82
  }
97
- function terminalScore(state, ply) {
98
- if (!inCheck(state, state.turn))
83
+ function terminalScore(state, rootPlayer) {
84
+ const result = gameResult(state);
85
+ if (result === 'stalemate' || !inCheck(state, state.turn))
99
86
  return 0;
100
- return -MATE + ply;
87
+ const winner = result === 'white-wins' ? 1 : -1;
88
+ return winner === rootPlayer ? MATE : -MATE;
101
89
  }
102
90
  function orderedMoves(state, moves) {
103
91
  return moves.slice().sort((a, b) => moveOrder(state, b) - moveOrder(state, a));
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.js","sourceRoot":"","sources":["../../src/board/Engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Engine.js","sourceRoot":"","sources":["../../src/board/Engine.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export { startingChess, parseFen, cloneChess, legalMoves, applyMove, inCheck, gameResult, sq, squareName, } from './chess.ts';
2
2
  export type { ChessSide, ChessKind, ChessPiece, ChessSquare, PromotionKind, ChessMove, ChessCastling, ChessState, ChessResult, } from './chess.ts';
3
- export { chooseMove, search } from './Engine.ts';
3
+ export { chessGame, chooseMove, search } from './Engine.ts';
4
4
  export type { ChessEngineOptions, ChessSearchResult } from './Engine.ts';
5
5
  export { BoardGrid, startingCheckers, checkersMoves, applyCheckersMove, startingGo, playGo, passGo, goResult, goScore, startingBackgammon, rollBackgammonDice, backgammonMoves, applyBackgammonMove, createDeck, shuffleDeck, deal, trickWinner, dealSolitaire, drawSolitaire, moveSolitaireTableau, moveSolitaireToFoundation, solitaireWon, rollDice, rollExpression, DiceCup, scoreDice, } from './Classics.ts';
6
6
  export type { BoardOwner, BoardPiece, CheckersSide, CheckersPiece, CheckersMove, CheckersState, GoStone, GoState, DiceCategory, TrickPlay, BackgammonState, BackgammonMove, CardSuit, CardRank, Card, SolitaireState, } from './Classics.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/board/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,EAAE,EACF,UAAU,GACV,MAAM,YAAY,CAAC;AACpB,YAAY,EACX,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,EACb,UAAU,EACV,WAAW,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,WAAW,EACX,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,OAAO,EACP,SAAS,GACT,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,SAAS,EACT,eAAe,EACf,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,eAAe,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,GAChB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/board/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,EAAE,EACF,UAAU,GACV,MAAM,YAAY,CAAC;AACpB,YAAY,EACX,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,EACb,UAAU,EACV,WAAW,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,WAAW,EACX,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,OAAO,EACP,SAAS,GACT,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,SAAS,EACT,eAAe,EACf,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,eAAe,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,GAChB,MAAM,kBAAkB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  export { startingChess, parseFen, cloneChess, legalMoves, applyMove, inCheck, gameResult, sq, squareName, } from './chess.js';
2
- export { chooseMove, search } from './Engine.js';
2
+ export { chessGame, chooseMove, search } from './Engine.js';
3
3
  export { BoardGrid, startingCheckers, checkersMoves, applyCheckersMove, startingGo, playGo, passGo, goResult, goScore, startingBackgammon, rollBackgammonDice, backgammonMoves, applyBackgammonMove, createDeck, shuffleDeck, deal, trickWinner, dealSolitaire, drawSolitaire, moveSolitaireTableau, moveSolitaireToFoundation, solitaireWon, rollDice, rollExpression, DiceCup, scoreDice, } from './Classics.js';
4
4
  export { startingTactics, addTacticalUnit, canPlaceTacticalUnit, tacticalMoves, moveTacticalUnit, setTacticalOverwatch, triggerTacticalOverwatch, tacticalAttack, endTacticalTurn, } from './Tactics.js';
5
5
  export { FactionFog } from './FogOfWar.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/board/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,EAAE,EACF,UAAU,GACV,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,WAAW,EACX,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,OAAO,EACP,SAAS,GACT,MAAM,eAAe,CAAC;AAmBvB,OAAO,EACN,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,eAAe,GACf,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7F,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,GACf,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/board/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,EAAE,EACF,UAAU,GACV,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,WAAW,EACX,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,OAAO,EACP,SAAS,GACT,MAAM,eAAe,CAAC;AAmBvB,OAAO,EACN,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,eAAe,GACf,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7F,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,GACf,MAAM,kBAAkB,CAAC"}