1
0
Fork 0
spacetac/src/core/ai/AbstractAI.ts

119 lines
3.4 KiB
TypeScript
Raw Normal View History

module TS.SpaceTac {
/**
* Base class for all Artificial Intelligence interaction
*/
export class AbstractAI {
// Name of the AI
name: string
2015-02-17 00:00:00 +00:00
// Current ship being played
ship: Ship
2015-02-17 00:00:00 +00:00
// Random generator, if needed
random = RandomGenerator.global
2017-02-16 22:59:41 +00:00
// Timer for scheduled calls
timer: Timer
2017-02-16 22:59:41 +00:00
// Debug mode
debug = false
// Time at which work as started
private started: number
2015-02-17 00:00:00 +00:00
2017-03-09 17:11:00 +00:00
constructor(ship: Ship, timer = Timer.global, name?: string) {
this.ship = ship;
this.timer = timer;
this.name = name || classname(this);
2015-02-17 00:00:00 +00:00
}
2017-02-24 00:34:31 +00:00
toString = () => this.name;
/**
* Start playing current ship's turn.
*/
async play(debug = false): Promise<void> {
2015-02-17 00:00:00 +00:00
this.started = (new Date()).getTime();
this.debug = debug;
2017-02-24 00:34:31 +00:00
if (!this.ship.playing) {
console.error(`${this.name} tries to play a ship out of turn`);
return;
2017-02-16 22:59:41 +00:00
}
2015-02-17 00:00:00 +00:00
// Work loop
this.initWork();
let last = new Date().getTime();
let ship = this.ship;
while (this.doWorkUnit()) {
if (!this.ship.playing || this.ship != ship) {
console.error(`${this.name} switched to another ship in unit work`);
break;
}
if (this.getDuration() >= 10000) {
console.warn(`${this.name} takes too long to play, forcing turn end`);
break;
}
let t = new Date().getTime();
if (t - last > 50) {
await this.timer.sleep(10);
last = t + 10;
2015-02-17 00:00:00 +00:00
}
}
2015-02-17 00:00:00 +00:00
// End the ship turn
2017-09-19 15:09:06 +00:00
this.applyAction(new EndTurnAction(), Target.newFromShip(ship));
2015-02-17 00:00:00 +00:00
}
2017-02-16 22:59:41 +00:00
/**
* Make the AI play an action
*
* This should be the only real interaction point with battle state
2017-02-16 22:59:41 +00:00
*/
2017-09-19 15:09:06 +00:00
private applyAction(action: BaseAction, target: Target): boolean {
return action.apply(this.ship, target);
2017-02-16 22:59:41 +00:00
}
/**
* Make the AI play a full maneuver (sequence of actions)
*/
applyManeuver(maneuver: Maneuver): boolean {
if (maneuver.simulation.success) {
let parts = maneuver.simulation.parts;
for (let i = 0; i < parts.length; i++) {
let part = parts[i];
if (part.action instanceof EndTurnAction || !part.possible || !this.applyAction(part.action, part.target)) {
return false;
2017-03-09 17:11:00 +00:00
}
2017-02-16 22:59:41 +00:00
}
return true;
2015-02-17 00:00:00 +00:00
} else {
return false;
2015-02-17 00:00:00 +00:00
}
}
2017-02-16 22:59:41 +00:00
/**
* Prepare the groundwork for future doWorkUnit calls
2017-02-16 22:59:41 +00:00
*/
protected initWork(): void {
}
/**
* Do a single unit of synchronous work
*
* Returns true if something was done, false if the AI should end the ship turn and stop.
*/
protected doWorkUnit(): boolean {
return false;
2017-02-16 22:59:41 +00:00
}
/**
* Get the time spent thinking on this turn
2017-02-16 22:59:41 +00:00
*/
protected getDuration() {
return (new Date()).getTime() - this.started;
}
}
}