Skip to content
This repository has been archived by the owner on Nov 21, 2017. It is now read-only.

Commit

Permalink
Optimize danger cache calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
Afforess committed Mar 31, 2016
1 parent 372f05a commit cae5252
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 191 deletions.
10 changes: 7 additions & 3 deletions libs/ai/attack_plan.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ function attack_plan.tick(attack_data)
if attack_data.unit_group and not attack_data.wait_for_attack then
if attack_data.unit_group.valid then
attack_data.attack_in_progress = attack_data.attack_in_progress + 1
--TODO: track state and stop attacking locations that never generate attack state of 2 or 3 (1 -> 4 == never reached target).
if attack_data.attack_in_progress % 60 == 0 then
Logger.log("Unit group attack at (" .. serpent.line(attack_data.region_key, {comment = false}) .. ") in progress, state: " .. attack_data.unit_group.state)
end
else
attack_data.completed = true
Logger.log("Took " .. attack_data.attack_in_progress .. " ticks for the unit group to become invalid (attack complete)")
Expand Down Expand Up @@ -103,7 +107,7 @@ function attack_plan.coordinate_biters(attack_data)
attack_data.attack_in_progress = 0
local command = {type = defines.command.attack_area, destination = attack_data.target_position, radius = 16, distraction = defines.distraction.by_damage}

if game.evolution_factor > 0.5 and #enemy_units < 20 then
if game.evolution_factor > 0.5 and #enemy_units < 20 and math.random() < 0.5 then
local target_pos = attack_data.target_position
local half_way_pos = { x = (safe_pos.x + target_pos.x) / 2, y = (safe_pos.y + target_pos.y) / 2}
local safe_base_pos = surface.find_non_colliding_position("behemoth-spitter", half_way_pos, 16, 0.5)
Expand All @@ -118,6 +122,6 @@ function attack_plan.coordinate_biters(attack_data)
unit_group.start_moving()
end

function attack_plan.new(surface_name, position, biter_base)
return { position = position, surface_name = surface_name, biter_base = biter_base, completed = false }
function attack_plan.new(surface_name, position, region_key, biter_base)
return { position = position, surface_name = surface_name, region_key = region_key, biter_base = biter_base, completed = false }
end
152 changes: 84 additions & 68 deletions libs/map.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ function Map.new()
if not global.visited_regions then global.visited_regions = {} end
-- list of regions with biter or spitter spawners in them
if not global.enemy_regions then global.enemy_regions = {} end

if not global.attack_plans then global.attack_plans = {} end


if not global.iteration_phase then global.iteration_phase = 1 end

global.enemyRegions = nil
global.powerShorts = nil
global.powerLineTargets = nil
Expand All @@ -28,32 +30,35 @@ function Map.new()
global.enemyRegionQueue = nil
global.foo = nil
global.bar = nil

if not global.migrated_keys then
global.migrated_keys = true

local region_queue = {}
for _, region_data in pairs(global.region_queue) do
table.insert(region_queue, region.region_key(region_data))
end
global.region_queue = region_queue

local visited_regions = {}
for _, region_data in pairs(global.visited_regions) do
visited_regions[region.region_key(region_data)] = true
end
global.visited_regions = visited_regions

local enemy_regions = {}
for _, region_data in pairs(global.enemy_regions) do
table.insert(enemy_regions, region.region_key(region_data))
end
global.enemy_regions = enemy_regions

Logger.log("Migrated reqion queue structures")
end



for _, region_data in pairs(global.regions) do
region.migrate_regions(region_data)
end

local Map = {}

function Map:tick()
Expand Down Expand Up @@ -84,10 +89,10 @@ function Map.new()
if #region_data.enemy_bases > 0 then
region_attack_plans = {}
for _, base in pairs(region_data.enemy_bases) do
local plan = attack_plan.new(region_data.surface_name, base.position, base)
local plan = attack_plan.new(region_data.surface_name, base.position, region.region_key(region_data), base)
table.insert(region_attack_plans, plan)
end

Logger.log("Created new region attack plans (" .. plan_key .. "): " .. serpent.line(#region_attack_plans))
global.attack_plans[plan_key] = region_attack_plans
end
Expand All @@ -100,17 +105,17 @@ function Map.new()
frequency = 3600
end

if (game.tick % frequency == 0) then
if #global.enemy_regions == 0 then
Logger.log("No enemy regions found.")
else
if (game.tick % frequency == 0) then
if #global.enemy_regions == 0 then
Logger.log("No enemy regions found.")
else
Logger.log("Current enemy regions: " .. #global.enemy_regions)
local enemy_region_key = table.remove(global.enemy_regions, 1)
local enemy_region = global.regions[enemy_region_key]

Logger.log("")
Logger.log("Checking enemy region: " .. region.tostring(enemy_region))
if region.update_biter_base_locations(enemy_region) and region.any_potential_targets(enemy_region, 16) then
if region.update_biter_base_locations(enemy_region) and region.any_potential_targets(enemy_region, 16) then
-- add back to the end of the list
table.insert(global.enemy_regions, enemy_region_key)

Expand All @@ -119,60 +124,71 @@ function Map.new()
end
Logger.log("Updating enemy region ai: " .. region.tostring(enemy_region))
self:update_region_ai(enemy_region)
end
end
Logger.log("Number of enemy regions: " .. #global.enemy_regions)
Logger.log("")

end
end
end
end
end

function Map:iterate_map()
if (game.tick % 120 == 0) then
local region_data = self:next_region()

region.update_player_target_cache(region_data)
region.update_danger_cache(region_data)

Logger.log("Iterating map, region: " .. region.tostring(region_data))
if not self:is_enemy_region(region_data) and (region.update_biter_base_locations(region_data) and region.any_potential_targets(region_data, 16)) then
Logger.log("Found enemy region: " .. region.tostring(region_data))
table.insert(global.enemy_regions, region.region_key(region_data))
end
end
if (game.tick % 90 == 0) then
local num_turrets = danger_cache.num_turrets()
local total_phases = num_turrets + 1
Logger.log("Iteration phase: " .. global.iteration_phase .. ", Total Phases: " .. total_phases)
if global.iteration_phase == total_phases then
global.iteration_phase = 1
local region_data = self:next_region(true)
region.update_player_target_cache(region_data)

Logger.log("Iterating map, region: " .. region.tostring(region_data))
if not self:is_enemy_region(region_data) and (region.update_biter_base_locations(region_data) and region.any_potential_targets(region_data, 16)) then
Logger.log("Found enemy region: " .. region.tostring(region_data))
table.insert(global.enemy_regions, region.region_key(region_data))
end
else
local region_data = self:next_region(false)
region.update_danger_cache(region_data, global.iteration_phase)
global.iteration_phase = global.iteration_phase + 1
end
end
end

function Map:seed_initial_values()
Logger.log("Seeding initial region values")

-- reset lists
global.visited_regions = {}
global.region_queue = {}
-- reset lists
global.visited_regions = {}
global.region_queue = {}

for i = 1, #game.players do
if game.players[i].connected then
for i = 1, #game.players do
if game.players[i].connected then
self:add_partially_charted(region.lookup_region_from_position(game.players[i].surface, game.players[i].position))
end
end
table.insert(global.region_queue, region.lookup_region_key(game.surfaces.nauvis.name, 0, 0))
end
end
table.insert(global.region_queue, region.lookup_region_key(game.surfaces.nauvis.name, 0, 0))
end

function Map:next_region()
if #global.region_queue == 0 then
function Map:next_region(remove)
if #global.region_queue == 0 then
self:seed_initial_values()
end
end

local next_region_key = table.remove(global.region_queue, 1)
local next_region_key = global.region_queue[1]
local next_region = global.regions[next_region_key]
if remove then
table.remove(global.region_queue, 1)

self:add_partially_charted(region.offset(next_region, 1, 0))
self:add_partially_charted(region.offset(next_region, -1, 0))
self:add_partially_charted(region.offset(next_region, 0, 1))
self:add_partially_charted(region.offset(next_region, 0, -1))
self:add_partially_charted(region.offset(next_region, 1, 0))
self:add_partially_charted(region.offset(next_region, -1, 0))
self:add_partially_charted(region.offset(next_region, 0, 1))
self:add_partially_charted(region.offset(next_region, 0, -1))

global.visited_regions[region.region_key(next_region)] = true
global.visited_regions[region.region_key(next_region)] = true
end

return next_region
return next_region
end

function Map:is_already_iterated(region_data)
Expand All @@ -181,33 +197,33 @@ function Map.new()

function Map:is_pending_iteration(region_data)
local region_key = region.region_key(region_data)
for i = 1, #global.region_queue do
if (global.region_queue[i] == region_key) then
return true
end
end
return false
for i = 1, #global.region_queue do
if (global.region_queue[i] == region_key) then
return true
end
end
return false
end

function Map:is_enemy_region(region_data)
local region_key = region.region_key(region_data)
for _, enemy_region_key in pairs(global.enemy_regions) do
if region_key == enemy_region_key then
return true
end
end
return false
for _, enemy_region_key in pairs(global.enemy_regions) do
if region_key == enemy_region_key then
return true
end
end
return false
end

function Map:add_partially_charted(region_data)
if not (self:is_already_iterated(region_data) or self:is_pending_iteration(region_data)) then
if region.is_partially_charted(region_data) then
table.insert(global.region_queue, region.region_key(region_data))
else
-- don't recheck if partially charted over and over in the future, just add to 'visited list'
if not (self:is_already_iterated(region_data) or self:is_pending_iteration(region_data)) then
if region.is_partially_charted(region_data) then
table.insert(global.region_queue, region.region_key(region_data))
else
-- don't recheck if partially charted over and over in the future, just add to 'visited list'
global.visited_regions[region.region_key(region_data)] = true
end
end
end
end
end
return Map
end
Expand Down
Loading

0 comments on commit cae5252

Please sign in to comment.