Jump to content

Search the Community

Showing results for tags 'Language'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome
    • Announcements / News
    • Introductions & Off-Topic Discussion
    • Help & Feedback
  • 0 A.D.
    • General Discussion
    • Gameplay Discussion
    • Game Development & Technical Discussion
    • Art Development
    • Game Modification
    • Project Governance
    • Testing

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests


First Name


Last Name


Skype ID

Found 1 result

  1. I think, I'm getting really close to finalize the domain specific lanaguage (DSL) used in Hannibal's groups and want to ask for some feedback, because this what this bot is all about. The idea is only groups talk to the engine. Some unit should gather a field, there is a group for that. Want to build houses - launch a builder group. Need resources, give the supplier group some entity ids of trees, mines or whales. Groups are the building blocks of the behavior of Hannibal, everything else is low level or services. If something is going wrong a group is probably missing or not properly programmed. Actually you can think of Hannibal as a bot framework with groups as the user interface. Let's say you want an anarchy bot, but don't want to deal with map analysis or the 0AD bot API, all you need to do is fork Hannibal and define new groups with new behavior. How does it work? Well, technically the DSL works by chaining JavaScript methods. Here is a trivial example: array .sort() .filter(item => item > 5) .forEach(/* do stuff */);That works because both sort() and filter() return an array. Fortunately JavaScript's automatic semicolon inserter doesn't kick in. Hannibal's DSL looks similar, but it adds another level. Let's start with the most important group, the base of any village, the grain pickers. I'm going to challenge your imagination, but give it a try: Assume YOU are that little female unit contracted to do nothing but gathering food. Still here? Ok, what is your job description? Basically: Stay alive and gather food. What are your options to stay alive? Let's say, if you got hit seriously flee and search for shelter. If the attacker is gone try to heal. And to gather? Well, that's simple: Gather food and carry it to a dropsite. OK, may be I should order a field if there is none. And even a dropsite, if all others are to far away. You see a gather-food-unit only needs a very simple mind. That's the concept of Hannibal: Give units a simple job description so they never go idle and group similar jobs together. From there complex bot behavior will follow/emerge. I now hear objections: You can't win a game with female food gatherer only! That's right. And I must say I haven't seen attacking units so far with this concept. So here is what I'm going to implement: The job description of a military is actually close to the above, stay alive and do damage. If you are successful move forward otherwise move back to a more secure place like a fully garrisoned fortress of a tower triangle. Hannibal's job is to provide this information, the attacking unit's job is to use it wisely. Can you now imagine a horde of cavalry keeping the right distance avoiding suicide attacks, never going idle and heal if exhausted? Back to the DSL, a group's scripts are triggered by events only. There is a one time event when the group launches, another when Hannibal assigns an asset (read entity, e.g. unit, field, house, dropsite), when the group got attacked, an asset got destroyed or a timed event. Here is the list: launchassignattackdestroyintervalObviously launch is kinda initialization. The group declares what assets are needed and presumably orders the first one. This is the grain pickers launch script: function launch (w) { w.units = ["exclusive", "food.grain GATHEREDBY WITH costs.metal = 0, costs.stone = 0"]; w.field = ["exclusive", "food.grain PROVIDEDBY"]; w.dropsite = ["shared", "food ACCEPTEDBY"]; w.units.size = 5; w.field.size = 1; w.dropsite.size = 1; w.nounify("units", "field", "dropsite"); w.dropsite.on.request(); }The assets are defined using the internal query language, they all need a size and then the definition gets 'nounified'. All left is requesting a dropsite which sooner or later triggers the assign script. The DSL has kind of a grammar consisting of sentences, nouns, subjects, objects, verbs, attributes and modifiers. w.dropsite.on.request();Above is a sentence. JS experts see property chaining works too. 'w' is the world the language is defined in. Each group acts in its own world. 'w' is always the first parameter in script call. Whenever something is nounified it is available either as subject or object. Here is what in this sentence happens: w // each sentence starts with the world .dropsite // dropsite is picked as current object .on // the current object is picked as subject .request() // the current subject fires an action, amount defaults here to 1; // sentence doneSo, in plain English it means: Dear Hannibal, I desperately need a dropsite for food. As most maps have a civic centre as start up building this command is actually a no-brainer. Probably already the next tick calls assign. If Hannibal can't provide a dropsite the map is probably un-playabale, because of lack of resources or whatever. Now things get a bit more complicated, the group may get assigned a dropsite, a field or an unit, so a filter is needed. function assign (w, item) { w.objectify("item", item); // got dropsite, requests unit, exits w.dropsite.on .member(w.item) .units.do.request() .exit ; ...Here dropsite is first selected as object, then as subject and then a member check follows. If that check fails all the rest of the sentence is ignored. In case of success units is selected as subject (do) and a unit is requested. 'exit' means all the rest of the whole script is ignored, think of 'return' in a JS function. It should be clear what comes next - a sentence for a new unit: // keep requesting units until size is metw.units.on .member(w.item) .lt(w.units.count, w.units.size) .request();'lt' - less than - compares 'size' as defined in launch with the actual amount of units. You miss the field? // the first unit requests field, exitsw.units.on .member(w.item) .match(w.units.count, 1) .match(w.field.count, 0) .field.do.request() .exit;Still the units do not gather, the script makes sure through the order of requesting there is a dropsite and units and a field. // got the field foundation, all units repair, exitsw.field.on .member(w.item) .match(w.item.foundation) .units.do.repair(w.field) .exit;Here is another modifier 'match' just checking whether a attribute is true. There are two more sentences, the whole thing is currently here: https://github.com/agentx-cgn/Hannibal/blob/master/source/simulation/ai/hannibal/grp-harvester.js#L61 For sure this is just the beginning, beside grain-picker, miners, lumber jacks, builders more is needed to support a village or even launch an attack. For example there will be a scout group having an object called scanner which scans the terrain and Hannibal transforms this information into a potential field needed to tell attackers which region is safe or not, thus giving the direction of forward or back. If at this point you think - wait stop - I have some sentences in mind for another group, you're welcome. Please, let me know or even better paste them below. This is the purpose of Hannibal, it let you try out in a simple way how an AI can work. All you need to do is put yourself into the position of an 0AD unit and determine your options. That's it. I nearly spend a year getting this idea running and actually see now units building villages, powered by groups scripts. I hope, I could understandably layout the potential. Now, my target is to release a sandbox (no attacks) version within weeks, showcasing this concept. Follow this topic for breathtaking videos PS. Developers may have all alarm clocks ringing because of performance, but keep in mind the scripts are fired on events only, there are not that many groups needed and so far none took longer than a millisecond. PPS: Ok, another one. A unit of your group got killed, what's the sentence? function destroy (w, item) { w.objectify("item", item); // lost unit, request another w.units .member(w.item) .request() ;}
×
×
  • Create New...