FormulaAI Functions

From The Battle for Wesnoth Wiki
Revision as of 21:03, 15 March 2009 by Boucman (talk | contribs) ('set_var' function)

Contents

Overview

Syntax used to explain functions usage in this document is:

<result> = <function name>( <comma-separated list of parameters> [, <comma-separated list of optional parameters] )

Function may return <result> as:

  • <variable> - any of the supported variable types
  • <boolean> - false ( 0 or null ) or true ( 1 )
  • <unit> - unit
  • <location> - place on a gamemap
  • <action> - object, which, if later passed to 'move= ' as the result of formula evaluation, make the AI perform a desired action.
  • <result> - any of the above

Also function may return only single argument, or be able to return a whole list or a map.

There are a wide variety of functions which can be used to accomplish many different tasks. You can also define your own functions.

core functions

'abs' function

<number> = abs( <input number> )

Function returns absolute value of an <input number>, for example

abs( -5 )

will return 5.

'choose' function

<result> = choose( <input list> , [ <string> ,] <formula> )

This function evaluates <formula> for each item in the <input> (which can be a list ro a map). Will evaluate to the one item which <formula> gave the highest value. For example:

choose(my_units, level)

gives back the unit with the highest level.

Note: The implicit input when evaluating a mapping/filtering function's <formula> component will be that specific item under evaluation (in this example one of "my_units"), and it can be explicitly referenced as 'self' when necessary. Optional <string> paremater indicates what word used in <formula> is equivalent to 'self'.

When evaluating the map data type, we can reference to each key by 'key' and each value by 'value'. For example:

choose( [ 'elf' -> 10, 'dwarf' -> 20 ], value )

Will return a key-value pair

{ key->'dwarf', value->20 }

'contains_string' function

<boolean> = contains_string( <string>, <key> )

Returns 1 if <key> can be found withing <string>, 0 otherwise

contains_string( 'Testing', 'ing' )

returns

1

'debug_print' function

<formula> = debug_print( [ <optional string> ,] <formula>  )

This function can be used for debging the formulas. It takes formula, writes output to the console and return it unchanged. For example:

debug_print( [ 1, 2, 3 ] )

will result in printing to the console

[ 1, 2, 3 ]

Return value is the same.

We can specify optional parameter that helps to distinguish what each of debug_print outputs is (useful if we have multiple debug_print functions):

debug_print( 'My array: ', [ 1, 2, 3 ] )

will write in the console:

My array: [ 1, 2, 3 ]

And return

[ 1, 2, 3 ]

'dir' function

<list of names> = dir ( <input object> )

This function return list with all names of <input object's> members. For example:

dir( my_leader )

will result in output:

[ 'x', 'y', 'loc', 'id', 'leader', 'hitpoints', 'max_hitpoints', 'experience', 'max_experience', 'level',
'total_movement', 'movement_left', 'side', 'is_enemy', 'is_mine']

This command is useful in formula command line, to get information about members of different type of data. To get list of members of the ai, type:

dir( self )

'filter' function

<result> = filter( <input>, [ <string> ,] <formula> )

This function will run <formula> on each item in the <input> (which can be a list or a map). Will evaluate to a <result> which only contains items the <formula> was true for. Optional <string> indicates what word used in <formula> is equivalent to 'self'. For example:

filter(my_units, hitpoints < max_hitpoints)

will return all of your units which have less than maximum hitpoints. For instance this could be used if looking for candidates for healing.

'find' function

<result> = find( <input>, [ <string>,] <formula> )

This function will run <formula> on each item in the <input> (which can be a list or a map) and will return a first item for which <formula> was true. Optional <string> indicates what word used in <formula> is equivalent to 'self'. For example:

filter(units, id = 'Elvish Archer' )

will return first unit with id equal to 'Elvish Archer'.

'head' function

<variable> = head( <list of variables> )

Head returns first item from the <list of variables>, for example

head( [ 5, 7, 9] )            #returns 5
head( [ 'Orc', 'Human' ] )    #returns 'Orc'

'if' function

<result> = if( <condition> , <if true> , <otherwise> )


If the <condition> parameter is true, the function will evaluate to being equal to its second input ( <if true> ), otherwise it will evaluate to being equal to its third input ( <otherwise> ). For instance, an AI that recruits Wolf Riders on the first turn, and Orcish Grunts thereafter might look like this:

move="if(turn = 1, recruit('Wolf Rider'), recruit('Orcish Grunt'))"


'index_of' function

<result> = index_of( <value>,<list> )

This function will return the first index where <value> can be found in <list>

It will return -1 if the value is not found

'keys' function

<result list> = keys( <input map> )

Extract key values from a <input map> and return them as a <result list>

keys( [ 'Elvish Fighter' -> 50, 'Elvish Archer' -> 60 ] )

Returns

[ 'Elvish Fighter', 'Elvish Archer' ]

'map' function

<result> = map( <input> , [ <string> ,] <formula> )

This function will run <formula> on each item in the <input> (which can be a list or a map), and evaluate to a new <result> list, or a map, which contains the same number of items as in <input>, with the formulas run on each item. Optional <string> indicates what word used in <formula> is equivalent to 'self'. For example:

map( [10,20], self*self)

and

map( [10,20], 'value', value*value)

both will result in [100, 400]. Formula:

map(my_units, hitpoints) 

will give a list back with the number of hitpoints each unit has. This is more useful in conjunction with other functions.

map( [ 'elf' -> 10, 'dwarf' -> 20 ], value*2 )

Above will produce [ 'elf' -> 20, 'dwarf' -> 40 ]. Note that in case of a map data type, 'map' function can modify only the value.

'max' function

<number> = max( <list of numbers> )

Function will return maximal number from a list,

max( [ 2, 8, -10, 3] )

will return 8.

'min' function

<number> = min( <list of numbers> )

Function will return minimal number from a list,

min( [ 3, 7, -2, 6] )

will return -2.

'rgb' function

<value> = rgb( <red>,<green>,<blue> )

Function will return a single int which encodes the color defined with the three parameters red,green,blue

The parameters must be in the range [0..99]

'size' function

<number> = size( <list of variables> )

This function returns how many variables are stored in a list:

size( [ 5, 7, 9] )                #return 3
size( [ 'Archer', 'Fighter' ] )   #return 2

'sort' function

<result list> = sort( <input list> , <formula> )

This function evaluates to a <result list> sorted according to the comparison <formula> for each item 'a' and its successor 'b'. For instance, sorting units according to hitpoints would be done by:

sort( my_units, a.hitpoints > b.hitpoints )

'sum' function

<number> = sum( <list of numbers> )

This function evaluates to the sum of the items in the <list of numbers>. For example

sum( [ 2, 5, 8] )

returns 15, and:

sum( map( my_units,  max_hitpoints - hitpoints ) )

finds the total damage your units have taken.

'switch' function

<result> = switch( <variable>, <value 1>, <outcome 1>, ... , <value N>, <outcome N> [, <default outcome> ] >

Switch funtion takes variable, and checks if it is equal to any of the specified <values>. If matching value is found, <outcome> assigned to it is returned, if not, then function returns either <default outcome> (if specified) or null.

'tolist' function

<list> = tolist( <input map> )

This function takes map and return a list of key-value pairs objects. For example:

tolist( [ 'Elf' -> 10, 'Dwarf' -> 20] )

will return:

[{key->'Elf',value->10}, {key->'Dwarf',value->20}]

'tomap' function

<map> = tomap( <input list A> [, <input list B> ] )

This function takes one or two lists as input and returns a map. If only one list is specified, then function will evaluate this list, count how many simmilar elements are withing this list, and return a map with keys being these elements, and values being a number representing of them list contains, For example:

tomap( ['elf', 'dwarf', 'elf', 'elf', 'human', 'human' ] )

will return:

[ 'elf' -> 3, 'dwarf' -> 1, 'human' -> 2 ]

If two lists are specified, then elements of the first one will be used as a keys, and elements of second one as a values, when creating a output map. Note that these input lists must be of the same length.

tomap( [ 'elf', 'dwarf' ], [10, 20] )

will result in:

[ 'elf' -> 10, 'dwarf' -> 20 ]

'values' function

<result list> = values( <input map> )

Extract values assigned to keys from a <input map> and return them as a <result list>

values( [ 'Elvish Fighter' -> 50, 'Elvish Archer' -> 60 ] )

Returns

[ 50, 60 ]

'wave' function

<value> = wave( <value> )

given a value V, returns

 sin(2*pi/(V%1000/1000) )

AI specific functions

Base functions

'attack' function

<action> = attack( <attacker's position>, <destination>, <attack location> [,  <weapon> ] )

The first three parameters are locations. At the begining, unit which is standing at <attacker's position> is moved to <destination> place. Then, from that place unit is attacking unit which stands in place marked by <attack location>. Fourth optional parameter is number, and indicates which weapon attacker should use - if not specified, best possible weapon is chosed automatically.

'fallback' function

<action> = fallback( [<name>] )

This function allows to chose different AI or to human player, who will take control over side untill the end of current turn. For example:

fallback()

will transfer control to the default C++ AI. You can specify a name of different AI (for example python_ai) to transfer control to it. If you want to give control to the player, use:

fallback( 'human' )

'get_unit_type' function

<unit> = get_unit_type( <unit name> )

Function returns unit_type object of desired type, for example:

get_unit_type( 'Mage' )

will result in returning unit_type of a Mage.

'move' function

<action> = move( <source> , <destination> )

Moves unit from <source> to <destination> and sets unit movement to 0. For example unit formula like:

move(my_leader.loc, loc(my_leader.loc.x, my_leader.loc.y - 1) )

will make leader move one hex north. Leader's movement points will be reset to 0.

'move_partial' function

<action> = move_partial( <source> , <destination> )

Moves unit from <source> to <destination>. For example unit formula like:

move(my_leader.loc, loc(my_leader.loc.x, my_leader.loc.y - 1) )

will make leader move one hex north.

'set_unit_var' function

<action> = set_unit_var( <key>, <value> , <location>)

This action creates a new variable which is attached to the unit at <location>


'set_var' function

<action> = set_var( <key> , <value> )

This action sets new variable, for example:

set_var( 'Number one' , 1 )

Will create variable with name 'Number one' and assign 1 to it.

Evaluation

'calculate_outcome' function

[<list of outcoms>]  = calculate_outcome(<attacker> ,<attacker location> , <defender location> , [<weapon>] )

returns a list of possible outcomes when <attacker> attacks the unit at <defender location> from <attacker location>

if no weapon is provided, it will return for the weapon considered the best by the C++ weapon choice algorithm (the one used to select default weapon in normal games)


'chance to hit' function

<number> = chance_to_hit( <unit> , <location> )

This function returns how possible ( in % ) it is to hit given <unit> in a specific <location>. For example:

chance_to_hit( my_leader , my_leader.loc )

shows how easy it is to hit your leader has in a place he is currently standing on.


'evaluate_for_position' function

<variant> = evaluate_for_position(<position>, <formula> )

Returns the result of <formula> as if <formula> was evaluated with a position of <position> instead of the current position

'max_possible_damage' function

<number> = max_possible_damage( <attacking unit> , <defending unit> )

Function returns highest possible damage that <attacking unit> can inflict to <defending unit>.

'max_possible_damage_with_retaliation' function

<number> = max_possible_damage_with_retaliation( <attacking unit> , <defending unit> )

Function returns an array:

[ <attacker_melee>, <attacker_ranged>, <defender_melee>, <defender_ranged> ] 

in which first two elements are highest possible damage that <attacking unit> can inflict to <defending unit> with melee and ranged attacks, and latter two elements are highest possible damage that <defending unit> can inflict to <attacking unit> also with melee and ranged attacks.

'movement_cost' function

<number> = movement_cost( <unit> , <location> )

This function returns movememtn cost of given <unit> in a specific <location>. For example:

movement_cost( my_leader , my_leader.loc )

shows what movement cost your leader has in a place he is currently standing on.

Gamemap functions

'adjacent_locs' function

<loc list> = adjacent_locs( <location> )

Returns a list containing the list of the six locations adjacent to <location>


'close enemies' function

<units list> = close_enemies( <location> , <distance> )

This function gets a list of enemies in the given or smaller distance from the location. For example:

close_enemies(loc(10,10), 5)

gives back a list of enemies in the distance of 5 tiles or less from the tile (10, 10).

'distance_between' function

<number> = distance_between( <location A> , <location B> )

This function returns distance (in hexes) between <location A> and <location B>. For example:

distance_between( loc( 1, 1) , loc( 3, 3) )

will return 3.

'distance_to_nearest_unowned_village' function

<number> = distance_to_nearest_unowned_village( <location A> )

This function returns distance (in hexes) between <location A> and nearest unowned village.

'defense_on' function

<number> = defense_on( <unit> , <location> )

This function returns defense rate of given <unit> in a specific <location>. For example:

defense_on( my_leader , my_leader.loc )

shows how good defense your leader has in a place he is currently standing on.

'find_shroud' function

<locations list> = find_shroud()

This function will return a list of locations of shrouded hexes.

'is_village' function

<boolean> = is_village( <map or ai.map> , <location> )   #1
<boolean> = is_village( <map or ai.map> , <coordinate x> , <coordinate y> )   #2

The first argument is always a 'map' - member of the ai which provides information about the gamemap.

In #1 usage, we put in as a second argument location. In #2, second and third arguments are numbers: coordniates of the certain hex on a map. Function checks if that place is a village, and returns either 1 (yes, it is village) or 0 (no, it isn't village). Example of usage:

is_village( map , loc( 2, 3) )
is_village( map , 2, 3)

Both check, if hex with coordinates 2,3 is a village.

Remember, when using is_village in custom function, you either have to access map by writing 'ai.map', or specify ai as a 'default input'.

'loc' function

<location> = loc( <X number>, <Y number> )

Function will return a location (pair of numbers) from two given input arguments.

'shortest_path' function

<list of locations> = shortest_path( <location A> , <location B> [, <unit location> ] )

When only 2 parameters are specified, function returns list with all locations that unit standing on <location A> has to move through to get to <location B>. If optional 3rd parameter is specified, it returns list with all locations that unit standing on <unit location> would need to move through to get from <location A> to <location B>. This function takes into account zone of control of enemy units.

'simplest_path' function

<list of locations> = simplest_path( <location A> , <location B> [, <unit location> ] )

When only 2 parameters are specified, function returns list with all locations that unit standing on <location A> has to move through to get to <location B>. If optional 3rd parameter is specified, it returns list with all locations that unit standing on <unit location> would need to move through to get from <location A> to <location B>. This function does not take into account zone of control or enemy units.

'unit_at' function

<unit> = unit_at( <location> ) 

This function takes only one argument - location, and returns unit if there is one standing in that location, or null otherwise. Example of usage:

unit_at( loc( 4, 4) )

'nearest_keep' function

<keep location> = nearest_keep( <input location> )

Function returns location of nearest keep to the specified <input location>, or null if there is no keep on the map.

'nearest_loc' function

<keep location> = nearest_keep( <input location>, <list of locations> )

Function returns location that is the nearest to <input location>.

'unit_moves' function

<locations list> = unit_moves( <unit location> )

Function returns list of all possible locations which unit standing at <unit location> can reach. If unit can't move, or there is no unit standing at given location, empty list is returned.

'units_can_reach' function

<units list> = units_can_reach( <possible moves list>, <location> )

Function takes as an input list of possible moves ( ai.my_moves for units that belong to AI, or ai.enemy_moves for units that belong to the opponent ) and checks which units from that list can reach <location>.

Recruitment

'recruit' function

<action> = recruit( <unit name> [, <location> ] )

This function results in recruting a unit specifed by <unit name> at first free castle hex, or at given <location>. Function:

recruit('Footpad', loc(3,3) ) 

will result in recruting Footpad at castle hex with coordinates 3,3.