poke-crucible 0.1.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/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/battle/pairing.d.ts +25 -0
- package/dist/battle/pairing.js +59 -0
- package/dist/battle/pairing.js.map +1 -0
- package/dist/battle/pool.d.ts +25 -0
- package/dist/battle/pool.js +97 -0
- package/dist/battle/pool.js.map +1 -0
- package/dist/battle/run-battle.d.ts +13 -0
- package/dist/battle/run-battle.js +49 -0
- package/dist/battle/run-battle.js.map +1 -0
- package/dist/battle/worker.d.ts +1 -0
- package/dist/battle/worker.js +21 -0
- package/dist/battle/worker.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +326 -0
- package/dist/cli.js.map +1 -0
- package/dist/critic/agent-sdk-model.d.ts +27 -0
- package/dist/critic/agent-sdk-model.js +21 -0
- package/dist/critic/agent-sdk-model.js.map +1 -0
- package/dist/critic/critique.d.ts +21 -0
- package/dist/critic/critique.js +51 -0
- package/dist/critic/critique.js.map +1 -0
- package/dist/critic/evidence.d.ts +24 -0
- package/dist/critic/evidence.js +17 -0
- package/dist/critic/evidence.js.map +1 -0
- package/dist/critic/llm.d.ts +34 -0
- package/dist/critic/llm.js +23 -0
- package/dist/critic/llm.js.map +1 -0
- package/dist/critic/parse.d.ts +5 -0
- package/dist/critic/parse.js +84 -0
- package/dist/critic/parse.js.map +1 -0
- package/dist/critic/prompt.d.ts +14 -0
- package/dist/critic/prompt.js +56 -0
- package/dist/critic/prompt.js.map +1 -0
- package/dist/critic/types.d.ts +52 -0
- package/dist/critic/types.js +2 -0
- package/dist/critic/types.js.map +1 -0
- package/dist/designer/agent-sdk-model.d.ts +30 -0
- package/dist/designer/agent-sdk-model.js +62 -0
- package/dist/designer/agent-sdk-model.js.map +1 -0
- package/dist/designer/design.d.ts +12 -0
- package/dist/designer/design.js +218 -0
- package/dist/designer/design.js.map +1 -0
- package/dist/designer/fitness.d.ts +25 -0
- package/dist/designer/fitness.js +24 -0
- package/dist/designer/fitness.js.map +1 -0
- package/dist/designer/model.d.ts +14 -0
- package/dist/designer/model.js +27 -0
- package/dist/designer/model.js.map +1 -0
- package/dist/designer/mutate.d.ts +31 -0
- package/dist/designer/mutate.js +209 -0
- package/dist/designer/mutate.js.map +1 -0
- package/dist/designer/rng.d.ts +17 -0
- package/dist/designer/rng.js +40 -0
- package/dist/designer/rng.js.map +1 -0
- package/dist/designer/types.d.ts +103 -0
- package/dist/designer/types.js +2 -0
- package/dist/designer/types.js.map +1 -0
- package/dist/evaluate.d.ts +11 -0
- package/dist/evaluate.js +99 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/gauntlet/gauntlet.d.ts +18 -0
- package/dist/gauntlet/gauntlet.js +41 -0
- package/dist/gauntlet/gauntlet.js.map +1 -0
- package/dist/gauntlet/teams-g1.d.ts +23 -0
- package/dist/gauntlet/teams-g1.js +476 -0
- package/dist/gauntlet/teams-g1.js.map +1 -0
- package/dist/gauntlet/teams-g2.d.ts +14 -0
- package/dist/gauntlet/teams-g2.js +725 -0
- package/dist/gauntlet/teams-g2.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/agent-query.d.ts +21 -0
- package/dist/llm/agent-query.js +70 -0
- package/dist/llm/agent-query.js.map +1 -0
- package/dist/pilot/damage.d.ts +34 -0
- package/dist/pilot/damage.js +75 -0
- package/dist/pilot/damage.js.map +1 -0
- package/dist/pilot/eval-pilot.d.ts +39 -0
- package/dist/pilot/eval-pilot.js +161 -0
- package/dist/pilot/eval-pilot.js.map +1 -0
- package/dist/pilot/pilot.d.ts +71 -0
- package/dist/pilot/pilot.js +290 -0
- package/dist/pilot/pilot.js.map +1 -0
- package/dist/ranking.d.ts +25 -0
- package/dist/ranking.js +40 -0
- package/dist/ranking.js.map +1 -0
- package/dist/seed.d.ts +13 -0
- package/dist/seed.js +42 -0
- package/dist/seed.js.map +1 -0
- package/dist/team.d.ts +29 -0
- package/dist/team.js +100 -0
- package/dist/team.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for the poke-crucible evaluation harness.
|
|
3
|
+
*
|
|
4
|
+
* The single seam is {@link evaluate}; everything else (Team I/O, the Pilot, the
|
|
5
|
+
* runner, the Gauntlet loader) is reached through it. Later slices — the Critic,
|
|
6
|
+
* then the Designer — build on this stable entry point rather than the CLI.
|
|
7
|
+
*/
|
|
8
|
+
export { evaluate } from './evaluate.js';
|
|
9
|
+
export type { EvaluateRuntimeOptions } from './evaluate.js';
|
|
10
|
+
export { loadGauntlet, knownGauntletVersions, DEFAULT_GAUNTLET_VERSION, GAUNTLET_VERSION, type Gauntlet, type GauntletMember, } from './gauntlet/gauntlet.js';
|
|
11
|
+
export * from './types.js';
|
|
12
|
+
export { critique, critiqueTeam, type CritiqueTeamOptions } from './critic/critique.js';
|
|
13
|
+
export { StubCritiqueModel, type CritiqueModel } from './critic/llm.js';
|
|
14
|
+
export { AgentSdkCritiqueModel, DEFAULT_CRITIC_MODEL, type AgentSdkModelOptions, } from './critic/agent-sdk-model.js';
|
|
15
|
+
export { CritiqueParseError } from './critic/parse.js';
|
|
16
|
+
export type { Critique, CritiqueInput, CritiqueWeakness, CritiqueFix, Severity, } from './critic/types.js';
|
|
17
|
+
export type { CritiqueContext } from './critic/evidence.js';
|
|
18
|
+
export { buildContext } from './critic/evidence.js';
|
|
19
|
+
export { buildPrompt, PILOT_CAVEAT, type CritiquePrompt } from './critic/prompt.js';
|
|
20
|
+
export { design, PILOT_ID } from './designer/design.js';
|
|
21
|
+
export { StubDesignerModel } from './designer/model.js';
|
|
22
|
+
export { AgentSdkDesignerModel, DEFAULT_DESIGNER_MODEL, type AgentSdkDesignerOptions, } from './designer/agent-sdk-model.js';
|
|
23
|
+
export { composite, fitnessParts, robustnessFloor, DEFAULT_WEIGHTS } from './designer/fitness.js';
|
|
24
|
+
export { buildGenePool, buildMovePool, mutate, crossover, isLegal } from './designer/mutate.js';
|
|
25
|
+
export type { DesignInput, DesignResult, DesignedTeam, DesignBudget, DesignerModel, FitnessWeights, FitnessParts, Lineage, Origin, } from './designer/types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for the poke-crucible evaluation harness.
|
|
3
|
+
*
|
|
4
|
+
* The single seam is {@link evaluate}; everything else (Team I/O, the Pilot, the
|
|
5
|
+
* runner, the Gauntlet loader) is reached through it. Later slices — the Critic,
|
|
6
|
+
* then the Designer — build on this stable entry point rather than the CLI.
|
|
7
|
+
*/
|
|
8
|
+
export { evaluate } from './evaluate.js';
|
|
9
|
+
export { loadGauntlet, knownGauntletVersions, DEFAULT_GAUNTLET_VERSION, GAUNTLET_VERSION, } from './gauntlet/gauntlet.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
// Slice 2 — the Critic (LLM behind the CritiqueModel seam).
|
|
12
|
+
export { critique, critiqueTeam } from './critic/critique.js';
|
|
13
|
+
export { StubCritiqueModel } from './critic/llm.js';
|
|
14
|
+
export { AgentSdkCritiqueModel, DEFAULT_CRITIC_MODEL, } from './critic/agent-sdk-model.js';
|
|
15
|
+
export { CritiqueParseError } from './critic/parse.js';
|
|
16
|
+
export { buildContext } from './critic/evidence.js';
|
|
17
|
+
export { buildPrompt, PILOT_CAVEAT } from './critic/prompt.js';
|
|
18
|
+
// Slice 3 — the Designer (evolutionary discovery over the evaluate() seam).
|
|
19
|
+
export { design, PILOT_ID } from './designer/design.js';
|
|
20
|
+
export { StubDesignerModel } from './designer/model.js';
|
|
21
|
+
export { AgentSdkDesignerModel, DEFAULT_DESIGNER_MODEL, } from './designer/agent-sdk-model.js';
|
|
22
|
+
export { composite, fitnessParts, robustnessFloor, DEFAULT_WEIGHTS } from './designer/fitness.js';
|
|
23
|
+
export { buildGenePool, buildMovePool, mutate, crossover, isLegal } from './designer/mutate.js';
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,wBAAwB,EACxB,gBAAgB,GAGjB,MAAM,wBAAwB,CAAC;AAChC,cAAc,YAAY,CAAC;AAE3B,4DAA4D;AAC5D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAA4B,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAsB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AASvD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAEpF,4EAA4E;AAC5E,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Claude Agent SDK call — one place both the Critic and the Designer
|
|
3
|
+
* reach the LLM. Runs `query()` once, headless: our system prompt replaces the
|
|
4
|
+
* default, all built-in tools are disabled and denied, `.claude` config is
|
|
5
|
+
* ignored, and there's a wall-clock guard so it can't hang.
|
|
6
|
+
*
|
|
7
|
+
* AUTH: the Claude Code OAuth credential (`claude` login or `CLAUDE_CODE_OAUTH_TOKEN`),
|
|
8
|
+
* billing the maintainer's subscription. `ANTHROPIC_API_KEY` shadows it and
|
|
9
|
+
* reverts to pay-per-token — a one-time warning fires before any billable call.
|
|
10
|
+
*/
|
|
11
|
+
export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
12
|
+
export interface AgentQueryOptions {
|
|
13
|
+
model: string;
|
|
14
|
+
/** Default `low` — a single-pass generation needs no deep thinking, and Claude
|
|
15
|
+
* Code otherwise defaults to high effort (minute-plus of thinking). */
|
|
16
|
+
effort?: Effort;
|
|
17
|
+
/** Wall-clock cap; the query is interrupted past this. Default 90s. */
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}
|
|
20
|
+
/** Run one headless Agent-SDK query and return the model's text. */
|
|
21
|
+
export declare function runAgentQuery(system: string, user: string, options: AgentQueryOptions): Promise<string>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const NO_TOOLS = 'You have no tools available. Do not attempt to call any tool, read any file, ' +
|
|
2
|
+
'or run any command. Respond with ONLY what is asked and nothing else.';
|
|
3
|
+
let apiKeyWarningShown = false;
|
|
4
|
+
function warnIfApiKeyShadows() {
|
|
5
|
+
if (!apiKeyWarningShown && process.env['ANTHROPIC_API_KEY']) {
|
|
6
|
+
apiKeyWarningShown = true;
|
|
7
|
+
process.stderr.write('poke-crucible: ANTHROPIC_API_KEY is set — LLM calls will bill pay-per-token, ' +
|
|
8
|
+
'not your Claude subscription. Unset it to use the subscription.\n');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Run one headless Agent-SDK query and return the model's text. */
|
|
12
|
+
export async function runAgentQuery(system, user, options) {
|
|
13
|
+
warnIfApiKeyShadows();
|
|
14
|
+
const { query } = await import('@anthropic-ai/claude-agent-sdk');
|
|
15
|
+
const timeoutMs = options.timeoutMs ?? 90_000;
|
|
16
|
+
const stream = query({
|
|
17
|
+
prompt: user,
|
|
18
|
+
options: {
|
|
19
|
+
systemPrompt: `${NO_TOOLS}\n\n${system}`,
|
|
20
|
+
model: options.model,
|
|
21
|
+
effort: options.effort ?? 'low',
|
|
22
|
+
allowedTools: [],
|
|
23
|
+
permissionMode: 'dontAsk', // headless auto-deny instead of blocking on approval
|
|
24
|
+
settingSources: [],
|
|
25
|
+
maxTurns: 6,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
let timedOut = false;
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
timedOut = true;
|
|
31
|
+
try {
|
|
32
|
+
stream.interrupt?.();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* best effort */
|
|
36
|
+
}
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
let assistantText = '';
|
|
39
|
+
let resultText;
|
|
40
|
+
try {
|
|
41
|
+
for await (const message of stream) {
|
|
42
|
+
if (message['type'] === 'assistant') {
|
|
43
|
+
const inner = message['message'];
|
|
44
|
+
const blocks = Array.isArray(inner?.content) ? inner.content : [];
|
|
45
|
+
for (const b of blocks) {
|
|
46
|
+
const block = b;
|
|
47
|
+
if (block.type === 'text' && typeof block.text === 'string')
|
|
48
|
+
assistantText += block.text;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (message['type'] === 'result') {
|
|
52
|
+
const result = message['result'];
|
|
53
|
+
if (typeof result === 'string')
|
|
54
|
+
resultText = result;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
}
|
|
61
|
+
const text = (resultText ?? assistantText).trim();
|
|
62
|
+
if (!text) {
|
|
63
|
+
if (timedOut)
|
|
64
|
+
throw new Error(`Agent SDK timed out after ${timeoutMs}ms with no output.`);
|
|
65
|
+
throw new Error('Agent SDK returned no text. Check auth: log in with `claude`, and ensure ' +
|
|
66
|
+
'ANTHROPIC_API_KEY is unset (it shadows the subscription OAuth token).');
|
|
67
|
+
}
|
|
68
|
+
return text;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=agent-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-query.js","sourceRoot":"","sources":["../../src/llm/agent-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Damage and type-matchup estimation for the Pilot.
|
|
3
|
+
*
|
|
4
|
+
* These are *heuristic* estimates, not the sim's exact damage calc: enough to
|
|
5
|
+
* rank moves, judge KOs, and weigh switch-ins for competent greedy play. Gen 3
|
|
6
|
+
* specifics baked in here: a move's Physical/Special category follows its
|
|
7
|
+
* TYPE (the sim's gen3 dex already reflects this), STAB is 1.5x, and the
|
|
8
|
+
* effectiveness multiplier is `2 ** dex.getEffectiveness(...)`.
|
|
9
|
+
*/
|
|
10
|
+
import type { Battle, Pokemon } from '@pkmn/sim';
|
|
11
|
+
export interface ResolvedMove {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
category: 'Physical' | 'Special' | 'Status';
|
|
16
|
+
basePower: number;
|
|
17
|
+
/** Accuracy as a probability in [0, 1] (a never-miss move is 1). */
|
|
18
|
+
accuracy: number;
|
|
19
|
+
}
|
|
20
|
+
/** Resolve a move by its set name (so `Hidden Power Bug` gets its real type/power). */
|
|
21
|
+
export declare function resolveMove(battle: Battle, name: string): ResolvedMove;
|
|
22
|
+
/**
|
|
23
|
+
* Type-effectiveness multiplier of `moveType` against a defender, accounting
|
|
24
|
+
* for the ability-based immunities that matter for Gen 3 OU switching.
|
|
25
|
+
*/
|
|
26
|
+
export declare function typeMultiplier(battle: Battle, moveType: string, defender: Pokemon): number;
|
|
27
|
+
/**
|
|
28
|
+
* Estimated damage as a fraction of the defender's max HP if the move hits.
|
|
29
|
+
* Uses the Gen 3 damage formula at level 100 with an average roll; folds in
|
|
30
|
+
* STAB, type effectiveness, burn, and Choice Band.
|
|
31
|
+
*/
|
|
32
|
+
export declare function estimateDamageFraction(battle: Battle, attacker: Pokemon, defender: Pokemon, move: ResolvedMove): number;
|
|
33
|
+
/** The single move (across all of `attacker`'s slots) that hits `defender` hardest. */
|
|
34
|
+
export declare function bestDamageFraction(battle: Battle, attacker: Pokemon, defender: Pokemon): number;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Resolve a move by its set name (so `Hidden Power Bug` gets its real type/power). */
|
|
2
|
+
export function resolveMove(battle, name) {
|
|
3
|
+
const m = battle.dex.moves.get(name);
|
|
4
|
+
const accuracy = m.accuracy === true ? 1 : m.accuracy / 100;
|
|
5
|
+
return {
|
|
6
|
+
id: m.id,
|
|
7
|
+
name: m.name,
|
|
8
|
+
type: m.type,
|
|
9
|
+
category: m.category,
|
|
10
|
+
basePower: m.basePower,
|
|
11
|
+
accuracy,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Type-effectiveness multiplier of `moveType` against a defender, accounting
|
|
16
|
+
* for the ability-based immunities that matter for Gen 3 OU switching.
|
|
17
|
+
*/
|
|
18
|
+
export function typeMultiplier(battle, moveType, defender) {
|
|
19
|
+
const ability = defender.ability;
|
|
20
|
+
if (ability === 'levitate' && moveType === 'Ground')
|
|
21
|
+
return 0;
|
|
22
|
+
if (ability === 'flashfire' && moveType === 'Fire')
|
|
23
|
+
return 0;
|
|
24
|
+
if (ability === 'waterabsorb' && moveType === 'Water')
|
|
25
|
+
return 0;
|
|
26
|
+
if (ability === 'voltabsorb' && moveType === 'Electric')
|
|
27
|
+
return 0;
|
|
28
|
+
const types = defender.types;
|
|
29
|
+
if (!battle.dex.getImmunity(moveType, types))
|
|
30
|
+
return 0;
|
|
31
|
+
let mult = Math.pow(2, battle.dex.getEffectiveness(moveType, types));
|
|
32
|
+
if (ability === 'thickfat' && (moveType === 'Fire' || moveType === 'Ice'))
|
|
33
|
+
mult *= 0.5;
|
|
34
|
+
// Wonder Guard (Shedinja): only super-effective hits land.
|
|
35
|
+
if (ability === 'wonderguard' && mult <= 1)
|
|
36
|
+
return 0;
|
|
37
|
+
return mult;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Estimated damage as a fraction of the defender's max HP if the move hits.
|
|
41
|
+
* Uses the Gen 3 damage formula at level 100 with an average roll; folds in
|
|
42
|
+
* STAB, type effectiveness, burn, and Choice Band.
|
|
43
|
+
*/
|
|
44
|
+
export function estimateDamageFraction(battle, attacker, defender, move) {
|
|
45
|
+
if (move.category === 'Status' || move.basePower <= 0)
|
|
46
|
+
return 0;
|
|
47
|
+
const mult = typeMultiplier(battle, move.type, defender);
|
|
48
|
+
if (mult === 0)
|
|
49
|
+
return 0;
|
|
50
|
+
const physical = move.category === 'Physical';
|
|
51
|
+
const atk = attacker.getStat(physical ? 'atk' : 'spa');
|
|
52
|
+
const def = Math.max(1, defender.getStat(physical ? 'def' : 'spd'));
|
|
53
|
+
const stab = attacker.types.includes(move.type) ? 1.5 : 1;
|
|
54
|
+
const level = attacker.level || 100;
|
|
55
|
+
let power = move.basePower;
|
|
56
|
+
if (physical && attacker.item === 'choiceband')
|
|
57
|
+
power *= 1.5;
|
|
58
|
+
let damage = ((((2 * level) / 5 + 2) * power * atk) / def / 50 + 2) * stab * mult;
|
|
59
|
+
damage *= 0.925; // average of the 0.85–1.00 damage roll
|
|
60
|
+
if (physical && attacker.status === 'brn')
|
|
61
|
+
damage *= 0.5;
|
|
62
|
+
return damage / Math.max(1, defender.maxhp);
|
|
63
|
+
}
|
|
64
|
+
/** The single move (across all of `attacker`'s slots) that hits `defender` hardest. */
|
|
65
|
+
export function bestDamageFraction(battle, attacker, defender) {
|
|
66
|
+
let best = 0;
|
|
67
|
+
attacker.moveSlots.forEach((slot, i) => {
|
|
68
|
+
const name = attacker.set?.moves?.[i] ?? slot.id;
|
|
69
|
+
const f = estimateDamageFraction(battle, attacker, defender, resolveMove(battle, name));
|
|
70
|
+
if (f > best)
|
|
71
|
+
best = f;
|
|
72
|
+
});
|
|
73
|
+
return best;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=damage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"damage.js","sourceRoot":"","sources":["../../src/pilot/damage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EXPERIMENT (ADR 0004): a positional-evaluation Pilot. Instead of "pick max
|
|
3
|
+
* immediate damage", it scores each candidate action by a 1-ply *heuristic*
|
|
4
|
+
* estimate of the resulting position (no sim clone — real-sim forking is
|
|
5
|
+
* infeasible) and picks the best. The evaluation rewards the assets stall
|
|
6
|
+
* accrues: HP and material, foe status (attrition), hazards, boosts.
|
|
7
|
+
*
|
|
8
|
+
* Swapped in via POKE_PILOT=eval for A/B measurement on the archetype ladder.
|
|
9
|
+
* Throwaway until the ladder shows it helps; see ADR 0004.
|
|
10
|
+
*/
|
|
11
|
+
import type { Battle } from '@pkmn/sim';
|
|
12
|
+
type SideID = 'p1' | 'p2';
|
|
13
|
+
interface RM {
|
|
14
|
+
move: string;
|
|
15
|
+
id: string;
|
|
16
|
+
pp?: number;
|
|
17
|
+
disabled?: boolean | string;
|
|
18
|
+
}
|
|
19
|
+
interface RA {
|
|
20
|
+
moves: RM[];
|
|
21
|
+
trapped?: boolean;
|
|
22
|
+
maybeTrapped?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface RP {
|
|
25
|
+
ident: string;
|
|
26
|
+
details: string;
|
|
27
|
+
condition: string;
|
|
28
|
+
active?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface Req {
|
|
31
|
+
active?: RA[];
|
|
32
|
+
side: {
|
|
33
|
+
pokemon: RP[];
|
|
34
|
+
};
|
|
35
|
+
forceSwitch?: boolean[];
|
|
36
|
+
wait?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare function chooseActionEval(battle: Battle, sideID: SideID, request: Req): string;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { bestDamageFraction, estimateDamageFraction, resolveMove } from './damage.js';
|
|
2
|
+
const RECOVERY = new Set([
|
|
3
|
+
'recover', 'softboiled', 'milkdrink', 'slackoff', 'moonlight', 'morningsun', 'synthesis', 'rest', 'wish',
|
|
4
|
+
]);
|
|
5
|
+
const SETUP = {
|
|
6
|
+
swordsdance: { stat: 'atk', cap: 2 }, dragondance: { stat: 'atk', cap: 2 }, bulkup: { stat: 'atk', cap: 2 },
|
|
7
|
+
curse: { stat: 'atk', cap: 2 }, calmmind: { stat: 'spa', cap: 3 }, agility: { stat: 'spe', cap: 2 },
|
|
8
|
+
};
|
|
9
|
+
const PARALYZE = new Set(['thunderwave', 'stunspore', 'glare']);
|
|
10
|
+
const BURN = new Set(['willowisp']);
|
|
11
|
+
const PHAZE = new Set(['roar', 'whirlwind']);
|
|
12
|
+
const hpFrac = (p) => (p.maxhp > 0 ? p.hp / p.maxhp : 0);
|
|
13
|
+
function effSpeed(p) { let s = p.getStat('spe'); if (p.status === 'par')
|
|
14
|
+
s = Math.floor(s * 0.25); return s; }
|
|
15
|
+
function spikes(side) { const c = side.sideConditions?.['spikes']; return c ? (typeof c.layers === 'number' ? c.layers : 1) : 0; }
|
|
16
|
+
const isFainted = (rp) => rp.condition.includes('fnt');
|
|
17
|
+
function battleMon(team, rp) { const sp = (rp.details.split(',')[0] ?? '').trim(); return team.find((m) => m && m.species && m.species.name === sp) ?? null; }
|
|
18
|
+
function statusVal(status) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case 'tox': return 0.4;
|
|
21
|
+
case 'brn': return 0.25;
|
|
22
|
+
case 'psn': return 0.2;
|
|
23
|
+
case 'par': return 0.2;
|
|
24
|
+
case 'slp': return 0.3;
|
|
25
|
+
case 'frz': return 0.5;
|
|
26
|
+
default: return 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function sideTotals(side) { let hp = 0, alive = 0; for (const p of side.pokemon)
|
|
30
|
+
if (p.hp > 0) {
|
|
31
|
+
alive++;
|
|
32
|
+
hp += p.hp / p.maxhp;
|
|
33
|
+
} return { hp, alive }; }
|
|
34
|
+
const canToxic = (foe) => !foe.types.includes('Steel') && !foe.types.includes('Poison') && foe.ability !== 'immunity';
|
|
35
|
+
const canBurn = (foe) => !foe.types.includes('Fire') && foe.ability !== 'waterveil';
|
|
36
|
+
function classify(m) {
|
|
37
|
+
if (RECOVERY.has(m.id))
|
|
38
|
+
return 'recover';
|
|
39
|
+
if (m.id === 'spikes')
|
|
40
|
+
return 'spikes';
|
|
41
|
+
if (m.id === 'rapidspin')
|
|
42
|
+
return 'spin';
|
|
43
|
+
if (m.id === 'toxic')
|
|
44
|
+
return 'toxic';
|
|
45
|
+
if (BURN.has(m.id))
|
|
46
|
+
return 'wisp';
|
|
47
|
+
if (PARALYZE.has(m.id))
|
|
48
|
+
return 'para';
|
|
49
|
+
if (PHAZE.has(m.id))
|
|
50
|
+
return 'phaze';
|
|
51
|
+
if (SETUP[m.id])
|
|
52
|
+
return 'setup';
|
|
53
|
+
if (m.category !== 'Status' && m.basePower > 0)
|
|
54
|
+
return 'damage';
|
|
55
|
+
return 'other';
|
|
56
|
+
}
|
|
57
|
+
// Weighted position score (my perspective) from post-turn scalar estimates.
|
|
58
|
+
function score(myHp, foeHp, myAlive, foeAlive, foeStatus, myStatus, foeSpikes, mySpikes, boost) {
|
|
59
|
+
return (myHp - foeHp) + 0.8 * (myAlive - foeAlive) + (foeStatus - myStatus)
|
|
60
|
+
+ 0.15 * (foeSpikes - mySpikes) + 0.3 * boost;
|
|
61
|
+
}
|
|
62
|
+
/** Estimate the position score after I use `move` this turn and the foe replies. */
|
|
63
|
+
function scoreMove(battle, myIdx, move) {
|
|
64
|
+
const me = battle.sides[myIdx], foe = battle.sides[1 - myIdx];
|
|
65
|
+
const ma = me.active[0], fa = foe.active[0];
|
|
66
|
+
const mt = sideTotals(me), ft = sideTotals(foe);
|
|
67
|
+
const kind = classify(move);
|
|
68
|
+
let myActive = hpFrac(ma), foeActive = hpFrac(fa);
|
|
69
|
+
let foeStatus = statusVal(fa.status), myStatus = statusVal(ma.status);
|
|
70
|
+
let fSpikes = spikes(foe), mSpikes = spikes(me), boost = 0;
|
|
71
|
+
const myDmg = estimateDamageFraction(battle, ma, fa, move) * (move.accuracy || 1);
|
|
72
|
+
const foeDmg = bestDamageFraction(battle, fa, ma);
|
|
73
|
+
const iFaster = effSpeed(ma) > effSpeed(fa);
|
|
74
|
+
if (kind === 'recover')
|
|
75
|
+
myActive = Math.min(1, myActive + Math.min(0.5, 1 - myActive));
|
|
76
|
+
if (kind === 'spikes' && fSpikes < 3)
|
|
77
|
+
fSpikes += 1;
|
|
78
|
+
if (kind === 'spin')
|
|
79
|
+
mSpikes = 0;
|
|
80
|
+
if (kind === 'toxic' && fa.status === '' && canToxic(fa))
|
|
81
|
+
foeStatus = statusVal('tox');
|
|
82
|
+
if (kind === 'wisp' && fa.status === '' && canBurn(fa))
|
|
83
|
+
foeStatus = statusVal('brn');
|
|
84
|
+
if (kind === 'para' && fa.status === '')
|
|
85
|
+
foeStatus = statusVal('par');
|
|
86
|
+
if (kind === 'setup') {
|
|
87
|
+
const s = SETUP[move.id];
|
|
88
|
+
if (ma.boosts[s.stat] < s.cap)
|
|
89
|
+
boost = 1;
|
|
90
|
+
}
|
|
91
|
+
// Resolve the HP exchange with speed / KO ordering.
|
|
92
|
+
if (iFaster) {
|
|
93
|
+
foeActive -= myDmg;
|
|
94
|
+
if (foeActive > 0)
|
|
95
|
+
myActive -= foeDmg;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
myActive -= foeDmg;
|
|
99
|
+
if (myActive > 0)
|
|
100
|
+
foeActive -= myDmg;
|
|
101
|
+
}
|
|
102
|
+
const myFaint = myActive <= 0, foeFaint = foeActive <= 0;
|
|
103
|
+
const myHpTot = mt.hp - hpFrac(ma) + Math.max(0, myActive);
|
|
104
|
+
const foeHpTot = ft.hp - hpFrac(fa) + Math.max(0, foeActive);
|
|
105
|
+
return score(myHpTot, foeHpTot, mt.alive - (myFaint ? 1 : 0), ft.alive - (foeFaint ? 1 : 0), foeFaint ? 0 : foeStatus, myFaint ? 0 : myStatus, fSpikes, mSpikes, boost);
|
|
106
|
+
}
|
|
107
|
+
/** Estimate the position score after I switch to `c` and the foe hits it. */
|
|
108
|
+
function scoreSwitch(battle, myIdx, c) {
|
|
109
|
+
const me = battle.sides[myIdx], foe = battle.sides[1 - myIdx];
|
|
110
|
+
const fa = foe.active[0];
|
|
111
|
+
const mt = sideTotals(me), ft = sideTotals(foe);
|
|
112
|
+
const foeDmg = bestDamageFraction(battle, fa, c);
|
|
113
|
+
const cAfter = hpFrac(c) - foeDmg;
|
|
114
|
+
const myFaint = cAfter <= 0;
|
|
115
|
+
const myHpTot = mt.hp - hpFrac(c) + Math.max(0, cAfter);
|
|
116
|
+
return score(myHpTot, ft.hp, mt.alive - (myFaint ? 1 : 0), ft.alive, statusVal(fa.status), myFaint ? 0 : statusVal(c.status), spikes(foe), spikes(me), 0);
|
|
117
|
+
}
|
|
118
|
+
export function chooseActionEval(battle, sideID, request) {
|
|
119
|
+
const myIdx = sideID === 'p1' ? 0 : 1;
|
|
120
|
+
const me = battle.sides[myIdx];
|
|
121
|
+
const foe = battle.sides[1 - myIdx];
|
|
122
|
+
const team = me?.pokemon ?? [];
|
|
123
|
+
// Enumerate switch candidates once.
|
|
124
|
+
const switches = [];
|
|
125
|
+
request.side.pokemon.forEach((rp, i) => {
|
|
126
|
+
if (rp.active || isFainted(rp))
|
|
127
|
+
return;
|
|
128
|
+
const c = battleMon(team, rp);
|
|
129
|
+
if (c && foe?.active[0])
|
|
130
|
+
switches.push({ choiceIndex: i + 1, value: scoreSwitch(battle, myIdx, c) });
|
|
131
|
+
});
|
|
132
|
+
if (request.forceSwitch?.[0]) {
|
|
133
|
+
const best = switches.sort((a, b) => b.value - a.value)[0];
|
|
134
|
+
return best ? `switch ${best.choiceIndex}` : 'pass';
|
|
135
|
+
}
|
|
136
|
+
const active = request.active?.[0];
|
|
137
|
+
if (!active || !me?.active[0] || !foe?.active[0])
|
|
138
|
+
return 'default';
|
|
139
|
+
let best = null;
|
|
140
|
+
active.moves.forEach((rm, i) => {
|
|
141
|
+
if (rm.disabled)
|
|
142
|
+
return;
|
|
143
|
+
if (typeof rm.pp === 'number' && rm.pp <= 0)
|
|
144
|
+
return;
|
|
145
|
+
const name = me.active[0].set?.moves?.[i] ?? rm.move ?? rm.id;
|
|
146
|
+
const value = scoreMove(battle, myIdx, resolveMove(battle, name));
|
|
147
|
+
if (!best || value > best.value)
|
|
148
|
+
best = { kind: 'move', index: i, value };
|
|
149
|
+
});
|
|
150
|
+
const trapped = active.trapped || active.maybeTrapped;
|
|
151
|
+
if (!trapped) {
|
|
152
|
+
for (const sw of switches) {
|
|
153
|
+
if (!best || sw.value > best.value)
|
|
154
|
+
best = { kind: 'switch', index: sw.choiceIndex, value: sw.value };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!best)
|
|
158
|
+
return 'default';
|
|
159
|
+
return best.kind === 'move' ? `move ${best.index + 1}` : `switch ${best.index}`;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=eval-pilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-pilot.js","sourceRoot":"","sources":["../../src/pilot/eval-pilot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Pilot — one competent Gen 3 heuristic policy, identical on both sides
|
|
3
|
+
* (ADR 0002). Given the omniscient battle state and the current request, it
|
|
4
|
+
* returns a Showdown choice string.
|
|
5
|
+
*
|
|
6
|
+
* Competence is layered as an ordered decision tree; each layer only fires when
|
|
7
|
+
* the earlier, higher-priority ones decline:
|
|
8
|
+
* 1. secure a KO we can safely land (max-damage core)
|
|
9
|
+
* 2. pivot out of a losing matchup (matchup switching)
|
|
10
|
+
* 3. heal when worn down and safe (recovery / stall)
|
|
11
|
+
* 4. lay Spikes / spin them away (hazards)
|
|
12
|
+
* 5. spread status on a fresh target (Toxic / paralysis / burn)
|
|
13
|
+
* 6. set up when the foe can't pressure us (Dragon Dance, Calm Mind, ...)
|
|
14
|
+
* 7. otherwise hit as hard as possible (max-damage fallback)
|
|
15
|
+
*
|
|
16
|
+
* Per ADR 0002 / the PRD, the Pilot is never asserted move-by-move: its
|
|
17
|
+
* competence is judged only through outcome thresholds at the `evaluate` seam.
|
|
18
|
+
*/
|
|
19
|
+
import { BattleStreams } from '@pkmn/sim';
|
|
20
|
+
import type { Battle } from '@pkmn/sim';
|
|
21
|
+
export type SideID = 'p1' | 'p2';
|
|
22
|
+
type PlayerStream = ConstructorParameters<typeof BattleStreams.BattlePlayer>[0];
|
|
23
|
+
interface RequestMove {
|
|
24
|
+
move: string;
|
|
25
|
+
id: string;
|
|
26
|
+
pp?: number;
|
|
27
|
+
disabled?: boolean | string;
|
|
28
|
+
}
|
|
29
|
+
interface RequestActive {
|
|
30
|
+
moves: RequestMove[];
|
|
31
|
+
/** Known trap (e.g. Arena Trap / Magnet Pull): switching is forbidden. */
|
|
32
|
+
trapped?: boolean;
|
|
33
|
+
/** Possible trap: switching may be rejected, so we treat it as forbidden. */
|
|
34
|
+
maybeTrapped?: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface RequestPokemon {
|
|
37
|
+
ident: string;
|
|
38
|
+
details: string;
|
|
39
|
+
condition: string;
|
|
40
|
+
active?: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface PlayerRequest {
|
|
43
|
+
active?: RequestActive[];
|
|
44
|
+
side: {
|
|
45
|
+
pokemon: RequestPokemon[];
|
|
46
|
+
};
|
|
47
|
+
forceSwitch?: boolean[];
|
|
48
|
+
wait?: boolean;
|
|
49
|
+
teamPreview?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare function chooseAction(battle: Battle, sideID: SideID, request: PlayerRequest): string;
|
|
52
|
+
/**
|
|
53
|
+
* A player that drives one side of a BattleStream with the heuristic Pilot.
|
|
54
|
+
* It reads the shared omniscient {@link Battle} through `getBattle` (both sides
|
|
55
|
+
* see the same information, so the contest stays fair).
|
|
56
|
+
*/
|
|
57
|
+
export declare class PilotPlayer extends BattleStreams.BattlePlayer {
|
|
58
|
+
private readonly getBattle;
|
|
59
|
+
private readonly sideID;
|
|
60
|
+
/** Guards against re-entrant recovery within a single stuck decision. */
|
|
61
|
+
private recovering;
|
|
62
|
+
constructor(playerStream: PlayerStream, getBattle: () => Battle | null, sideID: SideID);
|
|
63
|
+
receiveRequest(request: PlayerRequest): void;
|
|
64
|
+
/**
|
|
65
|
+
* Safety net: if the heuristic ever produces an illegal choice (e.g. an
|
|
66
|
+
* uncertain trap it mis-read), fall back to the safest legal action instead
|
|
67
|
+
* of aborting the whole evaluation. Any other error still propagates.
|
|
68
|
+
*/
|
|
69
|
+
receiveError(error: Error): void;
|
|
70
|
+
}
|
|
71
|
+
export {};
|