Fixed several AI related problems
This commit is contained in:
parent
ea8771fc75
commit
851c59bac1
1
TODO.md
1
TODO.md
|
@ -69,7 +69,6 @@ Ships models and actions
|
|||
Artificial Intelligence
|
||||
-----------------------
|
||||
|
||||
* Fix tendency to use moves for nothing
|
||||
* Produce interesting "angle" areas
|
||||
* Evaluate active effects
|
||||
* Account for luck
|
||||
|
|
|
@ -27,7 +27,7 @@ module TK.SpaceTac {
|
|||
* Process AI in a webworker if possible, else do the work in the render thread
|
||||
*/
|
||||
async processAuto(feedback: AIFeedback): Promise<void> {
|
||||
if ((<any>window).Worker) {
|
||||
if (!this.debug && (<any>window).Worker) {
|
||||
await this.processInWorker(feedback);
|
||||
} else {
|
||||
await this.processHere(feedback);
|
||||
|
|
|
@ -41,6 +41,13 @@ module TK.SpaceTac {
|
|||
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
|
||||
*/
|
||||
|
@ -87,7 +94,9 @@ module TK.SpaceTac {
|
|||
for (let i = 0; i < parts.length; i++) {
|
||||
let part = parts[i];
|
||||
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 {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ module TK.SpaceTac {
|
|||
[maneuver, producer] = producer();
|
||||
}
|
||||
|
||||
if (maneuver) {
|
||||
if (maneuver && maneuver.isPossible()) {
|
||||
if (producer) {
|
||||
this.producers.push(producer);
|
||||
}
|
||||
|
@ -113,12 +113,12 @@ module TK.SpaceTac {
|
|||
|
||||
let evaluators: EvaluatorHelper[] = [
|
||||
scaled(TacticalAIHelpers.evaluateTurnCost, 1),
|
||||
scaled(TacticalAIHelpers.evaluateOverheat, 10),
|
||||
scaled(TacticalAIHelpers.evaluateEnemyHealth, 500),
|
||||
scaled(TacticalAIHelpers.evaluateAllyHealth, 800),
|
||||
scaled(TacticalAIHelpers.evaluateClustering, 3),
|
||||
scaled(TacticalAIHelpers.evaluatePosition, 1),
|
||||
scaled(TacticalAIHelpers.evaluateIdling, 1),
|
||||
scaled(TacticalAIHelpers.evaluateOverheat, 3),
|
||||
scaled(TacticalAIHelpers.evaluateEnemyHealth, 5),
|
||||
scaled(TacticalAIHelpers.evaluateAllyHealth, 20),
|
||||
scaled(TacticalAIHelpers.evaluateClustering, 4),
|
||||
scaled(TacticalAIHelpers.evaluatePosition, 0.5),
|
||||
scaled(TacticalAIHelpers.evaluateIdling, 2),
|
||||
]
|
||||
|
||||
let battle = nn(this.ship.getBattle());
|
||||
|
|
|
@ -120,20 +120,31 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipModel(ship, 100, 0, 10);
|
||||
let engine = TestTools.addEngine(ship, 50);
|
||||
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));
|
||||
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));
|
||||
check.equals(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver), 0);
|
||||
maneuver = new Maneuver(ship, toggle, Target.newFromShip(ship));
|
||||
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));
|
||||
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);
|
||||
|
||||
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));
|
||||
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 => {
|
||||
|
|
|
@ -59,7 +59,7 @@ module TK.SpaceTac {
|
|||
* Produce a turn end.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
static evaluateIdling(ship: Ship, battle: Battle, maneuver: Maneuver): number {
|
||||
let power_capacity = ship.getAttribute("power_capacity") || 1;
|
||||
|
||||
if (maneuver.action instanceof EndTurnAction) {
|
||||
return -ship.getValue("power") / ship.getAttribute("power_capacity");
|
||||
} else if (maneuver.action instanceof TriggerAction || maneuver.action instanceof ToggleAction) {
|
||||
// TODO Evaluate if drone is useful
|
||||
// TODO Check there are "interesting" effects
|
||||
if (maneuver.effects.length == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0.5;
|
||||
}
|
||||
return -ship.getValue("power") / power_capacity;
|
||||
} else if (maneuver.action instanceof TriggerAction) {
|
||||
return 0.5;
|
||||
} else if (maneuver.action instanceof ToggleAction) {
|
||||
return ship.actions.isToggled(maneuver.action) ? -0.2 : 0.5;
|
||||
} else if (maneuver.action instanceof MoveAction) {
|
||||
return -(ship.getValue("power") - maneuver.getPowerUsage()) / power_capacity;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ module TK.SpaceTac {
|
|||
let missile = new TriggerAction("Defense Missiles", {
|
||||
effects: [new DamageEffect(25, 30)],
|
||||
power: 3,
|
||||
range: 200, blast: 200,
|
||||
range: 200, blast: 180,
|
||||
}, "submunitionmissile");
|
||||
|
||||
return [
|
||||
|
|
|
@ -29,6 +29,9 @@ module TK.SpaceTac.UI {
|
|||
dialogs_layer!: Phaser.Group
|
||||
dialogs_opened: UIDialog[] = []
|
||||
|
||||
// Verbose debug output
|
||||
readonly debug = false
|
||||
|
||||
// Get the size of display
|
||||
getWidth(): number {
|
||||
return this.game.width || 1280;
|
||||
|
|
|
@ -174,7 +174,7 @@ module TK.SpaceTac.UI {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.actual_battle.playAI()) {
|
||||
if (this.actual_battle.playAI(this.debug)) {
|
||||
if (this.interacting) {
|
||||
this.action_bar.setShip(new Ship());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue