Implement modular scan strategies

This commit is contained in:
blunty666 2019-06-16 15:13:24 +01:00
parent 6c28791112
commit 61bef0e040
3 changed files with 127 additions and 99 deletions

View File

@ -154,4 +154,21 @@ function new( x, y, z, h )
}
setmetatable( l, lmetatable )
return l
end
end
local headings = {
[vector.new(0, 0, 1)] = 0,
[vector.new(-1, 0, 0)] = 1,
[vector.new(0, 0, -1)] = 2,
[vector.new(1, 0, 0)] = 3,
[vector.new(0, 1, 0)] = 4,
[vector.new(0, -1, 0)] = 5,
}
function headingFromDelta(delta)
for vec, dir in pairs(headings) do
if aStar.vectorEquals(delta, vec) then
return dir
end
end
end

View File

@ -2,6 +2,7 @@ local apis = {
"remoteMap",
"aStar",
"location",
"scanStrategy",
}
for _, api in ipairs(apis) do
if not _G[api] then
@ -49,23 +50,6 @@ local function distanceFunc(a, b)
return aStar.distance(a, b) -- we dont know anything useful so just calc the distance
end
local directions = {
[vector.new(0, 0, 1)] = 0,
[vector.new(-1, 0, 0)] = 1,
[vector.new(0, 0, -1)] = 2,
[vector.new(1, 0, 0)] = 3,
[vector.new(0, 1, 0)] = 4,
[vector.new(0, -1, 0)] = 5,
}
local function deltaToDirection(delta)
for vec, dir in pairs(directions) do
if aStar.vectorEquals(delta, vec) then
return dir
end
end
end
local function tryMove()
for i = 1, 4 do
if turtle.forward() then
@ -107,31 +91,16 @@ local function findPosition()
error("no gps signal - phase 2")
end
local direction = deltaToDirection(p1 - p2)
if direction and direction < 4 then
return location.new(p2.x, p2.y, p2.z, direction)
local currentDirection = location.headingFromDelta(p1 - p2)
if currentDirection and currentDirection < 4 then
return location.new(p2.x, p2.y, p2.z, currentDirection)
else
return false
end
end
local function detect(currPos, adjPos)
local direction = deltaToDirection(adjPos - currPos)
if direction then
position:setHeading(direction)
if direction == 4 then
return turtle.detectUp()
elseif direction == 5 then
return turtle.detectDown()
else
return turtle.detect()
end
end
return false
end
local function inspect(currPos, adjPos)
local direction = deltaToDirection(adjPos - currPos)
local direction = location.headingFromDelta(adjPos - currPos)
if direction then
position:setHeading(direction)
if direction == 4 then
@ -145,81 +114,35 @@ local function inspect(currPos, adjPos)
return false
end
local function updateCoord(coord, isBlocked)
local function updateSessionMap(coord, isBlocked)
if isBlocked then
sessionMap:set(coord, SESSION_COORD_BLOCKED)
serverMap:set(coord, UPDATE_COORD_BLOCKED)
else
sessionMap:set(coord, SESSION_COORD_CLEAR)
end
end
local function updateServerMap(coord, isBlocked)
if isBlocked then
serverMap:set(coord, UPDATE_COORD_BLOCKED)
else
serverMap:set(coord, UPDATE_COORD_CLEAR)
end
end
local function detectAll(currPos)
for _, pos in ipairs(aStar.adjacent(currPos)) do -- better order of checking directions
updateCoord(pos, detect(currPos, pos))
end
end
local function findSensor()
for _, side in ipairs({"left", "right"}) do
if peripheral.getType(side) == "turtlesensorenvironment" then
return side
end
end
return false
end
local function scan(currPos)
local sensorSide = findSensor()
if sensorSide then
local rawBlockInfo = peripheral.call(sensorSide, "sonicScan")
local sortedBlockInfo = aStar.newMap()
for _, blockInfo in ipairs(rawBlockInfo) do
sortedBlockInfo:set(currPos + vector.new(blockInfo.x, blockInfo.y, blockInfo.z), blockInfo)
end
local toCheckQueue = {}
for _, pos in ipairs(aStar.adjacent(currPos)) do
if sortedBlockInfo:get(pos) then
table.insert(toCheckQueue, pos)
end
end
while toCheckQueue[1] do
local pos = table.remove(toCheckQueue, 1)
local blockInfo = sortedBlockInfo:get(pos)
if blockInfo.type == "AIR" then
for _, pos2 in ipairs(aStar.adjacent(pos)) do
local blockInfo2 = sortedBlockInfo:get(pos2)
if blockInfo2 and not blockInfo2.checked then
table.insert(toCheckQueue, pos2)
end
end
updateCoord(pos, false)
else
updateCoord(pos, true)
end
blockInfo.checked = true
end
for _, blockInfo in ipairs(rawBlockInfo) do
local pos = currPos + vector.new(blockInfo.x, blockInfo.y, blockInfo.z)
local blockInfo = sortedBlockInfo:get(pos)
if not blockInfo.checked then
if blockInfo.type == "AIR" then
sessionMap:set(pos, SESSION_COORD_CLEAR)
else
sessionMap:set(pos, SESSION_COORD_BLOCKED)
end
end
end
local function scan(currentPosition)
local strategy = scanStrategy.getBest()
if strategy then
strategy.execute(currentPosition, updateSessionMap, updateServerMap)
serverMap:check()
serverMap:pushUpdates()
else
detectAll(currPos)
-- throw error ?
end
serverMap:check()
serverMap:pushUpdates()
end
local function move(currPos, adjPos)
local direction = deltaToDirection(adjPos - currPos)
local direction = location.headingFromDelta(adjPos - currPos)
if direction then
position:setHeading(direction)
if direction == 4 then
@ -356,3 +279,7 @@ function getPosition()
return position:value()
end
end
function addScanStrategy(strategy)
scanStrategy.add(strategy)
end

84
netNav/scanStrategy.lua Normal file
View File

@ -0,0 +1,84 @@
local strategies = {}
local function compareStrategies(a, b)
return a.priority > b.priority
end
function add(strategy)
table.insert(strategies, strategy)
table.sort(strategies, compareStrategies)
end
function getBest()
for _, strategy in ipairs(strategies) do
if strategy.isAvailable() then
return strategy
end
end
return false
end
--===== SET UP VANILLA SCAN STRATEGY =====--
local function detect(currPos, adjPos)
local heading = location.headingFromDelta(adjPos - currPos)
if heading then
currPos:setHeading(heading)
if heading == 4 then
return turtle.detectUp()
elseif heading == 5 then
return turtle.detectDown()
else
return turtle.detect()
end
end
return false
end
local vanillaScanStrategy = {
priority = 0, -- lowest priority
isAvailable = function() return true end, -- always available
execute = function(currentPosition, updateSessionMap, updateServerMap)
for _, pos in ipairs(aStar.adjacent(currentPosition)) do -- find better order of checking directions
local isBlocked = detect(currentPosition, pos)
updateSessionMap(pos, isBlocked)
updateServerMap(pos, isBlocked)
end
end,
}
add(vanillaScanStrategy)
--===== LOAD STRATEGIES FROM NET NAV STRATEGY FOLDER
local function loadStrategy(path)
local name = fs.getName(path)
if name:sub(-4) == ".lua" then
name = name:sub(1, -5)
end
local tEnv = {}
setmetatable(tEnv, {__index = _G})
local fnAPI, err = loadfile(path, tEnv)
if fnAPI then
local ok, err = pcall(fnAPI)
if not ok then
return printError("Failed to load strategy " .. name .. " due to " .. err, 1)
end
else
return printError("Failed to load strategy " .. name .. " due to " .. err, 1)
end
if type(tEnv.new) == "function" then
local strategy = tEnv.new()
add(strategy)
else
return printError("Failed to find constructor for strategy " .. name)
end
end
local STRATEGY_FOLDER = "netNavScanStrategies"
if fs.exists(STRATEGY_FOLDER) and fs.isDir(STRATEGY_FOLDER) then
for _, file in ipairs(fs.list(STRATEGY_FOLDER)) do
local path = fs.combine(STRATEGY_FOLDER, file)
loadStrategy(path)
end
end