1
0
Fork 0

Fixed several AI related problems

This commit is contained in:
Michaël Lemaire 2018-03-02 00:14:09 +01:00
parent ea8771fc75
commit 851c59bac1
9 changed files with 49 additions and 27 deletions

View file

@ -69,7 +69,6 @@ Ships models and actions
Artificial Intelligence Artificial Intelligence
----------------------- -----------------------
* Fix tendency to use moves for nothing
* Produce interesting "angle" areas * Produce interesting "angle" areas
* Evaluate active effects * Evaluate active effects
* Account for luck * Account for luck

View file

@ -27,7 +27,7 @@ module TK.SpaceTac {
* Process AI in a webworker if possible, else do the work in the render thread * Process AI in a webworker if possible, else do the work in the render thread
*/ */
async processAuto(feedback: AIFeedback): Promise<void> { async processAuto(feedback: AIFeedback): Promise<void> {
if ((<any>window).Worker) { if (!this.debug && (<any>window).Worker) {
await this.processInWorker(feedback); await this.processInWorker(feedback);
} else { } else {
await this.processHere(feedback); await this.processHere(feedback);

View file

@ -41,6 +41,13 @@ module TK.SpaceTac {
return `Use ${this.action.code} on ${this.target.jasmineToString()}`; return `Use ${this.action.code} on ${this.target.jasmineToString()}`;
} }
/**
* Returns true if the maneuver has at least one part doable
*/
isPossible(): boolean {
return any(this.simulation.parts, part => part.possible);
}
/** /**
* Returns true if the maneuver cannot be fully done this turn * Returns true if the maneuver cannot be fully done this turn
*/ */
@ -87,7 +94,9 @@ module TK.SpaceTac {
for (let i = 0; i < parts.length; i++) { for (let i = 0; i < parts.length; i++) {
let part = parts[i]; let part = parts[i];
if (part.action instanceof EndTurnAction || part.possible) { if (part.action instanceof EndTurnAction || part.possible) {
return battle.applyOneAction(part.action.id, part.target); if (!battle.applyOneAction(part.action.id, part.target)) {
return false;
}
} else { } else {
return false; return false;
} }

View file

@ -40,7 +40,7 @@ module TK.SpaceTac {
[maneuver, producer] = producer(); [maneuver, producer] = producer();
} }
if (maneuver) { if (maneuver && maneuver.isPossible()) {
if (producer) { if (producer) {
this.producers.push(producer); this.producers.push(producer);
} }
@ -113,12 +113,12 @@ module TK.SpaceTac {
let evaluators: EvaluatorHelper[] = [ let evaluators: EvaluatorHelper[] = [
scaled(TacticalAIHelpers.evaluateTurnCost, 1), scaled(TacticalAIHelpers.evaluateTurnCost, 1),
scaled(TacticalAIHelpers.evaluateOverheat, 10), scaled(TacticalAIHelpers.evaluateOverheat, 3),
scaled(TacticalAIHelpers.evaluateEnemyHealth, 500), scaled(TacticalAIHelpers.evaluateEnemyHealth, 5),
scaled(TacticalAIHelpers.evaluateAllyHealth, 800), scaled(TacticalAIHelpers.evaluateAllyHealth, 20),
scaled(TacticalAIHelpers.evaluateClustering, 3), scaled(TacticalAIHelpers.evaluateClustering, 4),
scaled(TacticalAIHelpers.evaluatePosition, 1), scaled(TacticalAIHelpers.evaluatePosition, 0.5),
scaled(TacticalAIHelpers.evaluateIdling, 1), scaled(TacticalAIHelpers.evaluateIdling, 2),
] ]
let battle = nn(this.ship.getBattle()); let battle = nn(this.ship.getBattle());

View file

@ -120,20 +120,31 @@ module TK.SpaceTac.Specs {
TestTools.setShipModel(ship, 100, 0, 10); TestTools.setShipModel(ship, 100, 0, 10);
let engine = TestTools.addEngine(ship, 50); let engine = TestTools.addEngine(ship, 50);
let weapon = TestTools.addWeapon(ship, 10, 2, 100, 10); let weapon = TestTools.addWeapon(ship, 10, 2, 100, 10);
let toggle = ship.actions.addCustom(new ToggleAction("test"));
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(0, 0)); let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(0, 0));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), 0.5); check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), 0.5, "fire");
maneuver = new Maneuver(ship, engine, Target.newFromLocation(0, 0)); maneuver = new Maneuver(ship, toggle, Target.newFromShip(ship));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), 0); check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), 0.5, "toggle on");
ship.actions.toggle(toggle, true);
maneuver = new Maneuver(ship, toggle, Target.newFromShip(ship));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -0.2, "toggle off");
maneuver = new Maneuver(ship, engine, Target.newFromLocation(0, 48));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -0.9, "move only, at full power");
maneuver = new Maneuver(ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)); maneuver = new Maneuver(ship, EndTurnAction.SINGLETON, Target.newFromShip(ship));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -1); check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -1, "end turn, at full power");
ship.setValue("power", 2); ship.setValue("power", 2);
maneuver = new Maneuver(ship, engine, Target.newFromLocation(0, 48));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -0.1, "move only, at reduced power");
maneuver = new Maneuver(ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)); maneuver = new Maneuver(ship, EndTurnAction.SINGLETON, Target.newFromShip(ship));
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -0.2); check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), -0.2, "end turn, at reduced power");
}); });
test.case("evaluates damage to enemies", check => { test.case("evaluates damage to enemies", check => {

View file

@ -59,7 +59,7 @@ module TK.SpaceTac {
* Produce a turn end. * Produce a turn end.
*/ */
static produceEndTurn(ship: Ship, battle: Battle): TacticalProducer { static produceEndTurn(ship: Ship, battle: Battle): TacticalProducer {
return isingle(new Maneuver(ship, new EndTurnAction(), Target.newFromShip(ship))); return isingle(new Maneuver(ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)));
} }
/** /**
@ -142,16 +142,16 @@ module TK.SpaceTac {
* Evaluate doing nothing, between -1 and 1 * Evaluate doing nothing, between -1 and 1
*/ */
static evaluateIdling(ship: Ship, battle: Battle, maneuver: Maneuver): number { static evaluateIdling(ship: Ship, battle: Battle, maneuver: Maneuver): number {
let power_capacity = ship.getAttribute("power_capacity") || 1;
if (maneuver.action instanceof EndTurnAction) { if (maneuver.action instanceof EndTurnAction) {
return -ship.getValue("power") / ship.getAttribute("power_capacity"); return -ship.getValue("power") / power_capacity;
} else if (maneuver.action instanceof TriggerAction || maneuver.action instanceof ToggleAction) { } else if (maneuver.action instanceof TriggerAction) {
// TODO Evaluate if drone is useful return 0.5;
// TODO Check there are "interesting" effects } else if (maneuver.action instanceof ToggleAction) {
if (maneuver.effects.length == 0) { return ship.actions.isToggled(maneuver.action) ? -0.2 : 0.5;
return -1; } else if (maneuver.action instanceof MoveAction) {
} else { return -(ship.getValue("power") - maneuver.getPowerUsage()) / power_capacity;
return 0.5;
}
} else { } else {
return 0; return 0;
} }

View file

@ -33,7 +33,7 @@ module TK.SpaceTac {
let missile = new TriggerAction("Defense Missiles", { let missile = new TriggerAction("Defense Missiles", {
effects: [new DamageEffect(25, 30)], effects: [new DamageEffect(25, 30)],
power: 3, power: 3,
range: 200, blast: 200, range: 200, blast: 180,
}, "submunitionmissile"); }, "submunitionmissile");
return [ return [

View file

@ -29,6 +29,9 @@ module TK.SpaceTac.UI {
dialogs_layer!: Phaser.Group dialogs_layer!: Phaser.Group
dialogs_opened: UIDialog[] = [] dialogs_opened: UIDialog[] = []
// Verbose debug output
readonly debug = false
// Get the size of display // Get the size of display
getWidth(): number { getWidth(): number {
return this.game.width || 1280; return this.game.width || 1280;

View file

@ -174,7 +174,7 @@ module TK.SpaceTac.UI {
return; return;
} }
if (this.actual_battle.playAI()) { if (this.actual_battle.playAI(this.debug)) {
if (this.interacting) { if (this.interacting) {
this.action_bar.setShip(new Ship()); this.action_bar.setShip(new Ship());
} }