User:Darth Fool

From The Battle for Wesnoth Wiki
Revision as of 21:25, 30 May 2007 by Darth Fool (talk | contribs)

This page is intended as a development page for the documentation of the new AI that I am working on. When the AI is officially released, the information will be migrated to the official wml reference pages. Some of this is partially implemented, some of it has not yet been implemented, and some of these are planned changes to something that is already implemented, and all of it is subject to change in the code without notification. So, in short, don't start using this in your scenarios and expect it to work just yet, or even to still be the same by the time of the official release. This is primarily meant as a way to organize my thoughts and reduce the time from when the code is complete to when the new AI is fully documented. You have been warned.


The Grand Idea

Ok, so what is this AI supposed to accomplish anyways. Well, it has many goals, but most of them can be wrapped up in the following statement: The AI should be sufficiently flexible to be able to specify parameters so that it can win Heir To The Throne on easy without cheating. That means, no knowing where things are before they are discovered (scepter of fire), no knowing where hidden or fogged units are, etc... Along the way, we should end up with an AI that makes it quite possible to create much more interesting AI behaviour in campaigns. so, how to accomplish this?

Orders

The basic scheme begins with a simple concept. The AI WML will be able to specify the order in which various objectives are accomplished, and by what units those orders are filled. Consider that currently, the AI pursues its goals in a very specific order (combat, village capture, healing, retreat, recruit...)

So, the first order of business is to enable the abilty to specify the order in which commands are executed. As a further refinement, we allow the order to restrict what type of units the order applies to. Inside the order are a series of commands that are executed. Units that fill that order remember which order they are following (via the ai_special tag in the unit) until they are reassigned. Units that have no ai_special are part of the "default" orders. Initially, any [fill] commands are executed within the order. After this, units are sorted according to any [sort] commands. Then, for each unit the remaining commands are executed in order by each unit before the next unit begins executing the commands.

[order]#This tag specifies the beginning of an order description.  
  name = #the name of the order.  Acts to id units that are part of this order
  id = #uniq ID of this order tag.  Used when executing summon commands.
  execute = # yes(default) or no.  If yes will execute when encountered.  
            # If no, only executed if explicitly called by an execute command.
  memory = #In the various calculations, use the last seen locations of units that 
           # are now invisible if they were last seen within memory turns.
  priority = # determines if order can steal units from other orders during fill. 
             # can only steal units from orders with strictly lower priority.
             # units of equal or greater priority will ignore the request to fill 
             # the order.  default value = 0
  [fill]#command to attempt to fill the order with units that match the appropriate unit filter
    number = #command of how many units to fill that match the filter
    [filter]#standard unit filter.[/filter]
    sort = #evaluation of how to choose which unit to accept first.  Higher value chosen first.
  [/fill]
  [sort] 
    [filter]#standard unit filter.
    [/filter]
    sort = #evaluation of how to choose which unit to accept first.  Higher value chosen first.
  [/sort]   
  [command]#generic tags for all commands
    [filter]#standard unit filter.  limits which units will execute this command.
    [/filter]
    type = #type of command to execute.  command specific WML tags below
  [/command]#move command
    type = moveto # move to target.
  [command]
    type = set_order # change the unit to be a part of a different order
  [/command]
  [command]
    type = break # stop executing this order for this unit.  
    #Should really have a filter otherwise makes all following commands never be executed.
  [/command]
  [command]
    type = attack # execute an attack.  Does not move the unit! 
  [/command]
  [command]
    type = recruit # recruit units.  Does not move the unit!
  [/command]
  [command]
    type = execute # execute the following order before continuing.
    id = #id of order to execute
  [/command]
  [command]
    type = summon # summon units to give current unit a boost before combat.  
    #possibly will be eliminated in favor of the execute command.
  [/command]
 [/order]

Note that orders with the same name can be used multiple times and will keep the same units between calls, but they should each have a unique id.

Evaluators

Within the many options, there will be various parameters that need to be calculated, especially numeric ones. A large number of them will be possible to be specified as an expression that will be evaluated at the time the order is being executed. Most of these will be numeric. To make this more flexible, these values will allow the use of simple arithmetic expressions, wml variables, and some specialized function calls. A typical example might look like:

 sort_value = "$villages + (2*$enemies) / @distance(@unit(),@target(fool))"

note that the quotes are necessary to prevent certain preprocessor actions.

In this case the first thing that are evaluated are the WML variables. Then functions that are designated by beginning with an @ followed by the function name and a parenthetical expression that encloses a parameter string. Typically these functions will evaluate the parameter string in a similar manner before returning a value. Note that the string inside the parenthesis of a function will be passed as a whole into the function before being evaluated. Typically the first thing that each function will do is re-evaluate the string, but this is not a requirement.

The next thing that is evaluated are things within paranthesis and finally the arithmetic expression evaluated with the standard precedence.

Items within an individual command will be evaluated before the command is executed. Items within an individual order will be evaluated at the begining of the order for each unit in the order. Items within the AI tag but not in either of the above will be evaluated only at the beginning of the turn.

The use of evaluators will make it possible to control many of the AI parameters indirectly via WML variables that are set/changed within events.

@ Functions The following functions are planned for use within the evaluators. Parameters are generally a comma seperated list. Required parameters must be in the proper order at the beginning of the list. If optional parameters are allowed, they go at the end of the list and are generally of the form "A=b" where A is the optional parameter and B is the value to assign it.

@distance(x1,y1,x2,y2 [,type=[hex,turns]]) : evaluate distance between two hexes using different metrics @adjacent(x1,y1 [,direction=[1-6]]) : return adjacent hex [x,y] values in different directions (0=N, 1=NE ...) @unit([variable=[location,wml_variable...],id=]) : return variable from the current unit (or unit with matching id. @hex(x1,y1,variable) : return variable associated with particular hex @eval(string) : evaluate an aritmetic expression