#!/usr/bin/env node if (process.argv.length != 7) { console.log("Usage: ./run_tour.js "); console.log(" should contain a 32-hex-digit seed on each line. One game will be run for each seed. The games will all have turns."); console.log("The tournament will be run using parallel workers.") console.log("Output results will be written to .") console.log("Game log files will be written to the directory ."); 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);