2017-12-21 19:04:54 +00:00
|
|
|
module TK.SpaceTac {
|
2018-03-06 17:41:38 +00:00
|
|
|
/**
|
|
|
|
* Initialize the background worker, if possible
|
|
|
|
*/
|
|
|
|
function initializeWorker(): Worker | null {
|
|
|
|
if (typeof window != "undefined" && (<any>window).Worker) {
|
|
|
|
try {
|
|
|
|
return new Worker('aiworker.js'); // TODO not hard-coded
|
|
|
|
} catch {
|
|
|
|
console.error("Could not initialize AI web worker");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 19:04:54 +00:00
|
|
|
/**
|
|
|
|
* AI processing, either in the current process or in a web worker
|
|
|
|
*/
|
|
|
|
export class AIWorker {
|
2018-03-06 17:41:38 +00:00
|
|
|
private static worker = initializeWorker();
|
2017-12-21 19:04:54 +00:00
|
|
|
|
2019-05-22 18:06:42 +00:00
|
|
|
constructor(private battle: Battle, private player = battle.fleets[1].player, private debug = false) {
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the current playing ship with an AI
|
|
|
|
*
|
|
|
|
* This should be done on the real battle state
|
|
|
|
*/
|
2019-05-22 18:06:42 +00:00
|
|
|
static process(battle: Battle, player?: Player, debug = false): Promise<TurnPlan> {
|
|
|
|
const processing = new AIWorker(battle, player, debug);
|
|
|
|
return processing.processAuto();
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process AI in a webworker if possible, else do the work in the render thread
|
|
|
|
*/
|
2019-05-22 18:06:42 +00:00
|
|
|
processAuto(): Promise<TurnPlan> {
|
2018-03-06 17:41:38 +00:00
|
|
|
if (!this.debug && AIWorker.worker) {
|
|
|
|
try {
|
2019-05-22 18:06:42 +00:00
|
|
|
return this.processInWorker(AIWorker.worker);
|
2018-03-06 17:41:38 +00:00
|
|
|
} catch (err) {
|
|
|
|
console.error("Web worker error, falling back to main thread", err);
|
2019-05-22 18:06:42 +00:00
|
|
|
return this.processHere();
|
2018-03-06 17:41:38 +00:00
|
|
|
}
|
2017-12-21 19:04:54 +00:00
|
|
|
} else {
|
2019-05-22 18:06:42 +00:00
|
|
|
return this.processHere();
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process AI in a webworker
|
|
|
|
*/
|
2019-05-22 18:06:42 +00:00
|
|
|
processInWorker(worker: Worker): Promise<TurnPlan> {
|
2017-12-21 19:04:54 +00:00
|
|
|
let serializer = new Serializer(TK.SpaceTac);
|
2019-05-22 18:06:42 +00:00
|
|
|
let promise: Promise<TurnPlan> = new Promise((resolve, reject) => {
|
2018-03-06 17:41:38 +00:00
|
|
|
worker.onerror = reject;
|
2017-12-21 19:04:54 +00:00
|
|
|
worker.onmessage = (message) => {
|
2019-05-22 18:06:42 +00:00
|
|
|
let plan = serializer.unserialize(message.data);
|
|
|
|
if (this.debug) {
|
|
|
|
console.log("Received from AI worker", plan);
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
2019-05-22 18:06:42 +00:00
|
|
|
// TODO check type
|
|
|
|
resolve(plan);
|
2017-12-21 19:04:54 +00:00
|
|
|
};
|
|
|
|
});
|
2019-05-22 18:06:42 +00:00
|
|
|
worker.postMessage(serializer.serialize(this));
|
|
|
|
return promise;
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process AI in current thread
|
|
|
|
*/
|
2019-05-22 18:06:42 +00:00
|
|
|
async processHere(): Promise<TurnPlan> {
|
2019-05-23 17:54:05 +00:00
|
|
|
const settings = AISettingsStock.default(this.battle, this.player); // TODO settings choice ?
|
|
|
|
let ai = new ContinuousAI(settings, this.debug);
|
2019-05-22 18:06:42 +00:00
|
|
|
ai.play();
|
|
|
|
const result = await ai.getPlan(); // TODO Only when human player is done
|
|
|
|
return result.plan;
|
2017-12-21 19:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|