335 lines
7.2 KiB
Text
335 lines
7.2 KiB
Text
wfl 'recruitment.fai'
|
|
|
|
{ai/formula/lib/map_evaluation.fai}
|
|
{ai/formula/lib/util.fai}
|
|
|
|
def get_terrain_types(ai*, locations)
|
|
map( locations, 'l', fast_map[l].id ) where fast_map = location_to_terrain_map(ai);
|
|
|
|
|
|
def get_villages_on_terrain_map( ai*, locations_map )
|
|
filter( villages, locations_map[self] );
|
|
|
|
#
|
|
for now important locations are villages only
|
|
#
|
|
def mark_important_locations(ai*, location_map )
|
|
map( location_map,
|
|
if( tmp_villages[key],
|
|
1000,
|
|
value
|
|
)
|
|
)
|
|
where tmp_villages = tomap( get_locations_surroundings( ai, get_villages_on_terrain_map( ai, location_map ), 1 ) );
|
|
|
|
def get_important_locations(ai* )
|
|
keys(
|
|
map( ai.vars.side_terrain,
|
|
value >= 1000
|
|
)
|
|
);
|
|
|
|
def enemy_leaders( ai* )
|
|
sum(
|
|
map( enemies, 'enemy',
|
|
filter( units_of_side[enemy], canrecruit )
|
|
)
|
|
);
|
|
|
|
def find_enemies_part( ai*, locations_map)
|
|
tomap(
|
|
enemy_leaders,
|
|
map( enemy_leaders, 'leader',
|
|
sum(
|
|
map( keys(locations_map), 'location',
|
|
distance_between( location, leader.loc )
|
|
)
|
|
)
|
|
)
|
|
)
|
|
where enemy_leaders = enemy_leaders( ai );
|
|
|
|
def find_enemies( ai*, locations_map)
|
|
filter( keys(enemies_part), 'leader',
|
|
enemies_part[leader] <= average( values( enemies_part ) )
|
|
)
|
|
where enemies_part = find_enemies_part( ai, locations_map );
|
|
|
|
|
|
def direct_enemies_units( ai* )
|
|
sum(
|
|
map( vars.direct_enemies, 'enemy',
|
|
units_of_side[enemy.side]
|
|
)
|
|
);
|
|
|
|
def direct_enemies_recruits( ai* )
|
|
sum(
|
|
map( vars.direct_enemies, 'enemy',
|
|
recruits_of_side[enemy.side]
|
|
)
|
|
);
|
|
|
|
#
|
|
returns map of important locations and number of their occurrences on a gamemap
|
|
for example: [ 'forest' -> 10 ]
|
|
#
|
|
def important_locations_map(ai*)
|
|
tomap(get_terrain_types(ai, get_important_locations(ai)));
|
|
|
|
|
|
def my_recruits_defense(ai*)
|
|
tomap( map(my_recruits, id),
|
|
map( my_recruits, 'recruit',
|
|
sum(values(map( important_locs,
|
|
defense_on(recruit, id_translator[key]) * value
|
|
)))
|
|
)
|
|
)
|
|
where important_locs = important_locations_map(ai),
|
|
id_translator = id_to_location_map(ai);
|
|
|
|
def my_recruits_movement_cost(ai*)
|
|
tomap( map(my_recruits, id),
|
|
map( my_recruits, 'recruit',
|
|
sum(values(map( important_locs,
|
|
movement_cost(recruit, id_translator[key]) * value
|
|
)))
|
|
)
|
|
)
|
|
where important_locs = important_locations_map(ai),
|
|
id_translator = id_to_location_map(ai);
|
|
|
|
def locally_normalize_to_highest( input_map )
|
|
map( input_map, (value * 100)/max )
|
|
where max = highest_value(input_map);
|
|
|
|
def locally_normalize_to_lowest( input_map )
|
|
map( input_map, (value * 100)/min )
|
|
where min = lowest_value(input_map);
|
|
|
|
|
|
|
|
# look for who we fight against #
|
|
def enemy_leaders(ai*)
|
|
map( enemies, 'enemy_side', find(units_of_side[enemy_side], canrecruit ) );
|
|
|
|
|
|
def distance_to_enemies(ai*)
|
|
tomap( enemies, map( enemy_leaders(ai), distance_between( my_leader.loc, loc ) ));
|
|
|
|
# not used anymore
|
|
def find_important_opponents(ai*)
|
|
keys(filter( dist_en, value<avg ))
|
|
where avg = (average(values(distance_to_enemies(ai)))*11)/10,
|
|
dist_en = distance_to_enemies(ai);
|
|
|
|
|
|
def current_enemies_units(ai*)
|
|
sum(map( find_important_opponents(ai), 'enemy_side',
|
|
units_of_side[ enemy_side ] ));
|
|
|
|
def current_enemies_recruits(ai*)
|
|
sum(map( find_important_opponents(ai), 'enemy_side',
|
|
recruits_of_side[ enemy_side ] ));
|
|
#
|
|
|
|
def current_enemies(ai*)
|
|
if( en_units.size > 5, en_units, en_recruis )
|
|
where en_units = direct_enemies_units(ai),
|
|
en_recruis = direct_enemies_recruits(ai);
|
|
|
|
|
|
def evaluate_attacker_against_opponents(ai*, unit, enemy_units)
|
|
sum(
|
|
map(
|
|
enemy_units, 'enemy_unit',
|
|
sum(
|
|
map(
|
|
[
|
|
max_possible_damage_with_retaliation( unit, enemy_unit )
|
|
],
|
|
max(
|
|
[
|
|
self[0],
|
|
self[1]
|
|
]
|
|
)*3
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
def evaluate_defender_against_opponents(ai*, unit, enemy_units)
|
|
sum(
|
|
map(
|
|
enemy_units, 'enemy_unit',
|
|
sum(
|
|
map(
|
|
[
|
|
max_possible_damage_with_retaliation( enemy_unit, unit )
|
|
],
|
|
max(
|
|
[
|
|
self[0] - self[2],
|
|
self[1] - self[3]
|
|
]
|
|
)*5
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
def evaluate_recruits_offensive_combat(ai*, recruits, enemy_units)
|
|
map( recruits, 'recruit',
|
|
evaluate_attacker_against_opponents( ai, recruit, enemy_units )
|
|
);
|
|
|
|
def evaluate_recruits_defensive_combat(ai*, recruits, enemy_units)
|
|
map( recruits, 'recruit',
|
|
evaluate_defender_against_opponents( ai, recruit, enemy_units )
|
|
);
|
|
|
|
def combine_maps_mul( map_A, map_B )
|
|
map( map_A, value * map_B[key] );
|
|
|
|
def combine_maps_sub( map_A, map_B )
|
|
map( map_A, value - map_B[key] );
|
|
|
|
def combine_maps_add( map_A, map_B )
|
|
map( map_A, value + map_B[key] );
|
|
|
|
def combine_maps_div( map_A, map_B )
|
|
map( map_A, value / map_B[key] );
|
|
|
|
#
|
|
[ locally_normalize_to_highest(my_recruits_defense(self)),
|
|
tomap(map(my_recruits, id),map(my_recruits, hitpoints) ),
|
|
locally_normalize_to_lowest(my_recruits_movement_cost(self)),
|
|
tomap(map(my_recruits, id),map(my_recruits, max_moves))]
|
|
#
|
|
|
|
def consider_unit_cost(ai*)
|
|
make_positive_only(map( cost_map, (value - average(values(cost_map))) * 80))
|
|
where cost_map = tomap(map(my_recruits, id),map(my_recruits, cost ));
|
|
|
|
|
|
def defense_hp_eval(ai*, recruits_id_map)
|
|
locally_normalize_to_highest(
|
|
combine_maps_mul(
|
|
my_recruits_defense(self),
|
|
tomap(recruits_id_map, map(
|
|
my_recruits,
|
|
hitpoints*15)
|
|
)
|
|
)
|
|
);
|
|
|
|
def movement_eval(ai*, recruits_id_map)
|
|
locally_normalize_to_highest(
|
|
make_positive_only(
|
|
map(
|
|
combine_maps_div(
|
|
my_recruits_movement_cost( ai ),
|
|
tomap( recruits_id_map,
|
|
map( my_recruits,
|
|
max_moves
|
|
)
|
|
)
|
|
),
|
|
-value
|
|
)
|
|
)
|
|
);
|
|
|
|
def fighting_eval(ai*, recruits_id_map)
|
|
make_positive_only(
|
|
combine_maps_sub(
|
|
tomap(recruits_id_map, evaluate_recruits_offensive_combat( ai, my_recruits, current_enemies ) ),
|
|
tomap(recruits_id_map, evaluate_recruits_defensive_combat( ai, my_recruits, current_enemies ) )
|
|
)
|
|
)
|
|
where current_enemies = current_enemies(ai);
|
|
|
|
def level_zero_malus(ai*)
|
|
map( lvl_map,
|
|
if(value = 0, 40, 0)
|
|
)
|
|
where lvl_map = tomap(
|
|
map(my_recruits, id),
|
|
map(my_recruits, level )
|
|
);
|
|
|
|
#tmp function #
|
|
def filter_out( input_map, comparable_map )
|
|
filter( input_map, comparable_map[key] > comp_val)
|
|
where comp_val = average(values(comparable_map))/2;
|
|
|
|
|
|
def calculate_recruits(ai*)
|
|
change_numbers_to_percents(
|
|
combine_maps_sub(
|
|
combine_maps_add(
|
|
combine_maps_add(
|
|
defense_hp_eval(ai, recruits_id_map ),
|
|
movement_eval(ai, recruits_id_map)
|
|
),
|
|
multiply_values(
|
|
fighting_eval(ai,recruits_id_map), 5
|
|
)
|
|
),
|
|
combine_maps_add(
|
|
consider_unit_cost(ai),
|
|
level_zero_malus(ai)
|
|
)
|
|
)
|
|
) where recruits_id_map = map(my_recruits, id);
|
|
|
|
def unit_chooser(ai*,unit_map)
|
|
choose(
|
|
keys(unit_map), 'unit_type',
|
|
unit_map[unit_type] -
|
|
(
|
|
(
|
|
100 *
|
|
size(
|
|
filter(
|
|
my_units,
|
|
type = unit_type
|
|
)
|
|
)
|
|
) /
|
|
size(my_units)
|
|
)
|
|
);
|
|
|
|
if( vars.side_terrain,
|
|
if(vars.direct_enemies,
|
|
if(vars.turn_initialized = turn,
|
|
|
|
safe_call( recruit(unit_chooser(self, vars.recruits_map)),
|
|
end
|
|
),
|
|
|
|
[
|
|
set_var(debug_print('turn_initialized'), turn) ,
|
|
set_var(debug_print('recruits_map'), calculate_recruits(self))
|
|
]
|
|
),
|
|
|
|
set_var( 'direct_enemies', find_enemies(self, vars.side_terrain ) )
|
|
),
|
|
|
|
set_var('side_terrain',
|
|
mark_important_locations( self,
|
|
calculate_map_ownership(
|
|
recruits_of_side,
|
|
map(filter(sum(units_of_side), canrecruit), loc),
|
|
4, 7, 4
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
wflend
|