Spaces:
Running
Running
File size: 4,875 Bytes
5c2ed06 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
/**
* Random Simulation harness for testing and benchmarking purposes.
* Pokemon Showdown - http://pokemonshowdown.com/
*
* Refer to `README.md` for detailed usage instructions.
*
* @license MIT
*/
'use strict';
if (process.argv[2]) {
const help = ['help', '-help', '--help', 'h', '-h', '--help', '?', '-?', '--?'].includes(process.argv[2]);
const unknown = !['multi', 'random', 'exhaustive'].includes(process.argv[2]) && !/^[0-9]+$/.test(process.argv[2]);
if (help || unknown) {
const out = help ? console.log : console.error;
if (unknown) out(`Unrecognized command: ${process.argv[2]}\n`);
out('tools/simulate random');
out('');
out(' Randomly simulates `--num` total games (default=100).');
out(' The format(s) played and what gets output can be altered.');
out('');
out('tools/simulate exhaustive');
out('');
out(' Plays through enough randomly simulated battles to exhaust');
out(' all options of abilities/items/moves/pokemon. `--cycles` can');
out(' used to run through multiple exhaustions of the options.');
out('');
out('tools/simulate help');
out('');
out(' Displays this reference');
out('');
out('Please refer to tools/SIMULATE.md for full documentation');
process.exit(help ? 0 : 1);
}
}
require('child_process').execSync('node ' + __dirname + "/../../build");
const Dex = require('../../sim/dex').Dex;
global.Config = { allowrequestingties: false };
Dex.includeModData();
const { ExhaustiveRunner } = require('../../sim/tools/exhaustive-runner');
const { MultiRandomRunner } = require('../../sim/tools/multi-random-runner');
// Tracks whether some promises threw errors that weren't caught so we can log
// and exit with a non-zero status to fail any tests. This "shouldn't happen"
// because we're "great at propagating promises (TM)", but better safe than sorry.
const RejectionTracker = new class {
constructor() {
this.unhandled = [];
}
onUnhandledRejection(reason, promise) {
this.unhandled.push({ reason, promise });
}
onRejectionHandled(promise) {
this.unhandled.splice(this.unhandled.findIndex(u => u.promise === promise), 1);
}
onExit(code) {
let i = 0;
for (const u of this.unhandled) {
const error = (u.reason instanceof Error) ? u.reason :
new Error(`Promise rejected with value: ${u.reason}`);
console.error(`UNHANDLED PROMISE REJECTION:\n${error.stack}`);
i++;
}
process.exit(code + i);
}
register() {
process.on('unhandledRejection', (r, p) => this.onUnhandledRejection(r, p));
process.on('rejectionHandled', p => this.onRejectionHandled(p));
process.on('exit', c => this.onExit(c)); // TODO
}
}();
RejectionTracker.register();
function missing(dep) {
try {
require.resolve(dep);
return false;
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') throw err;
return true;
}
}
function shell(cmd) {
require('child_process').execSync(cmd, { stdio: 'inherit', cwd: __dirname });
}
function parseFlags(argv) {
if (!(argv.length > 3 || argv.length === 3 && argv[2].startsWith('-'))) return { _: argv.slice(2) };
if (missing('minimist')) shell('npm install minimist');
return require('minimist')(argv.slice(2));
}
if (!process.argv[2] || /^[0-9]+$/.test(process.argv[2])) process.argv.splice(2, 0, 'multi');
switch (process.argv[2]) {
case 'multi':
case 'random':
{
const argv = parseFlags(process.argv);
const options = { totalGames: 100, ...argv };
options.totalGames = Number(argv._[1] || argv.num) || options.totalGames;
if (argv.seed) options.prng = argv.seed.split(',').map(s => Number(s));
// Run options.totalGames, exiting with the number of games with errors.
(async () => process.exit(await new MultiRandomRunner(options).run()))();
}
break;
case 'exhaustive':
{
const argv = parseFlags(process.argv);
let formats;
if (argv.formats) {
formats = argv.formats.split(',');
} else if (argv.format) {
formats = argv.format.split(',');
} else {
formats = ExhaustiveRunner.FORMATS;
}
let cycles = Number(argv._[1] || argv.cycles) || ExhaustiveRunner.DEFAULT_CYCLES;
let forever = argv.forever;
if (cycles < 0) {
cycles = -cycles;
forever = true;
}
const maxFailures = argv.maxFailures || argv.failures || (formats.length > 1 ? ExhaustiveRunner.MAX_FAILURES : 1);
const prng = argv.seed && argv.seed.split(',').map(s => Number(s));
const maxGames = argv.maxGames || argv.games;
(async () => {
let failures = 0;
do {
for (const format of formats) {
failures += await new ExhaustiveRunner({
format, cycles, prng, maxFailures, log: true, dual: argv.dual, maxGames,
}).run();
process.stdout.write('\n');
if (failures >= maxFailures) break;
}
} while (forever); // eslint-disable-line no-unmodified-loop-condition
process.exit(failures);
})();
}
break;
default:
throw new TypeError('Unknown command' + process.argv[2]);
}
|