From 0336cdaa2a7d6f2a1b85c9ad3f83b8d6964dc3f5 Mon Sep 17 00:00:00 2001 From: blunty666 Date: Sat, 10 Dec 2016 09:03:48 +0000 Subject: [PATCH] Further work to align starNav and netNav functionality --- netNav/explore.lua | 10 +++--- netNav/netNav.lua | 42 +++++++++++------------ netNav/netNav_goto.lua | 21 +++++++++--- starNav/explore.lua | 72 ++++++++++++++++++++++++++++++++++++++++ starNav/starNav.lua | 44 +++++++++++++----------- starNav/starNav_goto.lua | 4 +-- 6 files changed, 139 insertions(+), 54 deletions(-) create mode 100644 starNav/explore.lua diff --git a/netNav/explore.lua b/netNav/explore.lua index ae1ade0..3a05333 100644 --- a/netNav/explore.lua +++ b/netNav/explore.lua @@ -20,9 +20,9 @@ if minZ > maxZ then minZ, maxZ = maxZ, minZ end -- LOAD NETNAV API if not netNav then - if not os.loadAPI("netNav") then - error("could not load starNav API") - end + if not os.loadAPI("netNav") then + error("could not load netNav API") + end end -- OPEN REDNET @@ -42,9 +42,7 @@ if type(mapName) ~= "string" then printError("mapName must be string") return end -if not netNav.getMap() then - netNav.setMap(mapName, 15) -end +netNav.setMap(mapName, 15) local exit = false local returning = false diff --git a/netNav/netNav.lua b/netNav/netNav.lua index 1577b25..91390ad 100644 --- a/netNav/netNav.lua +++ b/netNav/netNav.lua @@ -1,16 +1,13 @@ -if not remoteMap then - if not os.loadAPI("remoteMap") then - error("could not load remoteMap API") - end -end -if not aStar then - if not os.loadAPI("aStar") then - error("could not load aStar API") - end -end -if not location then - if not os.loadAPI("location") then - error("could not load location API") +local apis = { + "remoteMap", + "aStar", + "location", +} +for _ api in ipairs(apis) do + if not _G[api] then + if not os.loadAPI(api) then + error("could not load API: "..api) + end end end @@ -20,9 +17,10 @@ local SESSION_MAX_DISTANCE_DEFAULT = 32 local SESSION_COORD_CLEAR = 1 local SESSION_COORD_BLOCKED = 2 - +local SESSION_COORD_DISTANCE = math.huge local UPDATE_COORD_CLEAR = -1 local UPDATE_COORD_BLOCKED = 1 +local UPDATE_COORD_DISTANCE = 2 local sessionMidPoint local sessionMaxDistance @@ -33,18 +31,18 @@ local serverMap local function distanceFunc(a, b) local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(b) if aStar.distance(a, sessionMidPoint) > sessionMaxDistance then - return math.huge -- first coord is outside the search region + return SESSION_COORD_DISTANCE -- first coord is outside the search region elseif aStar.distance(b, sessionMidPoint) > sessionMaxDistance then - return math.huge -- second coord is outside the search region + return SESSION_COORD_DISTANCE -- second coord is outside the search region elseif sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then - return math.huge -- we have found one of these coords to be blocked during this session + return SESSION_COORD_DISTANCE -- we have found one of these coords to be blocked during this session elseif sessionMapA == SESSION_COORD_CLEAR and sessionMapB == SESSION_COORD_CLEAR then return aStar.distance(a, b) -- we have found both of these coords to be clear during this session else local serverMapA, serverMapB = serverMap:get(a), serverMap:get(b) if serverMapA or serverMapB then - serverMapA = serverMapA and 2^(serverMapA + 1) or 1 - serverMapB = serverMapB and 2^(serverMapB + 1) or 1 + serverMapA = serverMapA and UPDATE_COORD_DISTANCE^(serverMapA + 1) or 1 + serverMapB = serverMapB and UPDATE_COORD_DISTANCE^(serverMapB + 1) or 1 return math.max(serverMapA, serverMapB) -- the remote server map is indicating one of these coords may be blocked end end @@ -254,16 +252,16 @@ local function _goto(x, y, z, maxDistance) local goal = vector.new(tonumber(x), tonumber(y), tonumber(z)) serverMap:check() -- remove timed out data we have received from server - sessionMap = aStar.newMap() -- reset the sessionMap + sessionMap = aStar.newMap() -- reset the sessionMap sessionMidPoint = vector.new(math.floor((goal.x + position.x)/2), math.floor((goal.y + position.y)/2), math.floor((goal.z + position.z)/2)) sessionMaxDistance = (type(maxDistance) == "number" and maxDistance) or math.max(2*aStar.distance(sessionMidPoint, goal), SESSION_MAX_DISTANCE_DEFAULT) - + local path = aStar.compute(distanceFunc, position, goal) if not path then return false, "no known path to goal" end - + while not (exit or aStar.vectorEquals(position, goal)) do local movePos = table.remove(path) while not move(position, movePos) do diff --git a/netNav/netNav_goto.lua b/netNav/netNav_goto.lua index 7a15242..72de183 100644 --- a/netNav/netNav_goto.lua +++ b/netNav/netNav_goto.lua @@ -1,8 +1,9 @@ local function printUsage() print("Usage:") - print(fs.getName(shell.getRunningProgram()).." ") - print(" The name of the remoteMap to connect to and use.") + print(fs.getName(shell.getRunningProgram()).." <(optional)max_distance>") + print(" The name of the map to use.") print(" The GPS coordinates you want to go to.") + print("<(optional)max_distance> The farthest distance allowed to travel from start position.") end if not netNav then @@ -40,10 +41,22 @@ for i = 2, 4 do end end +local maxDistance +if tArgs[5] ~= nil then + if tonumber(tArgs[5]) then + print("setting max_distance to: ", tArgs[5]) + maxDistance = tonumber(tArgs[5]) + else + printError("max_distance: number expected") + printUsage() + return + end +end + print("going to coordinates = ", tArgs[2], ",", tArgs[3], ",", tArgs[4]) -local ok, err = netNav.goto(tArgs[2], tArgs[3], tArgs[4]) +local ok, err = netNav.goto(tArgs[2], tArgs[3], tArgs[4], maxDistance) if not ok then printError("navigation failed: ", err) else print("succesfully navigated to coordinates") -end \ No newline at end of file +end diff --git a/starNav/explore.lua b/starNav/explore.lua new file mode 100644 index 0000000..9984298 --- /dev/null +++ b/starNav/explore.lua @@ -0,0 +1,72 @@ +local tArgs = {...} + +-- FIND AREA BOUNDARIES +local minX, minY, minZ = unpack(tArgs, 2, 4) +minX, minY, minZ = tonumber(minX), tonumber(minY), tonumber(minZ) +local maxX, maxY, maxZ = unpack(tArgs, 5, 7) +maxX, maxY, maxZ = tonumber(maxX), tonumber(maxY), tonumber(maxZ) +local function isInteger(var) + return type(var) == "number" and math.floor(var) == var +end +if not isInteger(minX) then printError("minX must be integer") return end +if not isInteger(minY) then printError("minX must be integer") return end +if not isInteger(minZ) then printError("minX must be integer") return end +if not isInteger(maxX) then printError("maxX must be integer") return end +if not isInteger(maxY) then printError("maxY must be integer") return end +if not isInteger(maxZ) then printError("maxZ must be integer") return end +if minX > maxX then minX, maxX = maxX, minX end +if minY > maxY then minY, maxY = maxY, minY end +if minZ > maxZ then minZ, maxZ = maxZ, minZ end + +-- LOAD STARNAV API +if not starNav then + if not os.loadAPI("starNav") then + error("could not load starNav API") + end +end + +-- OPEN REDNET +for _, side in ipairs({"left", "right"}) do + if peripheral.getType(side) == "modem" then + rednet.open(side) + end +end +if not rednet.isOpen() then + printError("Could not open rednet") + return +end + +-- SET STARNAV MAP +local mapName = tArgs[1] +if type(mapName) ~= "string" then + printError("mapName must be string") + return +end +starNav.setMap(mapName) + +local exit = false +local returning = false + +local function main() + local startX, startY, startZ = gps.locate(1) + while turtle.getFuelLevel() > 0 and not exit do + local x = math.random(minX, maxX) + local y = math.random(minY, maxY) + local z = math.random(minZ, maxZ) + starNav.goto(x, y, z) + end + returning = true + starNav.goto(startX, startY, startZ) +end + +local function control() + while true do + local senderID, message = rednet.receive("explore:return_to_base") + if not exit and not returning then + starNav.stop() + exit = true + end + end +end + +parallel.waitForAny(main, control) diff --git a/starNav/starNav.lua b/starNav/starNav.lua index c25dbe3..9389f38 100644 --- a/starNav/starNav.lua +++ b/starNav/starNav.lua @@ -1,16 +1,13 @@ -if not tinyMap then - if not os.loadAPI("tinyMap") then - error("could not load tinyMap API") - end -end -if not aStar then - if not os.loadAPI("aStar") then - error("could not load aStar API") - end -end -if not location then - if not os.loadAPI("location") then - error("could not load location API") +local apis = { + "tinyMap", + "aStar", + "location", +} +for _ api in ipairs(apis) do + if not _G[api] then + if not os.loadAPI(api) then + error("could not load API: "..api) + end end end @@ -38,13 +35,13 @@ local function distanceFunc(a, b) elseif aStar.distance(b, sessionMidPoint) > sessionMaxDistance then return SESSION_COORD_DISTANCE -- second coord is outside the search region elseif sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then - return SESSION_COORD_DISTANCE -- one of the coords has been found to be blocked this during this session - elseif sessionMapA == SESSION_COORD_CLEAR and sessionMapA == SESSION_COORD_CLEAR then - return aStar.distance(a, b) -- both coords has been found to be clear this during this session + return SESSION_COORD_DISTANCE -- we have found one of these coords to be blocked during this session + elseif sessionMapA == SESSION_COORD_CLEAR and sessionMapB == SESSION_COORD_CLEAR then + return aStar.distance(a, b) -- we have found both of these coords to be clear during this session elseif mainMap:get(a) or mainMap:get(b) then return MAIN_COORD_DISTANCE end - return aStar.distance(a, b) -- we are assuming both coords are clear + return aStar.distance(a, b) -- we dont know anything useful so just calc the distance end local directions = { @@ -230,7 +227,9 @@ local function move(currPos, adjPos) return false end +local exit = false local function _goto(x, y, z, maxDistance) + exit = false if not mainMap then error("mainMap has not been specified") end @@ -246,7 +245,7 @@ local function _goto(x, y, z, maxDistance) local goal = vector.new(tonumber(x), tonumber(y), tonumber(z)) - sessionMap = aStar.newMap() + sessionMap = aStar.newMap() -- reset the sessionMap sessionMidPoint = vector.new(math.floor((goal.x + position.x)/2), math.floor((goal.y + position.y)/2), math.floor((goal.z + position.z)/2)) sessionMaxDistance = (type(maxDistance) == "number" and maxDistance) or math.max(2*aStar.distance(sessionMidPoint, goal), SESSION_MAX_DISTANCE_DEFAULT) @@ -255,7 +254,7 @@ local function _goto(x, y, z, maxDistance) return false, "no known path to goal" end - while not aStar.vectorEquals(position, goal) do + while not (exit or aStar.vectorEquals(position, goal)) do local movePos = table.remove(path) while not move(position, movePos) do local blockPresent, blockData = inspect(position, movePos) @@ -293,7 +292,7 @@ local function _goto(x, y, z, maxDistance) mainMap:saveAll() - return true + return aStar.vectorEquals(position, goal) end local isRunning = false @@ -311,6 +310,11 @@ function goto(...) return unpack(passback, 2) end +function stop() + if isRunning then + exit = true + end +end function setMap(mapName) if type(mapName) ~= "string" then error("mapName must be string") diff --git a/starNav/starNav_goto.lua b/starNav/starNav_goto.lua index ca15b93..390fa62 100644 --- a/starNav/starNav_goto.lua +++ b/starNav/starNav_goto.lua @@ -1,7 +1,7 @@ local function printUsage() print("Usage:") print(fs.getName(shell.getRunningProgram()).." <(optional)max_distance>") - print(" The name of the remoteMap to connect to and use.") + print(" The name of the map to use.") print(" The GPS coordinates you want to go to.") print("<(optional)max_distance> The farthest distance allowed to travel from start position.") end @@ -49,4 +49,4 @@ if not ok then printError("navigation failed: ", err) else print("succesfully navigated to coordinates") -end \ No newline at end of file +end