forked from 0ad/0ad
Removes references to Testbot, replaces with JuBot.
This was SVN commit r9378.
This commit is contained in:
parent
88c44c7d73
commit
02ed11ac54
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "JuBot",
|
||||
"description": "Jubal's improved version of the 0AD TestBot.",
|
||||
"constructor": "TestBotAI"
|
||||
"constructor": "JuBotAI"
|
||||
}
|
||||
|
146
binaries/data/mods/public/simulation/ai/jubot/jubot.js
Normal file
146
binaries/data/mods/public/simulation/ai/jubot/jubot.js
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This is a primitive initial attempt at an AI player.
|
||||
* The design isn't great and maybe the whole thing should be rewritten -
|
||||
* the aim here is just to have something that basically works, and to
|
||||
* learn more about what's really needed for a decent AI design.
|
||||
*
|
||||
* The basic idea is we have a collection of independent modules
|
||||
* (EconomyManager, etc) which produce a list of plans.
|
||||
* The modules are mostly stateless - each turn they look at the current
|
||||
* world state, and produce some plans that will improve the state.
|
||||
* E.g. if there's too few worker units, they'll do a plan to train
|
||||
* another one. Plans are discarded after the current turn, if they
|
||||
* haven't been executed.
|
||||
*
|
||||
* Plans are grouped into a small number of PlanGroups, and for each
|
||||
* group we try to execute the highest-priority plans.
|
||||
* If some plan groups need more resources to execute their highest-priority
|
||||
* plan, we'll distribute any unallocated resources to that group's
|
||||
* escrow account. Eventually they'll accumulate enough to afford their plan.
|
||||
* (The purpose is to ensure resources are shared fairly between all the
|
||||
* plan groups - none of them should be starved even if they're trying to
|
||||
* execute a really expensive plan.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lots of things we should fix:
|
||||
*
|
||||
* * Find entities with no assigned role, and give them something to do
|
||||
* * Keep some units back for defence
|
||||
* * Consistent terminology (type vs template etc)
|
||||
* * ...
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function JuBotAI(settings)
|
||||
{
|
||||
// warn("Constructing JuBotAI for player "+settings.player);
|
||||
|
||||
BaseAI.call(this, settings);
|
||||
|
||||
this.turn = 0;
|
||||
|
||||
this.modules = [
|
||||
new EconomyManager(),
|
||||
new MilitaryAttackManager(),
|
||||
];
|
||||
|
||||
this.planGroups = {
|
||||
economyPersonnel: new PlanGroup(),
|
||||
economyConstruction: new PlanGroup(),
|
||||
militaryPersonnel: new PlanGroup(),
|
||||
};
|
||||
}
|
||||
|
||||
JuBotAI.prototype = new BaseAI();
|
||||
|
||||
JuBotAI.prototype.ShareResources = function(remainingResources, unaffordablePlans)
|
||||
{
|
||||
// Share our remaining resources among the plangroups that need
|
||||
// to accumulate more resources, in proportion to their priorities
|
||||
|
||||
for each (var type in remainingResources.types)
|
||||
{
|
||||
// Skip resource types where we don't have any spare
|
||||
if (remainingResources[type] <= 0)
|
||||
continue;
|
||||
|
||||
// Find the plans that require some of this resource type,
|
||||
// and the sum of their priorities
|
||||
var ps = [];
|
||||
var sumPriority = 0;
|
||||
for each (var p in unaffordablePlans)
|
||||
{
|
||||
if (p.plan.getCost()[type] > p.group.getEscrow()[type])
|
||||
{
|
||||
ps.push(p);
|
||||
sumPriority += p.priority;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid divisions-by-zero
|
||||
if (!sumPriority)
|
||||
continue;
|
||||
|
||||
// Share resources by priority, clamped to the amount the plan actually needs
|
||||
for each (var p in ps)
|
||||
{
|
||||
var amount = Math.floor(remainingResources[type] * p.priority / sumPriority);
|
||||
var max = p.plan.getCost()[type] - p.group.getEscrow()[type];
|
||||
p.group.getEscrow()[type] += Math.min(max, amount);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JuBotAI.prototype.OnUpdate = function()
|
||||
{
|
||||
// Run the update every n turns, offset depending on player ID to balance the load
|
||||
if ((this.turn + this.player) % 4 == 0)
|
||||
{
|
||||
var gameState = new GameState(this);
|
||||
|
||||
// Find the resources we have this turn that haven't already
|
||||
// been allocated to an escrow account.
|
||||
// (We need to do this before executing any plans, because those will
|
||||
// distort the escrow figures.)
|
||||
var remainingResources = gameState.getResources();
|
||||
for each (var planGroup in this.planGroups)
|
||||
remainingResources.subtract(planGroup.getEscrow());
|
||||
|
||||
Engine.ProfileStart("plan setup");
|
||||
|
||||
// Compute plans from each module
|
||||
for each (var module in this.modules)
|
||||
module.update(gameState, this.planGroups);
|
||||
|
||||
// print(uneval(this.planGroups)+"\n");
|
||||
|
||||
Engine.ProfileStop();
|
||||
Engine.ProfileStart("plan execute");
|
||||
|
||||
// Execute as many plans as possible, and keep a record of
|
||||
// which ones we can't afford yet
|
||||
var unaffordablePlans = [];
|
||||
for each (var planGroup in this.planGroups)
|
||||
{
|
||||
var plan = planGroup.executePlans(gameState);
|
||||
if (plan)
|
||||
unaffordablePlans.push({"group": planGroup, "priority": plan.priority, "plan": plan.plan});
|
||||
}
|
||||
|
||||
Engine.ProfileStop();
|
||||
|
||||
this.ShareResources(remainingResources, unaffordablePlans);
|
||||
|
||||
// print(uneval(this.planGroups)+"\n");
|
||||
|
||||
// Reset the temporary plan data
|
||||
for each (var planGroup in this.planGroups)
|
||||
planGroup.resetPlans();
|
||||
}
|
||||
if (this.turn == 0){
|
||||
this.chat("Good morning. Please prepare for annhilation. Jubal apologises for any inconvenience likely to be caused by your imminent demise.");
|
||||
}
|
||||
this.turn++;
|
||||
};
|
@ -298,7 +298,7 @@ var MilitaryAttackManager = Class({
|
||||
trainDefenderSquad: function(gameState, planGroups)
|
||||
{
|
||||
var pendingdefense = gameState.getOwnEntitiesWithRole("defenders");
|
||||
//TestBotAI.prototype.chat("Number of defenders is" + pendingdefense.length);
|
||||
//JuBotAI.prototype.chat("Number of defenders is" + pendingdefense.length);
|
||||
if (pendingdefense.length < this.defsquadmin && gameState.displayCiv() == "iber"){
|
||||
planGroups.economyPersonnel.addPlan(122,
|
||||
new UnitTrainingPlan(gameState,
|
||||
@ -310,21 +310,21 @@ var MilitaryAttackManager = Class({
|
||||
new UnitTrainingPlan(gameState,
|
||||
"units/{civ}_infantry_spearman_b", 3, { "role": "defenders" })
|
||||
);
|
||||
//TestBotAI.prototype.chat("Training defenders");
|
||||
//JuBotAI.prototype.chat("Training defenders");
|
||||
}
|
||||
else if (pendingdefense.length < this.defsquad && gameState.displayCiv() == "iber"){
|
||||
planGroups.economyPersonnel.addPlan(110,
|
||||
new UnitTrainingPlan(gameState,
|
||||
"units/{civ}_infantry_swordsman_b", 3, { "role": "defenders" })
|
||||
);
|
||||
//TestBotAI.prototype.chat("Training defenders");
|
||||
//JuBotAI.prototype.chat("Training defenders");
|
||||
}
|
||||
else if (pendingdefense.length < this.defsquad){
|
||||
planGroups.economyPersonnel.addPlan(110,
|
||||
new UnitTrainingPlan(gameState,
|
||||
"units/{civ}_infantry_spearman_b", 3, { "role": "defenders" })
|
||||
);
|
||||
//TestBotAI.prototype.chat("Training defenders");
|
||||
//JuBotAI.prototype.chat("Training defenders");
|
||||
}
|
||||
},
|
||||
|
||||
@ -648,25 +648,25 @@ var MilitaryAttackManager = Class({
|
||||
if (whatnext > 0.85){
|
||||
this.killstrat = 0;
|
||||
// Regular "train a few guys and go kill stuff" type attack.
|
||||
//TestBotAI.prototype.chat("Regular attack (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Regular attack (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
}
|
||||
else if (whatnext > 0.55) {
|
||||
this.killstrat = 2;
|
||||
//TestBotAI.prototype.chat("Cavalry raid (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Cavalry raid (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
// Cavalry raid
|
||||
}
|
||||
else if (whatnext > 0.2) {
|
||||
this.killstrat = 3;
|
||||
//TestBotAI.prototype.chat("3 pronged assault (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("3 pronged assault (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
// 3 prong
|
||||
}
|
||||
else {
|
||||
this.killstrat = 1;
|
||||
//TestBotAI.prototype.chat("Full assault (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Full assault (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
//Full Assault!
|
||||
}
|
||||
}
|
||||
@ -732,25 +732,25 @@ var MilitaryAttackManager = Class({
|
||||
if (whatnext > 0.8){
|
||||
this.killstrat = 0;
|
||||
// Regular "train a few guys and go kill stuff" type attack.
|
||||
//TestBotAI.prototype.chat("Regular attack (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Regular attack (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
}
|
||||
else if (whatnext > 0.5) {
|
||||
this.killstrat = 2;
|
||||
//TestBotAI.prototype.chat("Cavalry raid (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Cavalry raid (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
// Cavalry raid
|
||||
}
|
||||
else if (whatnext > 0.3) {
|
||||
this.killstrat = 3;
|
||||
//TestBotAI.prototype.chat("3 pronged assault (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("3 pronged assault (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
// 3 prong
|
||||
}
|
||||
else {
|
||||
this.killstrat = 1;
|
||||
//TestBotAI.prototype.chat("Full assault (" + gameState.displayCiv() + ")");
|
||||
//TestBotAI.prototype.chat(whatnext);
|
||||
//JuBotAI.prototype.chat("Full assault (" + gameState.displayCiv() + ")");
|
||||
//JuBotAI.prototype.chat(whatnext);
|
||||
//Full Assault!
|
||||
}
|
||||
}
|
||||
|
@ -191,14 +191,14 @@ var BuildingConstructionPlan = Class({
|
||||
{
|
||||
var v = friendlyTiles[i];
|
||||
var foe = enemyTiles[i];
|
||||
//TestBotAI.prototype.chat(v);
|
||||
//TestBotAI.prototype.chat(i);
|
||||
//TestBotAI.prototype.chat(foe);
|
||||
//JuBotAI.prototype.chat(v);
|
||||
//JuBotAI.prototype.chat(i);
|
||||
//JuBotAI.prototype.chat(foe);
|
||||
if (v >= bestVal)
|
||||
{
|
||||
bestVal = v;
|
||||
bestIdx = i;
|
||||
//TestBotAI.prototype.chat("BestVal is " + bestVal + ", and bestIdx is " + bestIdx + ".");
|
||||
//JuBotAI.prototype.chat("BestVal is " + bestVal + ", and bestIdx is " + bestIdx + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user