Jump to content


Community Members
  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by agentx

  1. Don't know, haven't investigated the GUI system yet. But in principle, I'd say yes, it is only a few numbers per second, thus only a few pixel to draw. But you are the master of mod! In any case, I think it'd be worth the effort, especially new comers appreciate to know where exactly the opponent is performing better. On the other hand, having live stats from your enemy is close to cheating, right? At second thought, at least on Linux it should be possible to live capture Numeris' output and draw it onto a separate window/canvas. This looks like a good starting point: http://www.tutorialspoint.com/python/tk_canvas.htm Mmh, going that route, a 0 A. D. launcher is pretty close, something where one selects mod, ai, map, etc. and get live stats in return, well, no fullscreen then. Do you speak Python?
  2. This is a little Hannibal spin-off, a bot which does nothing except logging some stats about other players. Currently it uses print() and dbgView is one way of capturing the output. It probably needs some cleansing by hand. It should look like this: time;id;name;civ;phase;food;wood;stone;metal;tresaure;unitsLost;unitsTrai;bldgsCons;bldgsLost;techs;popcnt;popcap;popmax;explored;kills0.6;1;Player 1;brit;village;300;300;300;300;0;0;0;0;0;2;9;20;300;8;00.6;2;Cleopatra Selene;ptol;village;300;300;300;300;0;0;0;0;0;1;9;20;300;8;02.2;1;Player 1;brit;village;300;300;300;300;0;0;0;0;0;2;9;20;300;8;02.2;2;Cleopatra Selene;ptol;village;300;300;300;300;0;0;0;0;0;1;9;20;300;8;03.8;1;Player 1;brit;village;300;300;300;300;0;0;0;0;0;2;9;20;300;8;03.8;2;Cleopatra Selene;ptol;village;250;300;300;300;0;0;0;0;0;1;10;20;300;8;05.4;1;Player 1;brit;village;300;300;300;300;0;0;0;0;0;2;9;20;300;8;05.4;2;Cleopatra Selene;ptol;village;200;300;300;300;0;0;0;0;0;1;10;20;300;8;07.0;1;Player 1;brit;village;300;300;300;300;0;0;0;0;0;2;9;20;300;8;07.0;2;Cleopatra Selene;ptol;village;150;300;300;300;0;0;0;0;0;1;10;20;300;8;0More columns can be easily included, the attached code gives a few hints what else is available. I use an IPython Notebook to analyze the data, it is here: http://nbviewer.ipython.org/url/dl.dropboxusercontent.com/u/354885/notebooks/Numerus.ipynb And that's me playing against another bot: numerus.zip
  3. Actually that leads a two-dimensional difficulty matrix: Econ Fort Aggr Randsandbox x x x xeasy x x x xmedium x x x xhard x x x xvery hard x x x xAlthough quite interesting, it is hard to fill the 'x' with game enhancing and distinguishable bot behaviour. Ideas? Also, it depends on the map, on some e.g. Fortifier might be the only option.
  4. Well, actually the idea is everybody feeling fancy enough forks Hannibal, spends groups a different behaviour and calls it a bot, remember - tournaments! Of course, there will be a super mega combat model with SimConomy 3.7 + GladiatorFix 7.9 trained by agentxTM.
  5. > group-self-conciousness That's too high of a target. They won't start a rebellion. I like group-self-sustainability. The grainpickers are responsible for their health and food output. To do this I give them the ability to adequately respond to field, unit, dropsite and center loss and to attacks. Other groups will be hunter, miner, logger, builder, healer and scouts. The economy is responsible to launch the right group mix depending on the map and overall output target. And on top a planner turning military requests in economic outcome or the other way round.
  6. I ran this sequence: '1': [() => "< - START: " + sequence + " - >"], '5': [T.launch("g.grainpicker", 44, 44, 44, 44, 44), "launching 5 grainpickers"], '241': [() => "< - FINIS: " + sequence + " - >"],and got this chart: Food started with 10,000, lowest was 8850. Launched at 12s the grain pickers were back to 10,000 at 282s and reached 11,000 at 386s. That makes roughly 200 food in 100 secs per grain picker for Athen without any technologies. The video is rather boring. Edit: words
  7. Even more concise: '1': [() => "< - START: " + sequence + " - >"], '2': [T.launch("g.grainpicker", 44, 44), "launching 2 grainpickers"], '10': [() => "please wait a moment"], '22': [T.destroy(216), "destroying field"], '30': [T.destroy(223, 224, 225), "destroying female units"], '44': [() => "ACTION"], '50': [T.launch("g.grainpicker", 44, 44, 44, 44, 44), "launching 5 grainpickers"], '210': [() => "< - FINIS: " + sequence + " - >"],The groups have a slightly different behaviour now, they first order one unit and the remaining four together with the field.
  8. Since 0 A.D. is fully deterministic it allows clever testing, you can be sure on map m entity e has always id n. So I made a tester module which works with this data structure: '1': [() => "Running Tester with: " + sequence], '2': [H.Groups.launch.bind(null, "g.grainpicker", 44), "launching group grainpicker #1"], '3': [H.Groups.launch.bind(null, "g.grainpicker", 44), "launching group grainpicker #2"], '22': [destroy.bind(null, 216), "destroying field"], '28': [destroy.bind(null, 221), "destroying female unit"], '29': [destroy.bind(null, 222), "destroying female unit"],At left hand ticks time right hand expressions are evaluated and a string produces a chat message. Functions destroy and chat fire engine postcommands.. The video shows how a grain-picker group responds to destroying their field and two units. Edit: words
  9. To expand: A bot doesn't have to use a mouse interface to command its forces. Even a perfect balance is topped by dividing an army into groups and moving them only to places where an advantage is expected. A good example is the wonder, it garrisons a lot of units and heals them fast, so it seems a perfect choice to secure a territorial claim. However, during battle humans fail to heal unhealthy units, because the interface is kind of a bottleneck of the command chain. If realism is a target, allowing human players to bring their choice of command chain to the field would probably help a lot. But, thinking as a bot, I can't complain.
  10. humans do not research military micro management, good!
  11. Great discussion. Bots are listening...
  12. I have just planned a hero: // state"ress": {},"ents": {"structures.athen.civil.centre": 1},"tech": ["phase.village"]// goal"ress": {},"ents": {"units.athen.hero.iphicrates":1},"tech": []HTN: SUCCESS actions: 35, 33 msecs, iter: 247, depth: 155 op: 1, inc_resource ( wood, 50 ) op: 2, inc_resource ( food, 50 ) op: 3, inc_resource ( population, 1 ) op: 4, wait_secs ( 10 ) op: 5, train_units ( units.athen.infantry.spearman.b, 1 ) op: 6, wait_secs ( 10 ) op: 7, inc_resource ( metal, 200 ) op: 8, inc_resource ( stone, 100 ) op: 9, wait_secs ( 200 ) op: 10, inc_resource ( stone, 300 ) op: 11, inc_resource ( wood, 400 ) op: 12, wait_secs ( 600 ) op: 13, inc_resource ( wood, 350 ) op: 14, build_structures ( structures.athen.house, 5 ) op: 15, wait_secs ( 265 ) op: 16, inc_resource ( wood, 400 ) op: 17, inc_resource ( wood, 400 ) op: 18, inc_resource ( food, 800 ) op: 19, research_tech ( phase.town.athen ) op: 20, inc_resource ( wood, 400 ) op: 21, build_structures ( structures.athen.defense.tower, 4 ) op: 22, wait_secs ( 600 ) op: 23, inc_resource ( stone, 100 ) op: 24, inc_resource ( metal, 800 ) op: 25, inc_resource ( stone, 900 ) op: 26, research_tech ( phase.city.athen ) op: 27, inc_resource ( metal, 200 ) op: 28, inc_resource ( stone, 100 ) op: 29, build_structures ( structures.athen.prytaneion, 1 ) op: 30, wait_secs ( 200 ) op: 31, inc_resource ( wood, 200 ) op: 32, inc_resource ( food, 50 ) op: 33, inc_resource ( population, 1 ) op: 34, train_units ( units.athen.hero.iphicrates, 1 ) op: 35, wait_secs ( 35 )op 3 + 33 look strange. The planner called about 250 methods and tree search depth was 155. I think, I rewrite some recursive parts where tail optimization doesn't work, 33 msecs are too much. Check it out: http://noiv.pythonanywhere.com/agentx/0ad/explorer/hannibal.html (FF30 mandatory, click GO) Edit: if you click stress with 10 loops, it shows stats from the triple store cache. Now, after clicking more often it takes only 13 msecs, much better.
  13. Actually, if I put 'use asm' into a module I get this: JavaScript warning: asm.js type error: Disabled by javascript.options.asmjs in about:config I've read these articles, because I couldn't believe the results I got. I wish I could you asm for the map analysis, that would be really great. But the way it currently looks, I can only image it as part of the API where bots request dozens of paths and get them back next tick.
  14. @Teiresias { isVictorious : true }, that's the plan to become a pro. No seriously, can't run this goal every second.In a RTS a bot has to re-evaluate plans after any incident, e.g. the building needed to advance to phase.town was destroyed in the meantime. I'll use the planner to feed the economy and advance from phase to phase. Attack plans are the holy grail of planning, but during combat only a few msecs can be spared for the planner. I don't know how far I get this. Current state of thinking looks like this: I'll give you some numbers about combinatoric explosion when planning heroes works. Athen uses about 70 templates and 40 techs/pairs. Going from zero to hero, may involve max 10 levels, not that bad. The triple store searches 500,000 node/edge combinations in less than 1 msec. The trick with JS is finding the sweet spot, where IonMonkey kicks in and compiles very fast code. Then you can do amazing things. > How do you set up the various operations for the planner - by hand or do you plan on parsing the entity templates (more or less) automatically? At game start all knowledge (template, techs) goes into the triple store, here is an example where I check and resolve the requirements for a phase, name === 'phase.town', buildings stores countable buildings and entities the ents in the state. if (tech.requires && tech.requires.class){ // check for enough buildings klass = tech.requires.class; amount = tech.requires.number; buildings = H.QRY(klass + " CONTAIN") .map(node => node.name) .filter(name => ( !name.contains("palisade") || !name.contains("field") || !name.contains("wall") || !name.contains("civil.centre") )); entities = H.attribs(state.ents); inter = H.intersect(buildings, entities); have = inter.reduce((a, => state.ents[a] + state.ents[b], 0); diff = amount - have; if (diff > 0){ if (name.contains('phase.town'){ house = H.QRY("house CONTAIN").first().name; } else (name.contains'phase.city'){ house = H.QRY("defensetower CONTAIN").first().name; } return [['produce', house, diff]]; }}A H.QRY with CONTAIN retrieves templates from a given class. If buildings are missing, this section composes and returns a new task for the planner, I'm sure you get the idea if you look how the produce function works: https://github.com/noiv/Hannibal/blob/master/htn-methods.js#L145
  15. Thank you for your inspiration. > asm.js tldr: forget it. Funny story. If I test in browser 0AD's handwritten cos function is as fast as the JS internal!!, cos with asm is 10 times slower AND interestingly if I remove the 'use asm' line the cos is comparable. Ontop there is a huge lag, if one calls into or out of ASM, so you are forced to write all your code in the asm module. However, then it is like writing assembler and a lot of JS feature are gone. So the only way seems to be writing Hannibal in usual JS and transpile it into asm.js. I postponed that until Alpha 517. > walls A must. Have you ever survived a MP without walls? Well, don't mean your 4 years old sister. Look here: http://www.cse.lehigh.edu/~munoz/CSE497/classes/Patrick2.ppt I think the challenge is not building the wall, but finding/logging a path through a map full of trees.
  16. https://github.com/noiv/Hannibal
  17. At game start or load a bot is thrown into cold water. He might discover a very hostile environment in terms of resources, units, buildings and enemies. Interestingly game start and end can be very similar, meaning eveything is low, if the human opponnent has victory within his grasp. But a bot doesn't give up, as long there is a small chance of success - he takes it, right? What is the worst case? Let's say no civic centers. That's close to ground zero in 0 A.D., because without CC you lack the territory to build any other structure. So, naturally the very first questions in this case are: Can I build a CC? And if not, what can I do at all? It turns out, these are very complex questions. Let's start with some simple conditions: has only resources -> whiteflag has only buildings -> whiteflag has only units -> whiteflag or fight like hellOk, that's not so difficult. And it looks translatable into straight forward JavaScript, too. Here comes the next level: has buildings, units, no resources has no CC has no CC builder can not train CC builder -> whiteflag or fight like hell can train CC builder -> gather resources -> train CC builder -> construct CC has CC builder -> gather resources -> construct CCActually that's only the surface. It assumes the units are not champions and the needed resources are available. Here are a few more: and finally: has units, resources, buildings has no CC has CC builder -> construct CC has no CC builder can train CC builder -> train builder -> construct CC can not train CC builder -> whiteflag or fight like hellCan you imagine how many conditions the bot has to check just to find out he has definetly lost? Now add more edge cases, mixin technologies, multiply with all buildings and all factions and you'll end up with tens of thousands lines of code, hard to read, difficult to maintain and taking months to write. That's where planners jump in. They know which conditions to check and how to answer them. Ontop they come up with a list of actions leading to your goal or none if your goal is unreachable. HTN (hierarchical task network) planners are conceptually fairly simple, but extremely powerful. They define a state, that's the starting point, a goal and operators and methods, the latter are just functions. Operators can change the state and methods result in more methods or operators. So, you initialize a planner with a state, your goal and then call the first method. From there it tries to decompose the problem until only an ordered list of operators is left - that's your plan. 0 A.D example: state = { resources: {food: 300, wood: 300}, entities: { structures.athen.civil.centre: 1 }, technologies: [phase.village]};goal = { resources: {}, entities: { structures.athen.field: 1}, technologies: [gather.wicker.baskets]}The goal basically says: I don't care about resources and the civic centre, but in any case I want a field and foragers better equipped. Do you see the two traps? Here's the plan: HTN: SUCCESS, actions: 8, 1 msecs op: 1, train_units ( units.athen.support.female.citizen, 1 ) op: 2, wait_secs ( 10 ) op: 3, build_structures ( structures.athen.farmstead, 1 ) op: 4, wait_secs ( 45 ) op: 5, build_structures ( structures.athen.field, 1 ) op: 6, wait_secs ( 100 ) op: 7, research_tech ( gather.wicker.baskets, 1 ) op: 8, wait_secs ( 40 )See how the planner automatically found out he needs a builder for the field and the farmstead for the technology. And the final state: resources: { food: 250, wood: 150, time: 195, metal: 0, stone: 0, pop: 1, popmax: 300, popcap: 20 }entities: { structures.athen.civil.centre: 1 units.athen.support.female.citizen: 1 structures.athen.farmstead: 1 structures.athen.field: 1}technologies: [phase.village, gather.wicker.baskets]... which can be used for your next goal. HTN Planners are well used in RTS games. The link finds a a few interesting presentations. Some games have highly optimized ones, checking hundreds of plans each tick, looking for the optimal strategy to keep the human opponent entertained. So far Hannibal's planner lacks a few features, he needs a better awareness of time e.g. calculate how long it takes to get a given amount of resources and more challenging learns the concept of parallel tasks. I'll continue when it produces heros. PS: Did I mention that's probably the first JS planner ever written for an RTS?
  18. > A purely client browser program, i.e. without backend, had a problem: it's impossible then to read or change a file in the 0ad data/mods/ folder. You can. Latest browsers provide a drag'n'drop api and a file open api, and to save you can provide the file as 'download' and the user chooses where to save, which is even better than directly overwriting files. There are good plugins available for both, shouldn't be an issue.
  19. Looking on how the API structured, I would expect this top level process: New Game : [b]ENGINE BOT[/b]read map prep entities prep maps call > CustomInit(gameState, sharedScript) prep selfstart game step +1 update events update entities update maps call > OnUpdate(sharedScript)[/font] analyse maps, entities, events fire commands // train, move, build, etc process commands goto step Load game: ENGINE BOTread saved game prep entities prep maps call > Deserialize(sharedScript) prep selfstart game step +1 update events update entities update maps call > OnUpdate(sharedScript) analyse maps, entities, events fire commands // train, move, build, etcprocess commandsgoto stepOne issue is, Deserialize got called without gameState, and the sharedScript lacks important information. This is API-wise managed by BaseAI.prototype.HandleMessage / Init. Probably long time ago there was misunderstanding what the engine and what the bot has to serilaize/deserialize, leading to assumption the bot has to serialize everything (maps, entities, events, +), however this can't work. The moment Bot.OnUpdate or API.HandleMessage is called, the engine has to deliver all/same information whether load or new game. If could read C a little better, I would try to find out if the engine is capable to provide the API a gamestate with same layout + information from a saved game and a loaded map. If the answer is yes, I would start dancing around my chair, because then a solution is very close. But I fear the engine doesn't run update maps, events, entities in case of load game.
  20. Here is the ticket: http://trac.wildfiregames.com/ticket/2495 Let me know when the API delivers proper objects, I'll do what I can to remove this roadblock. It can't be that difficult, because the C++/CCmpAIManager side knows how to initialize the game objects.
  21. Interesting. The bug starts in /simulation/ai/common-api/baseAI.js. But currently it looks more like the C++ side has problems to feed HandleMessage with proper params. Can you see any difference between loaded and fresh games here: http://trac.wildfiregames.com/browser/ps/trunk/source/simulation2/components/CCmpAIManager.cpp
  22. Well, forget about. I'm not going to listen to silly voices again. I don't see an even perfectly working patch taking this hurdle. If Wraitii would actively support loading games, why is this strange discussion happening? Don't misunderstand me, I don't want a blank check, I need reasonable criteria.
  23. OK, I got it, I entered uncharted land. There is a whole continent full of game amusement no one has ever enjoyed. But I'm alone and nobody speaks my language. Not a single soul ever continued playing a saved game. Maybe an analogy helps: a movie and a projector. The movie is suspenseful, you are sitting on the edge of your chair, chewing your nails. Then nature makes its call: You have to go for pee, too much ale. Fortunately the projector has a pause button. You press the button, light dims down, the projector goes silent and you to the men's room. Coming back, you think the movie continues where you paused. But this is what happens: Light comes back, the projector makes noise again, you see the last scene, and that's it. The projector does not continue playing. Whatever you do it still shows that last image. Then you hear a voice in your head telling you: Don't worry, it has found where you stopped. See that image, is that nothing? Don't be so greedy. But I'm greedy, I want to continue playing saved games. And I'm tired hearing about serialization, I'm talking about what happens AFTER, that very the moment the API ceases to continue. So, you silly voice, please go out of the way and shut down. > Or even fix it at the end. You want me to touch the API? Who is going to decide that?
  • Create New...