1def opening(ai*)
2	if(turn = 1, [
3		recruit('Skeleton Archer', loc(11,21)),
4		recruit('Dark Adept', loc(11,22)),
5		recruit('Dark Adept', loc(10,22)),
6		recruit('Skeleton Archer', loc(9,22)),
7		recruit('Ghost', loc(11,24)),
8		move(loc(11,23), loc(14,22)) ],
9	if(turn = 2, [
10		move(loc(11,21),loc(13,17)),
11		if(unit_at(loc(11,22)).max_moves = 6,
12		move(loc(11,22),loc(13,18)),
13		move(loc(11,22),loc(15,19))),
14		move(loc(10,22),loc(7,19)),
15		move(loc(9,22),loc(4,22)),
16		move(loc(11,24),loc(18,24)),
17		move(loc(14,22),loc(11,23)),
18		recruit('Dark Adept', loc(11,21)),
19		recruit('Dark Adept', loc(11,22)) ],
20	if(turn = 3, [
21		move(loc(18,24),loc(20,22)),
22		move(loc(15,19),loc(17,17)),
23		move(loc(4,22),loc(5,18)),
24		recruit('Skeleton Archer', loc(11,21)) ],
25	if(turn = 4, [
26		recruit('Skeleton Archer', loc(11,21)) ],
27        []))));
28
29def rate_position_defensiveness(ai*,src,dst)
30	units_can_reach(ai.my_moves, dst).size - units_can_reach(ai.enemy_moves, dst).size;
31
32def rate_position_danger(ai*,unit,dst)
33	(100*sum(map(units_can_reach(ai.enemy_moves, dst), 'enemy', max_possible_damage(enemy, unit)*defense_on(unit, dst)))) / unit.hitpoints;
34
35def build_attacks(attack_move)
36	if(attack_move,
37		map(attack_move.movements, attack(src, dst, attack_move.target)),
38	[]); def targets(ai)
39	ai.enemy_and_unowned_villages;
40
41def distance_to_target(ai,dst)
42	min(map(targets(ai), distance_between(dst, self)));
43
44def move_to_targets(ai*)
45	find(moves, src != my_leader.loc and rate_position_defensiveness(ai, src, dst) > 0)
46		where moves = sort(my_moves.moves, distance_to_target(ai, a.dst) < distance_to_target(ai, b.dst));
47
48def get_village_captures(ai)
49	sum(map(ai.enemy_and_unowned_villages, 'village', map(units_can_reach(ai.my_moves, village), move(loc, village))), []);
50
51def get_village_garrisons(ai*)
52	sum(map(my_villages, 'village', map(units_can_reach(ai.my_moves, village), move(loc, village))), []);
53
54def uncontended_captures(ai)
55	filter(get_village_captures(ai), (src != ai.my_leader.loc) and (units_can_reach(ai.enemy_moves, dst).empty));
56
57def move_to_keep(ai*)
58	if(keep_in_range,
59		move(my_leader.loc, keep_in_range),
60	null())
61		where keep_in_range = find(unit_moves(my_leader.loc), 'moveto', find(keeps, moveto = self));
62
63def village_value(ai*) 400;
64
65def rate_healing(unit*)
66	value * ((min(max_hitpoints - hitpoints, 8)*100)/max_hitpoints);
67
68def rate_village_garrison(ai*, move_from, village)
69	if(find(enemy_moves, dst = village),
70		village_value(ai),
71	0);
72
73def rate_village_capture(ai*,src,dst) village_value(ai);
74
75def rate_village_proximity(ai*, unit, dst)
76	if(distance = 1,
77		0,
78	village_value(ai)/(distance/unit.max_moves + 1))
79		where distance = distance_to_nearest_unowned_village(dst);
80
81def rate_move(ai*,src,dst)
82	if(is_village(map, dst),
83		rate_healing(u) + if(find(my_villages, self = dst),
84			rate_village_garrison(ai, src, dst),
85		rate_village_capture(ai, src, dst)),
86	rate_village_proximity(ai, u, dst)) - (danger*u.value)/2
87		where u = unit_at(src), danger = rate_position_danger(ai, unit_at(src), dst);
88
89def rate_attack(ai*,attack)
90	if(attack,
91		(attack.chance_to_kill*attack.target_value + (((attack.avg_damage_inflicted*100)/unit_at(attack.target).max_hitpoints)*attack.target_value) + sum(map(attack.movements, rate_move(ai, src, dst))))/attack.movements.size,
92	null());
93
94def get_best_move(ai*, candidate_moves)
95	if(rate_attack(ai, best_attack) >
96		if(best_move, rate_move(ai, best_move.src,
97			best_move.dst),
98		0),
99        build_attacks(best_attack),
100	[best_move])
101		where best_attack = choose(attacks, rate_attack(ai, self)),
102	best_move = choose(candidate_moves, rate_move(ai, src, dst));
103
104def move_leader_to_keep(ai*)
105	if(dest,
106		[move(my_leader.loc, dest)],
107	[])
108		where dest = find(unit_moves(my_leader.loc), 'dst', find(keeps, 'keep', keep = dst));
109
110if(vars.turn_opening != turn,
111	[set_var('turn_opening', turn)] + opening(self),
112if(my_leader.loc and find(keeps, self = my_leader.loc) = null(),
113	move_leader_to_keep(self),
114[]) + get_best_move(self, filter(my_moves.moves, src != my_leader.loc)) + [ recruit('Skeleton Archer', loc(11,21)), recruit('Dark Adept', loc(11,22)) ])
115