From 4a7292e99329fa2fb1fa4aef10a8b4a3d91b6662 Mon Sep 17 00:00:00 2001 From: mattsc Date: Wed, 16 Apr 2014 09:46:48 -0700 Subject: [PATCH] Goto Micro AI: code cleanup --- data/ai/micro_ais/cas/ca_goto.lua | 100 ++++++++++++------------------ 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/data/ai/micro_ais/cas/ca_goto.lua b/data/ai/micro_ais/cas/ca_goto.lua index 45e48bfdf44..09e60716ab7 100644 --- a/data/ai/micro_ais/cas/ca_goto.lua +++ b/data/ai/micro_ais/cas/ca_goto.lua @@ -5,9 +5,9 @@ local LS = wesnoth.require "lua/location_set.lua" local MAIUV = wesnoth.require "ai/micro_ais/micro_ai_unit_variables.lua" local MAISD = wesnoth.require "ai/micro_ais/micro_ai_self_data.lua" -local function custom_cost(x, y, u, enemy_map, enemy_attack_map, multiplier) +local function custom_cost(x, y, unit, enemy_map, enemy_attack_map, multiplier) local terrain = wesnoth.get_terrain(x, y) - local move_cost = wesnoth.unit_movement_cost(u, terrain) + local move_cost = wesnoth.unit_movement_cost(unit, terrain) move_cost = move_cost + (enemy_map:get(x,y) or 0) move_cost = move_cost + (enemy_attack_map.units:get(x,y) or 0) * multiplier @@ -18,10 +18,8 @@ end local ca_goto = {} function ca_goto:evaluation(ai, cfg, self) - - -- If cfg.release_all_units_at_goal is set, check - -- whether the goal has already been reached, in - -- which case we do not do anything + -- If cfg.release_all_units_at_goal is set, check whether the goal has + -- already been reached, in which case we do not do anything if MAISD.get_mai_self_data(self.data, cfg.ai_id, "release_all") then return 0 end @@ -46,7 +44,7 @@ function ca_goto:evaluation(ai, cfg, self) -- Now on to the current turn local str = 'GO_goals_taken_' .. wesnoth.current.turn - for _, loc in ipairs(all_locs) do + for _,loc in ipairs(all_locs) do if (not self.data[str]) or (not self.data[str]:get(loc[1], loc[2])) then table.insert(locs, loc) end @@ -56,16 +54,14 @@ function ca_goto:evaluation(ai, cfg, self) end if (not locs[1]) then return 0 end - -- Find the goto units local all_units = AH.get_units_with_moves { side = wesnoth.current.side, { "and", cfg.filter } } - -- Exclude released units local units = {} if cfg.release_unit_at_goal then - for _, unit in ipairs(all_units) do + for _,unit in ipairs(all_units) do if (not MAIUV.get_mai_unit_variables(unit, cfg.ai_id, "release")) then table.insert(units, unit) end @@ -82,9 +78,8 @@ function ca_goto:evaluation(ai, cfg, self) end function ca_goto:execution(ai, cfg, self) - local units, locs = self.data.GO_units, self.data.GO_locs -- simply for convenience + local units, locs = self.data.GO_units, self.data.GO_locs - -- Need the enemy map and enemy attack map if avoid_enemies is set local enemy_map, enemy_attack_map if cfg.avoid_enemies then if (type(cfg.avoid_enemies) ~= 'number') then @@ -93,56 +88,56 @@ function ca_goto:execution(ai, cfg, self) H.wml_error("Goto AI avoid_enemies= argument must be >0") end - local enemies = wesnoth.get_units { { "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } } } + local enemies = wesnoth.get_units { { "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } } } enemy_map = LS.create() - for i,e in ipairs(enemies) do - enemy_map:insert(e.x, e.y, (enemy_map:get(e.x, e.y) or 0) + 1000) - for x, y in H.adjacent_tiles(e.x, e.y) do - enemy_map:insert(x, y, (enemy_map:get(x, y) or 0) + 10) + for _,enemy in ipairs(enemies) do + enemy_map:insert(enemy.x, enemy.y, (enemy_map:get(enemy.x, enemy.y) or 0) + 1000) + for xa,ya in H.adjacent_tiles(enemy.x, enemy.y) do + enemy_map:insert(xa, ya, (enemy_map:get(xa, ya) or 0) + 10) end end enemy_attack_map = BC.get_attack_map(enemies) end - local closest_hex, best_path, best_unit, max_rating = {}, nil, {}, -9e99 - for i,u in ipairs(units) do - for i,l in ipairs(locs) do - - -- If use_straight_line is set, we simply find the closest + local max_rating, closest_hex, best_path, best_unit = -9e99 + for _,unit in ipairs(units) do + for _,loc in ipairs(locs) do + -- If cfg.use_straight_line is set, we simply find the closest -- hex to the goal that the unit can get to if cfg.use_straight_line then - local hex, unit, rating = AH.find_best_move(u, function(x, y) - local r = - H.distance_between(x, y, l[1], l[2]) + local hex, _, rating = AH.find_best_move(unit, function(x, y) + local r = - H.distance_between(x, y, loc[1], loc[2]) -- Also add distance from unit as very small rating component -- This is mostly here to keep unit in place when no better hexes are available - r = r - H.distance_between(x, y, u.x, u.y) / 1000. + r = r - H.distance_between(x, y, unit.x, unit.y) / 1000. return r end, { no_random = true }) if (rating > max_rating) then max_rating = rating - closest_hex, best_unit = hex, u + closest_hex, best_unit = hex, unit end else -- Otherwise find the best path to take local path, cost if cfg.avoid_enemies then - path, cost = wesnoth.find_path(u, l[1], l[2], + path, cost = wesnoth.find_path(unit, loc[1], loc[2], function(x, y, current_cost) - return custom_cost(x, y, u, enemy_map, enemy_attack_map, cfg.avoid_enemies) - end) + return custom_cost(x, y, unit, enemy_map, enemy_attack_map, cfg.avoid_enemies) + end + ) else local enemy_at_goal if cfg.ignore_enemy_at_goal then - enemy_at_goal = wesnoth.get_unit(l[1], l[2]) + enemy_at_goal = wesnoth.get_unit(loc[1], loc[2]) if enemy_at_goal and wesnoth.is_enemy(wesnoth.current.side, enemy_at_goal.side) then wesnoth.extract_unit(enemy_at_goal) else enemy_at_goal = nil end end - path, cost = wesnoth.find_path(u, l[1], l[2], { ignore_units = cfg.ignore_units }) + path, cost = wesnoth.find_path(unit, loc[1], loc[2], { ignore_units = cfg.ignore_units }) if enemy_at_goal then wesnoth.put_unit(enemy_at_goal) --- Give massive penalty for this goal hex @@ -151,26 +146,23 @@ function ca_goto:execution(ai, cfg, self) end -- Make all hexes within the unit's current MP equaivalent - if (cost <= u.moves) then cost = 0 end + if (cost <= unit.moves) then cost = 0 end - rating = - cost + local rating = - cost - -- Add a small penalty for occupied hexes - -- (this mean occupied by an allied unit, as enemies make the hex unreachable) - local unit_in_way = wesnoth.get_unit(l[1], l[2]) - if unit_in_way and (unit_in_way ~= u) then + -- Add a small penalty for hexes occupied by an allied unit + local unit_in_way = wesnoth.get_unit(loc[1], loc[2]) + if unit_in_way and (unit_in_way ~= unit) then rating = rating - 0.01 end if (rating > max_rating) then max_rating = rating - closest_hex, best_unit = l, u - best_path = path + closest_hex, best_unit, best_path = loc, unit, path end end end end - --print(best_unit.id, best_unit.x, best_unit.y, closest_hex[1], closest_hex[2], max_rating) -- If 'unique_goals' is set, mark this location as being taken if cfg.unique_goals then @@ -181,8 +173,8 @@ function ca_goto:execution(ai, cfg, self) -- If any of the non-standard path finding options were used, -- we need to pick the farthest reachable hex along that path - -- For simplicity, we simply do it for all kinds of pathfinding here, - -- rather than using ai_helper.next_hop for the standard + -- For simplicity, we do it for all types of pathfinding here, + -- rather than using ai_helper.next_hop for standard pathfinding -- Also, straight-line does not produce a path, so we do that first if not best_path then best_path = wesnoth.find_path(best_unit, closest_hex[1], closest_hex[2]) @@ -202,43 +194,33 @@ function ca_goto:execution(ai, cfg, self) end end - if closest_hex then - AH.checked_move_full(ai, best_unit, closest_hex[1], closest_hex[2]) - else - AH.checked_stopunit_moves(ai, best_unit) - end + AH.checked_move_full(ai, best_unit, closest_hex[1], closest_hex[2]) if (not best_unit) or (not best_unit.valid) then return end -- If release_unit_at_goal= or release_all_units_at_goal= key is set: -- Check if the unit made it to one of the goal hexes - -- This needs to be done for the original goal hexes, not checking the SLF again, + -- This needs to be done for the original goal hexes, not by checking the SLF again, -- as that might have changed based on the new situation on the map if cfg.release_unit_at_goal or cfg.release_all_units_at_goal then - local unit_at_goal = false - for i,l in ipairs(locs) do - if (best_unit.x == l[1]) and (best_unit.y == l[2]) then - unit_at_goal = true + local is_unit_at_goal = false + for _,loc in ipairs(locs) do + if (best_unit.x == loc[1]) and (best_unit.y == loc[2]) then + is_unit_at_goal = true break end end - -- If a unit was found, mark either it or all units as released - -- Needs to be stored persistently in self.data meaning: - -- 1. Needs to be in WML table format - -- 2. Keys cannot contain certain characters -> everything potentially user-defined needs to be in values - if unit_at_goal then + if is_unit_at_goal then if cfg.release_unit_at_goal then MAIUV.set_mai_unit_variables(best_unit, cfg.ai_id, { release = true }) end if cfg.release_all_units_at_goal then - --print("Releasing all units") MAISD.insert_mai_self_data(self.data, cfg.ai_id, { release_all = true }) end end end - -- And some cleanup self.data.GO_units, self.data.GO_locs = nil, nil end