Jump to content

A New A.i.?


Recommended Posts

Hey,

I'm in a group of second year A.I. students from Amsterdam, and we would like to write an A.I. for 0 A.D.

We would like to test this A.I. against JuBot, to see if it performs better. I already saw that there is an option in Atlas to run and speed up the game (which would come in handy with an A.I. vs A.I. battle), but when I press play, the other player doesn't use an A.I.

Is it possible in some way to let 2 A.I.'s play against each other? We could maybe also try to make a three player map and put the human player on top of a cliff or something, but that wouldn't be the neatest way of going about this.

Also, is there a function somewhere to actually attack an entity? Because I didn't see one in the entity in entity.js.

Edited by AI-Amsterdam
Link to comment
Share on other sites

  • Replies 70
  • Created
  • Last Reply

Top Posters In This Topic

here is an answer to your first question :

You can already run the game like "pyrogenesis -quickstart -autostart=Oasis -autostart-ai=1:testbot -autostart-ai=2:testbot" to set up AIvAI, then use the 'time warp' mode in the game or do Engine.SetSimRate(10) etc in the console to speed it up. (It should give the same outcome each time since it's deterministic - I guess at some point I should let the random seed be changed.)

for the second, you will have to add a new function to entity.js and entitycollection.js, like the move() one but with "attack" instead of "walk". If you don't want to attack a specific entity, the move() function should be fine (Jubot uses it).

Link to comment
Share on other sites

Hey, I tried the command you quoted, but got this error message:

Paths.cpp(82): Function call failed: return value was -110301 (Error during IO)
Function call failed: return value was -110301 (Error during IO)
Location: Paths.cpp:82 (Root)

Call stack:

(0x74717a) pyrogenesis() [0x74717a]
(0x6fe310) pyrogenesis() [0x6fe310]
(0x6fef28) pyrogenesis() [0x6fef28]
(0x6fe802) pyrogenesis() [0x6fe802]
(0x544332) pyrogenesis() [0x544332]
(0x545d3b) pyrogenesis() [0x545d3b]
(0x54d2ff) pyrogenesis() [0x54d2ff]
(0x54fa9f) pyrogenesis() [0x54fa9f]
(0x41398d) pyrogenesis() [0x41398d]
(0x415133) pyrogenesis() [0x415133]
(0x7fa3c6ba0eff) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff) [0x7fa3c6ba0eff]
(0x411a79) pyrogenesis() [0x411a79]

errno = 0 (?)
OS error = ?


(C)ontinue, (S)uppress, (B)reak, Launch (D)ebugger, or (E)xit?

So were there any other things I had to do? I just ran it in home/user, should it be some other directory?

Link to comment
Share on other sites

That error indicates we're not finding the path to the executable; even argv[0] isn't usable.

The game still runs because there's a second mechanism (XDG) to find the paths to the data files, but it'd be nice to find out what's going wrong.

Would you be so kind as to trace into sys_ExecutablePathname, and also print argv[0] in main?

Link to comment
Share on other sites

Thanks for all your replies,

@Badmanblacksad: The 2 AIvsAI works like a charm :)

However ,we are currently editing/creating an AI in the public.zip, which seems to work.

@janwas: I would be happy to help you but I don't know exactly how, if you could provide instructions I'll be happy to try.

We've got a basic bot at the moment, but we still seem to have some troubles regarding the following;

Is there a way to make a unit garrison into a building? I have noticed JuBot doesn't garrison his towers.

For that matter, how does one make direct calls to the engine, if possible?

Is it possible to read out the range of entities? I've seen the range overlay, but cant find a reference in the code for the life of me.

@Badmanblacksad: Could you perhaps share how you would make such a function with "attack" ? I can't seem to find a proper way to do so.

Thanks again, your replies are much appreciated,

Team AI-Amsterdam

Link to comment
Share on other sites

@janwas: I would be happy to help you but I don't know exactly how, if you could provide instructions I'll be happy to try.

Thanks! It'd be good to add as the first line of main():

debug_printf(L"%hs\n", argv[0]);

As to sys_ExecutablePathname, that's a bit more complicated. Please apply the attached patch

(mutatis mutandis, I can't compile it here) to linux.cpp and post the resulting console output (the first line, and the one starting with "sep").

Unfortunately I can't help with the other questions.

debug_sep.patch

Link to comment
Share on other sites

@Badmanblacksad: The 2 AIvsAI works like a charm :)

great

Is there a way to make a unit garrison into a building? I have noticed JuBot doesn't garrison his towers.

For that matter, how does one make direct calls to the engine, if possible?

@Badmanblacksad: Could you perhaps share how you would make such a function with "attack" ? I can't seem to find a proper way to do so.

I bet you didn't see this file ;)

did you try to do something along those lines ?

in entitycollection.js


EntityCollection.prototype.attack = function(target)
{
Engine.PostCommand({"type": "attack", "entities": this.toIdArray(), "target": target, "queued": false});
return this;
};

in entity.js


attack: function(target) {
Engine.PostCommand({"type": "attack", "entities": [this.id()], "target": target, "queued": false});
return this;
},

and then the same with "garrison"

Is it possible to read out the range of entities? I've seen the range overlay, but cant find a reference in the code for the life of me.


var cmpRanged = Engine.QueryInterface(entity, IID_Attack);
if (!cmpRanged)
return;
var range = cmpRanged.GetRange(type);

hope thats help. never coded anything related to bots.

Link to comment
Share on other sites

thanks again for the replies,

@badmadblacksad: the attack function works now, thanks a lot! We will try garrisoning in a few moments.

@janwas: about the debugging, I'm not sure where the game code is located (I know, it's stupid, but I just work from a checkout of the source, and let someone else test it on windows).

I just managed to locate the pyrogenesis executable, but that's it.

Is there some way to easily add the line

debug_printf(L"%hs\n", argv[0]);

to the main without having to build the game?

I presume it's the file in trunk/source/main.cpp, right? (a lot of other main files popped up too)

I also tried to apply the patch, but I got this:


patch <./Downloads/debug_sep.patch
(Stripping trailing CRs from patch.)
patching file linux.cpp
Hunk #1 FAILED at 36.
Hunk #2 FAILED at 45.
Hunk #3 FAILED at 54.

also... This API shows that there is a function isUnderAttack for buildings, but it turns out that this isn't implemented. Do you have any suggestions on how to implement this function.

thanks!

the team.

Link to comment
Share on other sites

If you're running the game like "pyrogenesis ...", then try "./pyrogenesis ..." instead. (The first version has to search through $PATH to find the executable, and the game doesn't bother searching $PATH when trying to find itself so it fails.)

This API shows that there is a function isUnderAttack for buildings, but it turns out that this isn't implemented.

That API design is ancient and was never implemented - the only documentation that's not wrong is this but it doesn't say very much so it's probably not too useful. But the "events" array should contain events with the name "Attacked" whenever a unit is attacked, so it should be possible somehow to detect and respond to those events (maybe with some extra code in common-api/base.js).

Link to comment
Share on other sites

Sounds like you'll be going a lot faster than me, I'm still part-stalled over exams. Can you share some results with me of your work? Also, remember that JuBot is not fully fledged by any means; it should not be hard to write a more developed bot, particularly if you've got experience in that area.

Good luck! :)

Link to comment
Share on other sites

@Ykkrosh Thanks! Too bad the API is outdated/not complete...

@Jubalbarca We're doing this as a 4 week project for our study and we're halfway now. We're using a behaviour tree so our A.I. is structured differently from yours. We'll definitely share the results when we're finished :)

Link to comment
Share on other sites

@gudo: We might, but there is also a little thing called summer break ;-). We will try to document our code and make everything as clear as possible, so other people (maybe even you?) can continue our work.

We have another question: For several things we would like to check how many entities exist and are queued with a certain class. For example, we would like to see how many "Melee" units we have with the role "defenders".

We already tried to write something like this (borrowing some code from JuBot's gamestate):


countEntitiesAndQueuedWithClass: function(theClass)
{
var count = 0;
this.getOwnEntities().forEach(function(ent) {

if (ent.hasClass(theClass))
++count;

var queue = ent.trainingQueue();
if (queue)
{
queue.forEach(function(item) {
var x = this.getTemplate(item.template).hasClass(theClass);
RootBot.prototype.chat(x);
if (x)
count += item.count;
});
}
});
return count;

but that doesn't seem to work. I'm also trying to write a function that takes a role argument too, to solve the query above, by doing this, but that might be wrong for the smae reasons:


countEntitiesAndQueued: function(theClass, role)
{
var count = 0;
this.getOwnEntities().forEach(function(ent) {

if (ent.hasClass(theClass) && ent.getMetadata("role") == role)
++count;

var queue = ent.trainingQueue();
if (queue)
{
queue.forEach(function(item) {
var x = this.getTemplate(item.template).hasClass(theClass);
RootBot.prototype.chat(x);
if (x && item.metadata && item.metadata.role == role)
count += item.count;
});
}
});
return count;
},

Oh, and what are the commands Engine.profileStart("some stuff") and Engine.profileStop() doing

Again, your help would be much appreciated ;-)

Edited by AI-Amsterdam
Link to comment
Share on other sites


var cmpRanged = Engine.QueryInterface(entity, IID_Attack);
if (!cmpRanged)
return;
var range = cmpRanged.GetRange(type);

I wasn't able to read if a unit is under attack. So I tried to define being under attack as being within the range of an enemy unit. To find the range of an enemy I tried to use the code given above, but I get an error: IID_Attack is not defined. When I searched through different codes I found that no IID_foo was ever instantiated. What's going on here?

thanks in advance,

team-ai

Link to comment
Share on other sites

The biggest weakness of the current bot is:

1. It attacks buildings and doesn't switch to units, so if it's attacking a house you can just use archers to kill it's units and they wont move to attack the units, they just carry on attacking the house.

2. It's way to slow to attack, it never really does much offensive.

Link to comment
Share on other sites

1. It attacks buildings and doesn't switch to units, so if it's attacking a house you can just use archers to kill it's units and they wont move to attack the units, they just carry on attacking the house.

I think this is more an issue with the current unit AI in general, as I find this annoying when your own units do this too. You send an army in to the enemy base, and while sending a second one, your first one has been wiped out by one or two infantrymen, because your units were attacking a building.

Link to comment
Share on other sites

Oh, and what are the commands Engine.profileStart("some stuff") and Engine.profileStop() doing

Again, your help would be much appreciated ;-)

Those would be profiling hooks, basically timers that give some idea of the performance in that part of the code. You can access profiling info with F11 or save it with Shift-F11 I believe.

I wasn't able to read if a unit is under attack. So I tried to define being under attack as being within the range of an enemy unit. To find the range of an enemy I tried to use the code given above, but I get an error: IID_Attack is not defined. When I searched through different codes I found that no IID_foo was ever instantiated. What's going on here?

I'm pretty sure the AI isn't allowed to directly access simulation components, which is why those aren't defined. Also the API which the AIs have access to is not nearly complete.

If you look at simulation\components\AIProxy.js, there is an OnAttacked event that doesn't appear to be used by the AIs (it may not do anything in fact, but could be a starting point). Also AIProxy.prototype.GetFullRepresentation is worth investigating. Anything you figure out here should either go in the AI proxy or base-AI module so all AIs can use it, and it will be no doubt very appreciated.

Edit: I see how those events work. Look at simulation\components\Attack.js in the CauseDamage method. It sends out an MT_Attacked message, which might well trigger the above OnAttacked event in the relevant AI.

Link to comment
Share on other sites

Thanks, we will try that.

Meanwhile, we've been working on a module to attack the enemy.

What we would like to know, is the following.

Is there a way to see which unit has a bonus against which? For example, the infantry spearman has a bonus against cavalry units.

Is there a function that does this, for example:


vs(templateA, templateB){
if(templateA beats templateB)
return 1;
if(templateB beats templateA)
return -1;
return 0;
}

vs("units/{civ}_infantry_spearman_b", "units/{civ}_cavalry_swordsman_b") //returns 1

What we would like to do is give entities one of our soldiers is good against a higher priority to be attacked.

Link to comment
Share on other sites

I'm pretty sure the AI isn't allowed to directly access simulation components, which is why those aren't defined.

Indeed - they're not even running in the same JS runtime or thread. Since the attack range is a constant that's determined by the entity template files, it should be possible to modify EntityTemplate in entity.js to return this._template.Attack.Melee.Range and/or this._template.Attack.Ranged.MaxRange, which will hopefully give the desired data without interacting with the entities directly.

Is there a way to see which unit has a bonus against which? For example, the infantry spearman has a bonus against cavalry units.

There aren't any attack bonuses implemented yet - it just depends on the hack/crush/pierce attack and armour values: damage = max(1, max(0, attack.hack - armour.hack) + max(0, attack.crush - armour.crush) + max(0, attack.pierce - armour.pierce))

Link to comment
Share on other sites

Guess you will have to counter the units countering your units then. :P

But your AI will do the same. So I will then have to counter the units countering my counter units countering its counter units. :(

Are you preparing your AI already for Alpha 6?

EDIT: I have written this reply before you have written your one. Cool.

Edited by Rasunadon
Link to comment
Share on other sites

Well Rasunadon, as you can see they have not implemented a rock-paper-scissors algorithm, so AI world domination is still a few releases away :P .

We have another question. Garrisoning works like a charm, but we can't seem to find the command to ungarrison units. we tried something like


ungarrison: function() {
Engine.PostCommand({"type": "Ungarrison", "entities": [this.id()], "target": null, "queued": false});
return this;
},

but we got a message that the engine does not recognise the command.


Ignoring unrecognized command type 'Ungarrison'

We found a function called ungarrison in UnitAI, but this doesn't seem to work with the engine command.

Please help :)

Edited by AI-Amsterdam
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share


×
×
  • Create New...