--- Heuristic functions for search algorithms.
-- A distance heuristic
-- provides an *estimate of the optimal distance cost* from a given location to a target.
-- As such, it guides the pathfinder to the goal, helping it to decide which route is the best.
--
-- This script holds the definition of some built-in heuristics available through jumper.
--
-- Distance functions are internally used by the `pathfinder` to evaluate the optimal path
-- from the start location to the goal. These functions share the same prototype:
-- local function myHeuristic(nodeA, nodeB)
-- -- function body
-- end
-- Jumper features some built-in distance heuristics, namely `MANHATTAN`, `EUCLIDIAN`, `DIAGONAL`, `CARDINTCARD`.
-- You can also supply your own heuristic function, following the same template as above.
local abs = math.abs
local sqrt = math.sqrt
local sqrt2 = sqrt(2)
local max, min = math.max, math.min
local Heuristics = {}
--- Manhattan distance.
--
This heuristic is the default one being used by the `pathfinder` object.
--
Evaluates as distance = |dx|+|dy|
-- @class function
-- @tparam node nodeA a node
-- @tparam node nodeB another node
-- @treturn number the distance from __nodeA__ to __nodeB__
-- @usage
-- -- First method
-- pathfinder:setHeuristic('MANHATTAN')
-- -- Second method
-- local Distance = require ('jumper.core.heuristics')
-- pathfinder:setHeuristic(Distance.MANHATTAN)
function Heuristics.MANHATTAN(nodeA, nodeB)
local dx = abs(nodeA._x - nodeB._x)
local dy = abs(nodeA._y - nodeB._y)
local dz = abs(nodeA._z - nodeB._z)
return (dx + dy + dz)
end
--- Euclidian distance.
--
Evaluates as distance = squareRoot(dx*dx+dy*dy)
-- @class function
-- @tparam node nodeA a node
-- @tparam node nodeB another node
-- @treturn number the distance from __nodeA__ to __nodeB__
-- @usage
-- -- First method
-- pathfinder:setHeuristic('EUCLIDIAN')
-- -- Second method
-- local Distance = require ('jumper.core.heuristics')
-- pathfinder:setHeuristic(Distance.EUCLIDIAN)
function Heuristics.EUCLIDIAN(nodeA, nodeB)
local dx = nodeA._x - nodeB._x
local dy = nodeA._y - nodeB._y
local dz = nodeA._z - nodeB._z
return sqrt(dx*dx+dy*dy+dz*dz)
end
--- Diagonal distance.
--
Evaluates as distance = max(|dx|, abs|dy|)
-- @class function
-- @tparam node nodeA a node
-- @tparam node nodeB another node
-- @treturn number the distance from __nodeA__ to __nodeB__
-- @usage
-- -- First method
-- pathfinder:setHeuristic('DIAGONAL')
-- -- Second method
-- local Distance = require ('jumper.core.heuristics')
-- pathfinder:setHeuristic(Distance.DIAGONAL)
function Heuristics.DIAGONAL(nodeA, nodeB)
local dx = abs(nodeA._x - nodeB._x)
local dy = abs(nodeA._y - nodeB._y)
return max(dx,dy)
end
--- Cardinal/Intercardinal distance.
--
Evaluates as distance = min(dx, dy)*squareRoot(2) + max(dx, dy) - min(dx, dy)
-- @class function
-- @tparam node nodeA a node
-- @tparam node nodeB another node
-- @treturn number the distance from __nodeA__ to __nodeB__
-- @usage
-- -- First method
-- pathfinder:setHeuristic('CARDINTCARD')
-- -- Second method
-- local Distance = require ('jumper.core.heuristics')
-- pathfinder:setHeuristic(Distance.CARDINTCARD)
function Heuristics.CARDINTCARD(nodeA, nodeB)
local dx = abs(nodeA._x - nodeB._x)
local dy = abs(nodeA._y - nodeB._y)
return min(dx,dy) * sqrt2 + max(dx,dy) - min(dx,dy)
end
return Heuristics