optimise [random_placement]

the cases distance=0 and distance = -1 now dont loop thougth all
possible locations anymore when removing a used location.
This commit is contained in:
gfgtdf 2016-05-20 14:25:20 +02:00
parent 2ba7ad5c43
commit 5de1d9b046

View file

@ -2,8 +2,6 @@ local helper = wesnoth.require "lua/helper.lua"
local utils = wesnoth.require "lua/wml-utils.lua"
wesnoth.wml_actions.random_placement = function(cfg)
local dist_le = nil
local parsed = helper.shallow_parsed(cfg)
-- TODO: In most cases this tag is used to place units, so maybe make include_borders=no the default for [filter_location]?
local filter = helper.get_child(parsed, "filter_location") or {}
@ -13,34 +11,7 @@ wesnoth.wml_actions.random_placement = function(cfg)
local variable = cfg.variable or helper.wml_error("[random_placement] missing required 'variable' attribute")
local allow_less = cfg.allow_less == true
local variable_previous = utils.start_var_scope(variable)
if distance < 0 then
-- optimisation for distance = -1
dist_le = function() return false end
elseif distance == 0 then
-- optimisation for distance = 0
dist_le = function(x1,y1,x2,y2) return x1 == x2 and y1 == y2 end
else
-- optimisation: cloasure is faster than string lookups.
local math_abs = math.abs
-- same effect as helper.distance_between(x1,y1,x2,y2) <= distance but faster.
dist_le = function(x1,y1,x2,y2)
local d_x = math_abs(x1-x2)
if d_x > distance then
return false
end
if d_x % 2 ~= 0 then
if x1 % 2 == 0 then
y2 = y2 - 0.5
else
y2 = y2 + 0.5
end
end
local d_y = math_abs(y1-y2)
return d_x + 2*d_y <= 2*distance
end
end
local math_abs = math.abs
local locs = wesnoth.get_locations(filter)
if type(num_items) == "string" then
num_items = math.floor(loadstring("local size = " .. #locs .. "; return " .. num_items)())
@ -61,11 +32,40 @@ wesnoth.wml_actions.random_placement = function(cfg)
wesnoth.set_variable(variable .. ".x", point[1])
wesnoth.set_variable(variable .. ".y", point[2])
wesnoth.set_variable(variable .. ".n", i)
for j = size, 1, -1 do
if dist_le(locs[j][1], locs[j][2], point[1], point[2]) then
if distance < 0 then
-- optimisation: nothing to do for distance < 0
elseif distance == 0 then
-- optimisation: for distance = 0 we just need to remove the element at index
-- optimisation: swapping elements and storing size in an extra variable is faster than table.remove(locs, j)
locs[index] = locs[size]
size = size - 1
else
-- the default case and the main reason why this was implemented.
for j = size, 1, -1 do
local x1 = locs[j][1]
local y1 = locs[j][2]
local x2 = point[1]
local y2 = point[2]
-- optimisation: same effect as "if helper.distance_between(x1,y1,x2,y2) <= distance then goto continue; end" but faster.
local d_x = math_abs(x1-x2)
if d_x > distance then
goto continue
end
if d_x % 2 ~= 0 then
if x1 % 2 == 0 then
y2 = y2 - 0.5
else
y2 = y2 + 0.5
end
end
local d_y = math_abs(y1-y2)
if d_x + 2*d_y > 2*distance then
goto continue
end
-- optimisation: swapping elements and storing size in an extra variable is faster than table.remove(locs, j)
locs[j] = locs[size]
size = size - 1
::continue::
end
end
wesnoth.wml_actions.command (command)