Spaces:
Running
Running
/** | |
* Battle Simulator multi random runner. | |
* Pokemon Showdown - http://pokemonshowdown.com/ | |
* | |
* @license MIT | |
*/ | |
import { PRNG, type PRNGSeed } from '../prng'; | |
import { Runner, type RunnerOptions } from './runner'; | |
export interface MultiRandomRunnerOptions extends Partial<RunnerOptions> { | |
totalGames: number; | |
prng?: PRNG | PRNGSeed | null; | |
format?: string; | |
cycle?: boolean; | |
all?: boolean; | |
async?: boolean; | |
} | |
export class MultiRandomRunner { | |
static readonly FORMATS = [ | |
'gen8randombattle', 'gen8randomdoublesbattle', 'gen8battlefactory', | |
'gen7randombattle', 'gen7battlefactory', | |
'gen6randombattle', 'gen6battlefactory', | |
'gen5randombattle', | |
'gen4randombattle', | |
'gen3randombattle', | |
'gen2randombattle', | |
'gen1randombattle', | |
]; | |
private readonly options: Partial<RunnerOptions>; | |
private readonly totalGames: number; | |
private readonly prng: PRNG; | |
private readonly format: string | undefined; | |
private readonly cycle: boolean; | |
private readonly all: boolean; | |
private readonly isAsync: boolean; | |
private formatIndex: number; | |
private numGames: number; | |
constructor(options: MultiRandomRunnerOptions) { | |
this.options = { ...options }; | |
this.totalGames = options.totalGames; | |
this.prng = PRNG.get(options.prng); | |
this.options.prng = this.prng; | |
this.format = options.format; | |
this.cycle = !!options.cycle; | |
this.all = !!options.all; | |
this.isAsync = !!options.async; | |
this.formatIndex = 0; | |
this.numGames = 0; | |
} | |
async run() { | |
let games = []; | |
let format: string | false; | |
let lastFormat: string | false = false; | |
let failures = 0; | |
while ((format = this.getNextFormat())) { | |
if (this.all && lastFormat && format !== lastFormat) { | |
if (this.isAsync) await Promise.all(games); | |
games = []; | |
} | |
const seed = this.prng.getSeed(); | |
const game = new Runner({ format, ...this.options }).run().catch(err => { | |
failures++; | |
console.error( | |
`Run \`node tools/simulate multi 1 --format=${format} --seed=${seed}\` ` + | |
`to debug (optionally with \`--output\` and/or \`--input\` for more info):\n`, | |
err | |
); | |
}); | |
if (!this.isAsync) await game; | |
games.push(game); | |
lastFormat = format; | |
} | |
if (this.isAsync) await Promise.all(games); | |
return failures; | |
} | |
private getNextFormat() { | |
const FORMATS = MultiRandomRunner.FORMATS; | |
if (this.formatIndex > FORMATS.length) return false; | |
if (this.numGames++ < this.totalGames) { | |
if (this.format) { | |
return this.format; | |
} else if (this.all) { | |
return FORMATS[this.formatIndex]; | |
} else if (this.cycle) { | |
const format = FORMATS[this.formatIndex]; | |
this.formatIndex = (this.formatIndex + 1) % FORMATS.length; | |
return format; | |
} else { | |
return this.prng.sample(FORMATS); | |
} | |
} else if (this.all) { | |
this.numGames = 1; | |
this.formatIndex++; | |
return FORMATS[this.formatIndex]; | |
} | |
return false; | |
} | |
} | |