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

145 lines
4.8 KiB
TypeScript
Raw Normal View History

2017-09-24 22:23:22 +00:00
module TK.SpaceTac {
2017-02-24 00:34:31 +00:00
/**
* Duel between two AIs, over multiple battles
*/
export class AIDuel {
static current: AIDuel | null = null
ai1: AbstractAI
ai2: AbstractAI
win1 = 0
win2 = 0
draw = 0
scheduled = null
stopped = false
onupdate: Function | null = null
constructor(ai1: AbstractAI, ai2: AbstractAI) {
this.ai1 = ai1;
this.ai2 = ai2;
}
/**
* Start the duel
*/
start(onupdate: Function | null = null) {
if (!this.scheduled) {
this.stopped = false;
this.scheduled = Timer.global.schedule(100, () => this.next());
this.onupdate = onupdate;
}
}
/**
* Stop the duel
*/
stop() {
this.stopped = true;
if (this.scheduled) {
Timer.global.cancel(this.scheduled);
this.scheduled = null;
}
}
/**
* Update the result of a single battle
*/
update(winner: number) {
if (winner >= 0) {
if (winner == 0) {
2017-02-24 00:34:31 +00:00
this.win1 += 1;
console.log(` => Player 1 wins (${this.ai1})`);
2017-02-24 00:34:31 +00:00
} else {
this.win2 += 1;
console.log(` => Player 2 wins (${this.ai2})`);
2017-02-24 00:34:31 +00:00
}
} else {
this.draw += 1;
console.log(" => draw");
}
if (this.onupdate) {
this.onupdate();
}
}
/**
* Perform the next battle
*/
async next() {
2017-02-24 00:34:31 +00:00
console.log(`${this.ai1.name} vs ${this.ai2.name} ...`);
// Prepare battle
2017-02-24 00:34:31 +00:00
let battle = Battle.newQuickRandom();
battle.fleets.forEach((fleet, findex) => {
fleet.ships.forEach((ship, sindex) => {
ship.name = `F${findex + 1}S${sindex + 1} (${ship.model.name})`;
});
});
2017-02-24 00:34:31 +00:00
// Run battle
2017-10-25 22:45:53 +00:00
while (!battle.ended && battle.cycle < 100) {
if (this.stopped) {
return;
}
let playing = battle.playing_ship;
2017-03-09 17:11:00 +00:00
if (playing) {
let ai = (playing.fleet == battle.fleets[0]) ? this.ai1 : this.ai2;
ai.ship = playing;
await ai.play();
2017-02-24 00:34:31 +00:00
}
}
// Update results, and go on to next battle
if (battle.outcome && !battle.outcome.draw && battle.outcome.winner) {
this.update(battle.fleets.indexOf(battle.outcome.winner));
2017-02-24 00:34:31 +00:00
} else {
this.update(-1);
2017-02-24 00:34:31 +00:00
}
this.scheduled = Timer.global.schedule(50, () => this.next());
2017-02-24 00:34:31 +00:00
}
/**
* Setup the duel HTML page
*/
static setup(element: HTMLElement) {
2017-03-09 17:11:00 +00:00
let fakeship = new Ship();
let ais = [new TacticalAI(fakeship), new AbstractAI(fakeship)];
2017-02-24 00:34:31 +00:00
ais.forEach((ai, idx) => {
let selects = element.getElementsByTagName("select");
for (let i = 0; i < selects.length; i++) {
let option = document.createElement("option");
option.setAttribute("value", idx.toString());
option.textContent = ai.name;
selects[i].appendChild(option);
}
ai.name += `${idx + 1}`;
ai.timer = new Timer();
ai.timer.schedule = (delay, callback) => Timer.global.schedule(1, callback);
2017-02-24 00:34:31 +00:00
});
let button = element.getElementsByTagName("button").item(0);
button.onclick = () => {
if (AIDuel.current) {
AIDuel.current.stop();
AIDuel.current = null;
button.textContent = "Start !";
} else {
console.clear();
2017-02-24 00:34:31 +00:00
let ai1 = parseInt(element.getElementsByTagName("select").item(0).value);
let ai2 = parseInt(element.getElementsByTagName("select").item(1).value);
2017-03-09 17:11:00 +00:00
let duel = new AIDuel(ais[ai1], ais[ai2]);
AIDuel.current = duel;
duel.start(() => {
element.getElementsByClassName("win1").item(0).textContent = duel.win1.toString();
element.getElementsByClassName("win2").item(0).textContent = duel.win2.toString();
element.getElementsByClassName("draw").item(0).textContent = duel.draw.toString();
2017-02-24 00:34:31 +00:00
});
button.textContent = "Stop !";
}
}
}
}
}