diff options
Diffstat (limited to 'run_tour.js')
-rwxr-xr-x | run_tour.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/run_tour.js b/run_tour.js new file mode 100755 index 0000000..ef6492f --- /dev/null +++ b/run_tour.js @@ -0,0 +1,122 @@ +#!/usr/bin/env node + +if (process.argv.length != 7) { + console.log("Usage: ./run_tour.js <seed_file> <num_turns> <num_workers> <output_file> <logs_dir>"); + console.log("<seed_file> should contain a 32-hex-digit seed on each line. One game will be run for each seed. The games will all have <num_turns> turns."); + console.log("The tournament will be run using <num_workers> parallel workers.") + console.log("Output results will be written to <output_file>.") + console.log("Game log files will be written to the directory <logs_dir>."); + process.exit(1); +} + +const fs = require("fs"); +const child_process = require("child_process"); +const mkdirp = require("mkdirp"); + +const seed_file = process.argv[2]; +const num_turns = +process.argv[3]; +const num_workers = +process.argv[4]; +const output_file = process.argv[5]; +const logs_dir = process.argv[6]; + +mkdirp.sync(logs_dir); + +const output_stream = fs.createWriteStream(output_file); + +const seeds = + fs.readFileSync(seed_file).toString() + .split("\n").filter(s => s.length > 0); + + +console.log(seeds.length + " games to play using " + num_workers + " workers."); + +function register_result(result) { + output_stream.write(result + "\n"); + + const seed = result.split(" ", 1)[0]; + console.log("Finished game with seed " + seed); +} + +const workers = []; +const current_seed = new Array(num_workers).fill(null); +const start_at = new Array(num_workers).fill(null); + +function distribute_work() { + if (seeds.length == 0) return; + + for (let i = 0; i < num_workers; i++) { + if (current_seed[i] == null) { + const seed = seeds.shift(); + current_seed[i] = seed; + start_at[i] = new Date(); + workers[i].stdin.write(seed + "\n"); + + console.log("Started game with seed " + seed); + } + } +} + +function check_finished() { + for (let i = 0; i < num_workers; i++) { + if (current_seed[i] != null) return false; + } + + console.log("\nFINISHED! Shutting down..."); + + output_stream.end(); + for (const worker of workers) { + worker.stdin.end(); + } + + console.log("All done."); + setTimeout(() => process.exit(0), 500); +} + +function spawn_worker(index) { + const worker = child_process.spawn( + "node", + ["tour_worker.js", num_turns.toString(), logs_dir], + { stdio: ["pipe", "pipe", "inherit"] } + ); + + let buffer = ""; + worker.stdout.on("data", (data) => { + buffer += data; + let idx = buffer.indexOf("\n"); + while (idx != -1) { + const line = buffer.slice(0, idx); + buffer = buffer.slice(idx + 1); + idx = buffer.indexOf("\n"); + + register_result(line); + current_seed[index] = null; + start_at[index] = null; + distribute_work(); + if (check_finished()) return; + } + }); + + return worker; +} + +for (let i = 0; i < num_workers; i++) { + workers.push(spawn_worker(workers.length)); +} + +distribute_work(); + +// Check for stuck games once in a while +setInterval(function() { + const max_game_time = 1350 * num_turns; + const now = new Date(); + + for (let i = 0; i < num_workers; i++) { + if (current_seed[i] != null && now - start_at[i] > max_game_time) { + console.log("Game for seed " + current_seed[i] + " is taking too long, KILLING!"); + workers[i].kill("SIGKILL"); + + console.log("Spawning new worker and hoping everything's fine..."); + workers[i] = spawn_worker(i); + } + } +}, 60 * 1000); |