summaryrefslogtreecommitdiff
path: root/run_tour.js
diff options
context:
space:
mode:
Diffstat (limited to 'run_tour.js')
-rwxr-xr-xrun_tour.js122
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);