1
0
Fork 0

Refactored BullyMove, using the new AIManeuver

For future AI helpers
This commit is contained in:
Michaël Lemaire 2015-03-12 01:00:00 +01:00
parent 8b256aa95c
commit 5cffb1680c
3 changed files with 81 additions and 54 deletions

View file

@ -0,0 +1,27 @@
module SpaceTac.Game.AI {
"use strict";
// Ship maneuver for an artifical intelligence
// A maneuver is like a human player action, choosing an equipment and using it
export class AIManeuver {
// Concerned ship
ship: Ship;
// Equipment to use
equipment: Equipment;
// Target for the action;
target: Target;
constructor(ship: Ship, equipment: Equipment, target: Target) {
this.ship = ship;
this.equipment = equipment;
this.target = target;
}
// Apply the maneuver in current battle
apply(): void {
this.equipment.action.apply(this.ship.getBattle(), this.ship, this.target);
}
}
}

View file

@ -2,23 +2,23 @@
module SpaceTac.Game.AI {
"use strict";
export class BullyMove {
// Position to move to, before firing
move_to: Target;
// Combination of a move action and a fire action
export class BullyManeuver {
// Move action to position the ship before firing
move: AIManeuver;
// Engine used to move
engine: Equipment;
// Fire action
fire: AIManeuver;
// Weapon to use
weapon: Equipment;
// Ship to target
target: Ship;
constructor(move: AIManeuver = null, fire: AIManeuver = null) {
this.move = move;
this.fire = fire;
}
// Get a sorting score, by distance to another point
// Nearest means higher score
getScoreByDistance(point: Target): number {
return -point.getDistanceTo(Target.newFromShip(this.target));
return -point.getDistanceTo(this.fire.target);
}
}
@ -35,13 +35,13 @@ module SpaceTac.Game.AI {
protected initWork(): void {
this.addWorkItem(() => {
var moves = this.listAllMoves();
var maneuvers = this.listAllManeuvers();
if (moves.length > 0) {
var move = this.pickMove(moves);
this.applyMove(move);
if (maneuvers.length > 0) {
var maneuver = this.pickManeuver(maneuvers);
this.applyManeuver(maneuver);
// Try to make another move
// Try to make another maneuver
this.initWork();
}
});
@ -65,18 +65,18 @@ module SpaceTac.Game.AI {
return this.ship.listEquipment(SlotType.Weapon);
}
// List all available "moves" for the playing ship
listAllMoves(): BullyMove[] {
var result: BullyMove[] = [];
// List all available maneuvers for the playing ship
listAllManeuvers(): BullyManeuver[] {
var result: BullyManeuver[] = [];
var enemies = this.listAllEnemies();
var weapons = this.listAllWeapons();
enemies.forEach((ship: Ship) => {
weapons.forEach((weapon: Equipment) => {
var move = this.checkBullyMove(ship, weapon);
if (move) {
result.push(move);
var maneuver = this.checkBullyManeuver(ship, weapon);
if (maneuver) {
result.push(maneuver);
}
});
});
@ -85,8 +85,8 @@ module SpaceTac.Game.AI {
}
// Check if a weapon can be used against an enemy
// Returns the BullyMove, or null if impossible to fire
checkBullyMove(enemy: Ship, weapon: Equipment): BullyMove {
// Returns the BullyManeuver, or null if impossible to fire
checkBullyManeuver(enemy: Ship, weapon: Equipment): BullyManeuver {
// Check if enemy in range
var target = Target.newFromShip(enemy);
var distance = target.getDistanceTo(Target.newFromShip(this.ship));
@ -121,40 +121,40 @@ module SpaceTac.Game.AI {
// Not enough AP to fire
return null;
} else {
var result = new BullyMove();
result.move_to = move;
result.engine = engine;
result.target = enemy;
result.weapon = weapon;
var result = new BullyManeuver();
if (move) {
result.move = new AIManeuver(this.ship, engine, move);
}
result.fire = new AIManeuver(this.ship, weapon, target);
return result;
}
}
// Pick a move from a list of available ones
// Pick a maneuver from a list of available ones
// By default, it chooses the nearest enemy
pickMove(available: BullyMove[]): BullyMove {
pickManeuver(available: BullyManeuver[]): BullyManeuver {
if (available.length === 0) {
return null;
}
// Sort by descending score
available.sort((m1: BullyMove, m2: BullyMove): number => {
available.sort((m1: BullyManeuver, m2: BullyManeuver): number => {
var point = Target.newFromShip(this.ship);
return m1.getScoreByDistance(point) < m2.getScoreByDistance(point) ? 1 : -1;
});
return available[0];
}
// Effectively apply the chosen move
applyMove(move: BullyMove): void {
if (move.move_to) {
// Effectively apply the chosen maneuver
applyManeuver(maneuver: BullyManeuver): void {
if (maneuver.move) {
this.addWorkItem(() => {
move.engine.action.apply(this.battle, this.ship, move.move_to);
maneuver.move.apply();
}, 500);
}
this.addWorkItem(() => {
move.weapon.action.apply(this.fleet.battle, this.ship, Target.newFromShip(move.target));
maneuver.fire.apply();
}, 1500);
this.addWorkItem(null, 1500);

View file

@ -63,10 +63,10 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 3;
enemy.arena_y = 0;
var result = ai.checkBullyMove(enemy, weapon);
expect(result.move_to).toBeNull();
expect(result.target).toBe(enemy);
expect(result.weapon).toBe(weapon);
var result = ai.checkBullyManeuver(enemy, weapon);
expect(result.move).toBeNull();
expect(result.fire.target).toEqual(Target.newFromShip(enemy));
expect(result.fire.equipment).toBe(weapon);
// enemy out of range, but moving can bring it in range
ship.ap_current.set(8);
@ -74,10 +74,10 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 6;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
expect(result.move_to).toEqual(Target.newFromLocation(3, 0));
expect(result.target).toBe(enemy);
expect(result.weapon).toBe(weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result.move.target).toEqual(Target.newFromLocation(3, 0));
expect(result.fire.target).toEqual(Target.newFromShip(enemy));
expect(result.fire.equipment).toBe(weapon);
// enemy out of range, but moving can bring it in range, except for the safety margin
ai.move_margin = 0.1;
@ -86,7 +86,7 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 6;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result).toBeNull();
ai.move_margin = 0;
@ -96,7 +96,7 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 30;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result).toBeNull();
// enemy in range but not enough AP to fire
@ -105,7 +105,7 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 3;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result).toBeNull();
// can move in range of enemy, but not enough AP to fire
@ -114,7 +114,7 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 6;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result).toBeNull();
// no engine, can't move
@ -124,7 +124,7 @@ module SpaceTac.Game.AI.Specs {
ship.arena_y = 0;
enemy.arena_x = 6;
enemy.arena_y = 0;
result = ai.checkBullyMove(enemy, weapon);
result = ai.checkBullyManeuver(enemy, weapon);
expect(result).toBeNull();
});
@ -144,7 +144,7 @@ module SpaceTac.Game.AI.Specs {
var ai = new BullyAI(ship1.fleet);
ai.ship = ship1;
var result = ai.listAllMoves();
var result = ai.listAllManeuvers();
expect(result.length).toBe(0);
var weapon1 = new Equipment(SlotType.Weapon);
@ -159,7 +159,7 @@ module SpaceTac.Game.AI.Specs {
ai.ship.ap_current.setMaximal(10);
ai.ship.ap_current.set(8);
result = ai.listAllMoves();
result = ai.listAllManeuvers();
expect(result.length).toBe(3);
});
@ -196,12 +196,12 @@ module SpaceTac.Game.AI.Specs {
ship2.hull.set(15);
ship2.shield.set(10);
var move = ai.checkBullyMove(ship2, weapon);
var move = ai.checkBullyManeuver(ship2, weapon);
expect(move).not.toBeNull();
battle.playing_ship = ai.ship;
battle.log.clear();
ai.applyMove(move);
ai.applyManeuver(move);
expect(battle.log.events.length).toBe(7);