remove pathfinder (is now separate mod/core feature)

This commit is contained in:
sapier 2013-03-19 20:22:56 +00:00
parent 5dba79a4f1
commit 7c72544598
3 changed files with 0 additions and 940 deletions

View File

@ -78,8 +78,6 @@ dofile (mobf_modpath .. "/mob_state.lua")
dofile (mobf_modpath .. "/inventory.lua")
dofile (mobf_modpath .. "/mob_preserve.lua")
dofile (mobf_modpath .. "/path.lua")
dofile (mobf_modpath .. "/pathfinder_v1/debug_path.lua")
dofile (mobf_modpath .. "/pathfinder_v1/shortest_path.lua")
--include spawning support
dofile (mobf_modpath .. "/spawning.lua")

View File

@ -1,276 +0,0 @@
function debug_print_g_pos(g_pos)
print("DIRS:")
print(" " .. mobf_fixed_size_string(g_pos.zp_weight,3) .. " ")
print(mobf_fixed_size_string(g_pos.xm_weight,3) .. " " .. mobf_fixed_size_string(g_pos.xp_weight,3))
print(" " .. mobf_fixed_size_string(g_pos.zm_weight,3) .. " ")
end
minetest.register_chatcommand("find_path",
{
params = "pos1, pos2",
description = "find a path between pos1 and pos2" ,
privs = {},
func = function(name,param)
--evaluate param
print("name: " .. name .. " param: " .. dump(param))
local parameters = param:split(" ")
if #parameters < 2 then
print("invalid parameter count")
return
end
local pos1_strings = parameters[1]:split(",")
local pos2_strings = parameters[2]:split(",")
if #pos1_strings ~= 3 then
print("pos1 invalid")
return
end
if #pos2_strings ~= 3 then
print("pos2 invalid")
return
end
local pos1 = {
x=tonumber(pos1_strings[1]),
y=tonumber(pos1_strings[2]),
z=tonumber(pos1_strings[3])
}
local pos2 = {
x=tonumber(pos2_strings[1]),
y=tonumber(pos2_strings[2]),
z=tonumber(pos2_strings[3])
}
local path = find_path(pos1,pos2,1,2,1,5,parameters[3])
if path ~= nil then
for i=1,#path,1 do
print(mobf_fixed_size_string(i,2) .. ": " ..printpos(path[i]))
end
end
print("Done!")
end,
})
function debug_print_area_paths(data)
print("Pathlength:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
if data.grid[i][j].istarget then
line = line .. " T "
else
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].pathlength),3)
.. " "
end
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_zp_weight(data)
print("ZP weight:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].zp_weight),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_zm_weight(data)
print("ZM weight:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].zm_weight),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_xp_weight(data)
print("XP weight:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].xp_weight),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_xm_weight(data)
print("XM weight:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].xm_weight),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_height(data)
print("height:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].pos.y),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end
function debug_print_path(data)
print("path:")
local head = "" .. mobf_fixed_size_string("",3) .. " "
local head2 = "-----"
for x=1,#data.grid[1],1 do
head = head .. " " ..
mobf_fixed_size_string(tostring(x),3)
.. " "
head2 = head2 .. "-----"
end
print(head)
print(head2)
for i=1,#data.grid,1 do
local line = "" .. mobf_fixed_size_string(tostring(i),3) .. ": "
for j=1,#data.grid[i],1 do
if data.grid[i][j].pathlength ~= nil then
line = line .. " " ..
mobf_fixed_size_string(tostring(data.grid[i][j].iselement),3)
.. " "
else
line = line .. " nil "
end
end
print(line)
end
print("")
end

View File

@ -1,662 +0,0 @@
-------------------------------------------------------------------------------
-- Mob Framework Settings Mod by Sapier
--
-- You may copy, use, modify or do nearly anything except removing this
-- copyright notice.
-- And of course you are NOT allow to pretend you have written it.
--
--! @file path.lua
--! @brief path support for mobf
--! @copyright Sapier
--! @author Sapier
--! @date 2013-02-20
--
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
function gridat(grid,pos)
mobf_assert_backtrace(grid ~= nil)
mobf_assert_backtrace(pos ~= nil)
mobf_assert_backtrace(pos.x ~= nil)
mobf_assert_backtrace(pos.z ~= nil)
if grid[pos.x] == nil then
return nil
end
return grid[pos.x][pos.z]
end
function realpos(data,ipos)
return {
x= data.limits.x.min + ipos.x,
z= data.limits.z.min + ipos.z,
y= ipos.y
}
end
function getipos(data,pos)
--todo check pos to be within limits
return {
x= pos.x - data.limits.x.min,
z= pos.z - data.limits.z.min,
y= pos.y
}
end
function remdir(_table,dir)
for i=1,#_table,1 do
if path_samepos(_table[i],dir) then
table.remove(_table,i)
return
end
end
end
function v2add(v1,v2)
return {
x= v1.x + v2.x,
z= v1.z + v2.z
}
end
function v2inv(v)
return {
x = v.x * -1,
z = v.z * -1
}
end
-------------------------------------------------------------------------------
-- name: path_samepos(pos1,pos2)
--
--! @brief check if two positions are identical ignoring y value
--
--! @param pos1 first position
--! @param pos2 second position
--
--! @return true/false
-------------------------------------------------------------------------------
function path_samepos(pos1,pos2)
if pos1 == nil or
pos2 == nil then
return false
end
if pos1.x == pos2.x and
pos1.z == pos2.z then
return true
end
return false
end
-------------------------------------------------------------------------------
-- name: get_cost(g_pos,dir)
--
--! @brief access weight of a movement in direction
--
--! @param g_pos position to start movement
--! @param dir direction to move to
--
--! @return cost of movement or nil
-------------------------------------------------------------------------------
function get_cost(g_pos,dir)
mobf_assert_backtrace(dir ~= nil)
mobf_assert_backtrace(g_pos ~= nil)
if dir.x > 0 then
return g_pos.xp_weight
end
if dir.x < 0 then
return g_pos.xm_weight
end
if dir.z > 0 then
return g_pos.zp_weight
end
if dir.z < 0 then
return g_pos.zm_weight
end
return nil
end
-------------------------------------------------------------------------------
-- name: find_shortest_path(pos1,pos2,maxdrop,maxjump,minheight,maxsurrounding)
--
--! @brief find shortest path from pos1 to pos2
--
--! @param pos1 startpos
--! @param pos2 endpos
--! @param maxdrop maximum height to drop down
--! @param maxjump maximum height to jump up
--! @param minheight minimum height to pass (UNUSED)
--! @param maxsurrounding maximum area around positions (not between) to consider
--! @param algo algorithm to use
--
--! @return path from pos1 -> pos2 or nil
-------------------------------------------------------------------------------
function find_path(pos1,pos2,maxdrop,maxjump,minheight,maxsurrounding,algo)
local total_starttime = mobf_get_time_ms()
--prepare context
local data = create_context(pos1,pos2,maxdrop,maxjump,minheight,maxsurrounding)
--build 2d weight map
build_cost_map(data)
mobf_warn_long_fct(total_starttime,"build weight map","pathfind")
local path_starttime = mobf_get_time_ms()
--debug_print_xp_weight(data)
--debug_print_xm_weight(data)
--debug_print_zp_weight(data)
--debug_print_zm_weight(data)
--debug_print_height(data)
--mark start and end point
print("MOBF: pathfinder v1 mark start and stop")
gridat(data.grid,getipos(data,pos2)).istarget = true
gridat(data.grid,getipos(data,pos1)).pathlength = 0
local lengthfunc = nil
--debug_print_area_paths(data)
if algo == "short" then
lengthfunc = update_all_lengths
else
lengthfunc = update_lengths_heuristic
end
print("MOBF: calculate path lenght")
--mark all positions with their pathlenght and check if there is at least
--one path to target
if lengthfunc(data,getipos(data,pos1),nil,0,0) then
mobf_warn_long_fct(path_starttime,"find path","pathfind")
debug_print_area_paths(data)
local fullpath = {}
build_path(data,fullpath,getipos(data,pos2))
debug_print_path(data)
--remvoe all nodes wich are on a line of sight
local optimized_path = {}
local startpos = 1
table.insert(optimized_path,gridat(data.grid,fullpath[1]).pos)
for i=2,#fullpath, 1 do
--print("MOBF: check for line of sight " ..
-- printpos(gridat(data.grid,fullpath[startpos]).pos) .. "-->" ..
-- printpos(gridat(data.grid,fullpath[i]).pos))
if not mobf_line_of_sight(
gridat(data.grid,fullpath[startpos]).pos,
gridat(data.grid,fullpath[i]).pos) then
table.insert(optimized_path,gridat(data.grid,fullpath[i-1]).pos)
startpos = i-1
end
end
table.insert(optimized_path,gridat(data.grid,fullpath[#fullpath]).pos)
mobf_warn_long_fct(total_starttime,"complete","pathfind")
local endtime = mobf_get_time_ms()
print("MOBF: took: " .. (endtime - total_starttime) .. " ms starttime: " .. total_starttime .. " endtime: " .. endtime)
return optimized_path;
end
mobf_warn_long_fct(path_starttime,"find path","pathfind")
mobf_warn_long_fct(total_starttime,"complete","pathfind")
debug_print_area_paths(data)
return nil
end
-------------------------------------------------------------------------------
-- name: create_context(pos1,pos2,maxdrop,maxjump,minheight,maxsurrounding)
--
--! @brief create a contect containing all data relevant for calculation
--
--! @param pos1 startpos
--! @param pos2 endpos
--! @param maxdrop maximum height to drop down
--! @param maxjump maximum height to jump up
--! @param minheight minimum height to pass (UNUSED)
--! @param maxsurrounding maximum area around positions (not between) to consider
--
--! @return context with all validated data or nil
-------------------------------------------------------------------------------
function create_context(pos1,pos2,maxdrop,maxjump,minheight,maxsurrounding)
print("MOBF: create context")
local data = {}
data.min = {
x = MIN(pos1.x,pos2.x),
z = MIN(pos1.z,pos2.z)
}
data.max = {
x = MAX(pos1.x,pos2.x),
z = MAX(pos1.z,pos2.z)
}
data.limits = {
x = {
min = data.min.x - maxsurrounding,
max = data.max.x + maxsurrounding
},
z = {
min = data.min.z - maxsurrounding,
max = data.max.z + maxsurrounding
}
}
data.maxjump = maxjump
data.maxdrop = maxdrop
data.minheight = minheight
data.miny = MIN(pos1.y,pos2.y) - maxsurrounding
data.maxy = MAX(pos1.y,pos2.y) + maxsurrounding
data.min_target_distance = nil
data.source = pos1
data.target = pos2
return data
end
-------------------------------------------------------------------------------
-- name: build_cost_map(data)
--
--! @brief build map containing all movement costs
--
--! @param data data to operate on
--
-------------------------------------------------------------------------------
function build_cost_map(data)
print("MOBF: calculate cost of movement for whole considered area")
data.grid = {}
for i=1, data.limits.x.max - data.limits.x.min, 1 do
data.grid[i] = {}
for j=1, data.limits.z.max - data.limits.z.min, 1 do
local ipos = {x=i,z=j}
local pos = realpos(data,ipos)
pos.y = mobf_get_surface(pos.x,pos.z, data.miny, data.maxy)
--print("MOBF: pathfinder v1 calculating weights for " .. printpos(ipos) .. " " .. printpos(pos))
local toadd = {
pos = pos,
pathlength = -1,
}
data.grid[i][j] = toadd
if pos.y ~= nil then
--data.node = minetest.env:get_node(pos)
toadd.xp_weight = calc_cost(data,ipos,{x= 1,z= 0})
toadd.xm_weight = calc_cost(data,ipos,{x=-1,z= 0})
toadd.zp_weight = calc_cost(data,ipos,{x= 0,z= 1})
toadd.zm_weight = calc_cost(data,ipos,{x= 0,z=-1})
end
--print("\t xp : " .. dump(data.grid[i][j].xp_weight))
--print("\t xm : " .. dump(data.grid[i][j].xm_weight))
--print("\t zp : " .. dump(data.grid[i][j].zp_weight))
--print("\t zm : " .. dump(data.grid[i][j].zm_weight))
--print("\t path: " .. dump(gridat(data.grid,{x=i,z=j}).pathlength))
end
end
end
-------------------------------------------------------------------------------
-- name: calc_cost(data,ipos,dir)
--
--! @brief calculate weight for transition from ipos in direction dir
--
--! @param data data to operate on
--! @param ipos index position to set weight for
--! @param dir direction to move
--! @return weight of transition
-------------------------------------------------------------------------------
function calc_cost(data,ipos,dir)
local g_pos = gridat(data.grid,ipos)
local ipos2 = {
x= ipos.x + dir.x,
z= ipos.z + dir.z
}
--not within checked area
if ipos2.x <= 0 or
ipos2.z <= 0 then
--print("\t " .. printpos(dir) .. " out of area negative")
return nil
end
local pos2 = realpos(data,ipos2)
--not within checked area
if pos2.x > data.limits.x.max or
pos2.z > data.limits.z.max then
--print("\t " .. printpos(dir) .. " out of area positive")
return nil
end
local y_surface = nil
local g_pos2 = gridat(data.grid,ipos2)
if g_pos2 ~= nil then
y_surface = g_pos2.pos.y
else
y_surface = mobf_get_surface(pos2.x,pos2.z, data.miny, data.maxy)
end
--print("\t " .. printpos(dir) .. " oldy = " .. g_pos.pos.y .. " new y = " .. dump(y_surface))
if y_surface == nil then
return nil
end
--not same level
if g_pos.pos.y ~= y_surface then
if g_pos.pos.y > y_surface then
local diff = g_pos.pos.y - y_surface
if diff > data.maxdrop then
return nil
end
if diff > 1 then
return 3
end
return 2
else
local diff = y_surface - g_pos.pos.y
if diff > data.maxjump then
return nil
end
return 2
end
end
--same level
return 1
end
-------------------------------------------------------------------------------
-- name: build_path(data,shortestpath,ipos)
--
--! @brief build list containing shortest path
--
--! @param data data to operate on
--! @param list to store path
--! @param current pos
--
-------------------------------------------------------------------------------
function build_path(data,shortestpath,ipos)
mobf_assert_backtrace(data ~= nil)
mobf_assert_backtrace(shortestpath ~= nil)
local g_pos = gridat(data.grid,ipos)
g_pos.iselement = 1
mobf_assert_backtrace(g_pos ~= nil)
--abort if source has been reached
if g_pos.pathlength == 0 then
table.insert(shortestpath,ipos)
return
end
mobf_assert_backtrace(g_pos.srcdir ~= nil)
local newpos = {
x=ipos.x + g_pos.srcdir.x,
z=ipos.z + g_pos.srcdir.z
}
build_path(data,shortestpath,newpos)
table.insert(shortestpath,newpos)
end
-------------------------------------------------------------------------------
-- name: update_all_lengths(data,ipos,srcdir,cur_length)
--
--! @brief length for a new pos
--
--! @param data data to operate on
--! @param ipos index position to set weight for
--! @param dir direction to move
--! @return weight of transition
-------------------------------------------------------------------------------
function update_all_lengths(data,ipos,srcdir,cur_length,lvl)
local g_pos = gridat(data.grid,ipos)
lvl = lvl +1
-- check if target reached
if g_pos.istarget then
if g_pos.pathlength < 0 or
g_pos.pathlength > cur_length then
g_pos.pathlength = cur_length
g_pos.srcdir = srcdir
data.min_target_distance = cur_length
end
return true
end
local retval = false
local directions = {}
table.insert(directions,{x= 1,z= 0})
table.insert(directions,{x=-1,z= 0})
table.insert(directions,{x= 0,z= 1})
table.insert(directions,{x= 0,z=-1})
for i=1,#directions,1 do
if not path_samepos(directions[i],srcdir) then
local ipos2 = v2add(ipos,directions[i])
local g_pos2 = gridat(data.grid,ipos2)
--print("(" .. lvl .. ") MOBF: check for update " ..
-- printpos(ipos) .. "-->" .. printpos(ipos2) ..
-- " cur_length: " .. dump(cur_length))
--found better way to g_pos2
if g_pos2 ~= nil then
local addonweight = get_cost(g_pos,directions[i])
if addonweight ~= nil then
local newlength = cur_length + addonweight
if data.min_target_distance ~= nil and
data.min_target_distance < newlength then
return false
end
if g_pos2.pathlength < 0 or
g_pos2.pathlength > newlength then
--print("\t(" .. lvl .. ") updating " .. printpos(directions[i]) .. " weight: " .. dump(addonweight))
g_pos2.pathlength = newlength
g_pos2.srcdir = v2inv(directions[i])
--print("\t(" .. lvl .. ") set lenght at: " .. printpos(directions[i]) .. " to " .. dump(g_pos2.pathlength))
if update_all_lengths(data,ipos2,v2inv(directions[i]),
newlength,lvl) or retval == true then
retval = true
end
else
--print("\t(" .. lvl .. ") not updating " ..
-- printpos(directions[i]) ..
-- " oldlength: " .. dump(g_pos2.pathlength) ..
-- " newlenght: " .. newpath)
end
else
--print("\t(" .. lvl .. ") not updating " .. printpos(directions[i]) .. " weight: " .. dump(addonweight))
--debug_print_g_pos(g_pos)
end
else
--print("\t(" .. lvl .. ") not updating " .. printpos(directions[i]))
end
end
end
return retval
end
-------------------------------------------------------------------------------
-- name: update_lengths_heuristic(data,ipos,srcdir,cur_length)
--
--! @brief length for a new pos
--
--! @param data data to operate on
--! @param ipos index position to set weight for
--! @param dir direction to move
--! @return weight of transition
-------------------------------------------------------------------------------
function update_lengths_heuristic(data,ipos,srcdir,cur_length,lvl)
local g_pos = gridat(data.grid,ipos)
lvl = lvl +1
-- check if target reached
if g_pos.istarget then
if g_pos.pathlength < 0 or
g_pos.pathlength > cur_length then
g_pos.pathlength = cur_length
g_pos.srcdir = srcdir
data.min_target_distance = cur_length
end
return true
end
local retval = false
local continue = true
local directions = {}
table.insert(directions,{x= 1,z= 0})
table.insert(directions,{x=-1,z= 0})
table.insert(directions,{x= 0,z= 1})
table.insert(directions,{x= 0,z=-1})
remdir(directions,srcdir)
while retval == false and
continue do
local tocheck = get_dir_heuristic(data,g_pos,directions)
if tocheck ~= nil then
remdir(directions,tocheck)
local ipos2 = v2add(ipos,tocheck)
local g_pos2 = gridat(data.grid,ipos2)
if g_pos2 ~= nil then
local addonweight = get_cost(g_pos,tocheck)
if addonweight ~= nil then
local length_new = cur_length + addonweight
if data.min_target_distance ~= nil and
data.min_target_distance < length_new then
return false
end
if g_pos2.pathlength < 0 or
g_pos2.pathlength > length_new then
--print("\t(" .. lvl .. ") updating " .. printpos(directions[i]) .. " weight: " .. dump(addonweight))
g_pos2.pathlength = length_new
g_pos2.srcdir = v2inv(tocheck)
--print("\t(" .. lvl .. ") set lenght at: " .. printpos(directions[i]) .. " to " .. dump(g_pos2.pathlength))
retval = update_lengths_heuristic(data,ipos2,
v2inv(tocheck),length_new,lvl)
else
--print("\t(" .. lvl .. ") not updating " ..
-- printpos(directions[i]) ..
-- " oldlength: " .. dump(g_pos2.pathlength) ..
-- " newlenght: " .. newpath)
end
else
--print("\t(" .. lvl .. ") not updating " .. printpos(directions[i]) .. " weight: " .. dump(addonweight))
--debug_print_g_pos(g_pos)
end
else
--print("\t(" .. lvl .. ") not updating " .. printpos(directions[i]))
end
else
continue = false
end
end
return retval
end
-------------------------------------------------------------------------------
-- name: get_manhattandistance2(pos1,pos2)
--
--! @brief calculate 2D manhattan distance between two points
--
--! @param pos1 source pos
--! @param pos2 destination pos
--
--! @return manhattan distance
-------------------------------------------------------------------------------
function get_manhattandistance2(pos1,pos2)
min_x = MIN(pos1.x,pos2.x)
max_x = MAX(pos1.x,pos2.x)
min_z = MIN(pos1.z,pos2.z)
max_z = MAX(pos1.z,pos2.z)
return (max_x - min_x) + (max_z - min_z)
end
-------------------------------------------------------------------------------
-- name: get_dir_heuristic(data,g_pos,directions)
--
--! @brief length for a new pos
--
--! @param data data to operate on
--! @param g_pos source position
--! @param directions available not checked directions
--
--! @return direction to check or nil
-------------------------------------------------------------------------------
function get_dir_heuristic(data,g_pos,directions)
local minscore = -1
local retdir = nil
local srcpos = g_pos.pos
for i=1,#directions,1 do
pos1 = {
x= srcpos.x + directions[i].x,
z= srcpos.z + directions[i].z
}
local cur_manhattan = get_manhattandistance2(pos1,data.target)
local cost = get_cost(g_pos,directions[i])
if cost ~= nil then
local score = cost + cur_manhattan
if minscore < 0 or
score < minscore then
minscore = score
retdir = directions[i]
end
end
end
return retdir
end