367 lines
8.4 KiB
Lua
367 lines
8.4 KiB
Lua
local robotApi = require('libs/robot')
|
|
local turtleUtils = require('libs/turtle-utils')
|
|
local config = require('config/mining')
|
|
|
|
local LOWER_SIZE_LIMIT = 2;
|
|
local HIGHER_SIZE_LIMIT = 128;
|
|
|
|
local INITIAL_TARGET_Y = config.targetY - config.startY
|
|
local TARGET_Z = config.size - 1
|
|
local TARGET_X = config.size - 1
|
|
|
|
local MAX_X = TARGET_X
|
|
local MAX_Y = INITIAL_TARGET_Y + (config.height - 1)
|
|
local MAX_Z = TARGET_Z
|
|
|
|
local MIN_PERCENTAGE_NEEDED = 10
|
|
|
|
local miner = {
|
|
robot = robotApi.create(),
|
|
mission = 'unload', -- "unload" | "refuel" | "mine" | "return-home" | "return-mine" | nil
|
|
started = false,
|
|
finished = false,
|
|
lastPositionState = nil, -- { x, y, z, dir }
|
|
targetY = INITIAL_TARGET_Y
|
|
}
|
|
|
|
local function saveMinerState()
|
|
local minerState = {
|
|
robotState = miner.robot.getState(),
|
|
mission = miner.mission,
|
|
started = miner.started,
|
|
finished = miner.finished,
|
|
lastPositionState = miner.lastPositionState and textutils.serializeJSON(miner.lastPositionState),
|
|
targetY = miner.targetY
|
|
}
|
|
|
|
local file = fs.open('.minerstate', 'w')
|
|
|
|
if not file then
|
|
error('saveMinerState: cannot open .minerstate file!')
|
|
end
|
|
|
|
file.write(textutils.serializeJSON(minerState))
|
|
file.close()
|
|
end
|
|
|
|
local function loadMinerState()
|
|
local file = fs.open('.minerstate', 'r')
|
|
|
|
if not file then
|
|
return
|
|
end
|
|
|
|
local serializedMinerState = file.readAll()
|
|
file.close()
|
|
|
|
local minerState = textutils.unserializeJSON(serializedMinerState)
|
|
|
|
local lastPositionState = nil
|
|
|
|
if minerState.lastPositionState then
|
|
lastPositionState = minerState.lastPositionState
|
|
end
|
|
|
|
miner = {
|
|
robot = robotApi.create(minerState.robotState),
|
|
mission = minerState.mission,
|
|
started = minerState.started,
|
|
finished = minerState.finished,
|
|
lastPositionState = lastPositionState,
|
|
targetY = minerState.targetY
|
|
}
|
|
end
|
|
|
|
local function cleanupMinerState()
|
|
fs.delete('.minerstate')
|
|
end
|
|
|
|
local function isOdd(x)
|
|
return (x % 2) == 1
|
|
end
|
|
|
|
local function robotForceForward()
|
|
local ok = miner.robot.forward()
|
|
|
|
if ok then
|
|
return ok
|
|
end
|
|
|
|
turtleUtils.digAll()
|
|
|
|
return miner.robot.forward()
|
|
end
|
|
|
|
local function robotForceDown()
|
|
local ok = miner.robot.down()
|
|
|
|
if ok then
|
|
return ok
|
|
end
|
|
|
|
turtle.digDown()
|
|
|
|
return miner.robot.down()
|
|
end
|
|
|
|
local function robotForceUp()
|
|
local ok = miner.robot.up()
|
|
|
|
if ok then
|
|
return ok
|
|
end
|
|
|
|
turtle.digUp()
|
|
|
|
return miner.robot.up()
|
|
end
|
|
|
|
local function checkConfig()
|
|
if config.targetY >= config.startY then
|
|
error('targetY should be lower than startY')
|
|
end
|
|
|
|
if config.height < 1 then
|
|
error('height cannot be lower than 1')
|
|
end
|
|
|
|
if config.size < LOWER_SIZE_LIMIT then
|
|
error('size cannot be lower than ' .. LOWER_SIZE_LIMIT)
|
|
end
|
|
|
|
if config.size > HIGHER_SIZE_LIMIT then
|
|
error('size is too large (higher limit is ' .. HIGHER_SIZE_LIMIT .. ')')
|
|
end
|
|
|
|
if isOdd(config.size) then
|
|
error('configured size should be even')
|
|
end
|
|
end
|
|
|
|
local function minerStarted()
|
|
turtle.select(1)
|
|
miner.started = true
|
|
print("> Miner program started, minimum percentgae fuel needed: " .. MIN_PERCENTAGE_NEEDED)
|
|
end
|
|
|
|
local function minerFinished()
|
|
cleanupMinerState()
|
|
print("> Miner program finished!")
|
|
end
|
|
|
|
local function isProgramFinished()
|
|
if miner.mission ~= nil then
|
|
return false
|
|
end
|
|
|
|
local robotState = miner.robot.getState()
|
|
|
|
return robotState.x == 0 and robotState.y == 0 and robotState.z == 0
|
|
end
|
|
|
|
|
|
local function unloadProcedure()
|
|
print('> Starting unload procedure...')
|
|
turtleUtils.waitForInventory('front')
|
|
|
|
for i=1, 16, 1 do
|
|
turtle.select(i)
|
|
turtle.refuel()
|
|
turtleUtils.tryDrop()
|
|
end
|
|
|
|
miner.mission = 'refuel'
|
|
end
|
|
|
|
local function refuelProcedure()
|
|
print('> Starting refuel procedure (' .. turtleUtils.getFuelPercentage() .. '%)')
|
|
turtleUtils.waitForInventory('top')
|
|
|
|
turtle.select(1)
|
|
|
|
while turtleUtils.getFuelPercentage() < MIN_PERCENTAGE_NEEDED do
|
|
turtleUtils.trySuckUp()
|
|
|
|
local ok = turtle.refuel()
|
|
if not ok then
|
|
turtleUtils.tryDrop()
|
|
end
|
|
end
|
|
|
|
print('> Refuel done (' .. turtleUtils.getFuelPercentage() .. '%)')
|
|
|
|
miner.mission = 'return-mine'
|
|
end
|
|
|
|
local function returnMineProcedure()
|
|
if miner.finished then
|
|
miner.mission = nil -- it will stop the loop
|
|
return
|
|
end
|
|
|
|
if miner.robot.lastPositionState then
|
|
local robotState = miner.robot.getState()
|
|
|
|
if robotState.y > miner.lastPositionState.y then
|
|
robotForceDown()
|
|
elseif robotState.z < miner.lastPositionState.z then
|
|
robotForceForward()
|
|
else
|
|
miner.robot.turnRight()
|
|
|
|
for i=1, miner.lastPositionState.x, 1 do
|
|
robotForceForward()
|
|
saveMinerState()
|
|
end
|
|
|
|
while miner.robot.getState().dir ~= miner.lastPositionState.dir do
|
|
miner.robot.turnRight()
|
|
saveMinerState()
|
|
end
|
|
|
|
miner.mission = 'mine'
|
|
print('> Starting mining procedure...')
|
|
end
|
|
else
|
|
miner.mission = 'mine'
|
|
print('> Starting mining procedure...')
|
|
end
|
|
end
|
|
|
|
local function mineProcedure()
|
|
local robotState = miner.robot.getState()
|
|
local targetY = miner.targetY
|
|
local targetZ = TARGET_Z
|
|
|
|
-- 1. Move
|
|
if robotState.y > targetY then
|
|
turtle.digDown()
|
|
robotForceDown()
|
|
elseif robotState.dir == 'FORWARD' and robotState.z < targetZ then
|
|
turtleUtils.digAll()
|
|
robotForceForward()
|
|
elseif robotState.dir == 'FORWARD' and robotState.z == targetZ then
|
|
miner.robot.turnRight()
|
|
turtleUtils.digAll()
|
|
robotForceForward()
|
|
miner.robot.turnRight()
|
|
elseif robotState.dir == 'BACKWARD' and robotState.z > 0 then
|
|
turtleUtils.digAll()
|
|
robotForceForward()
|
|
elseif robotState.dir == 'BACKWARD' and robotState.z == 0 then
|
|
miner.robot.turnLeft()
|
|
turtleUtils.digAll()
|
|
robotForceForward()
|
|
miner.robot.turnLeft()
|
|
end
|
|
|
|
-- 2. Check
|
|
if robotState.x == MAX_X and robotState.y == MAX_Y and robotState.z == 0 then
|
|
miner.finished = true
|
|
miner.mission = 'return-home'
|
|
miner.lastPositionState = miner.robot.getState()
|
|
print('> Starting return home procedure because mining session is finished...')
|
|
elseif robotState.x == MAX_X and robotState.z == 0 then
|
|
-- this part assume that the size of the mine is even
|
|
miner.robot.turnRight()
|
|
|
|
for i=1, config.size - 1, 1 do
|
|
robotForceForward()
|
|
saveMinerState()
|
|
end
|
|
|
|
miner.robot.turnRight()
|
|
-- mine the next stage
|
|
robotForceUp()
|
|
miner.targetY = miner.targetY + 1
|
|
end
|
|
|
|
if turtleUtils.countFreeSlots() < 1 then
|
|
print('> Starting return home procedure because inventory is almost full...')
|
|
miner.mission = 'return-home'
|
|
miner.lastPositionState = miner.robot.getState()
|
|
elseif turtleUtils.getFuelPercentage() <= 1 then
|
|
print('> Starting return home procedure because there is less than 1% of fuel...')
|
|
miner.mission = 'return-home'
|
|
miner.lastPositionState = miner.robot.getState()
|
|
end
|
|
end
|
|
|
|
local function returnHomeProcedure()
|
|
local robotState = miner.robot.getState()
|
|
|
|
if robotState.x == 0 and robotState.y == 0 and robotState.z == 0 then
|
|
miner.mission = 'unload'
|
|
elseif robotState.x == 0 and robotState.z == 0 then
|
|
while miner.robot.getState().dir ~= 'FORWARD' do
|
|
miner.robot.turnRight()
|
|
end
|
|
|
|
robotForceUp()
|
|
elseif robotState.x > 0 then
|
|
if robotState.dir == 'FORWARD' then
|
|
miner.robot.turnLeft()
|
|
elseif robotState.dir == 'BACKWARD' then
|
|
miner.robot.turnRight()
|
|
end
|
|
|
|
for i=1, robotState.x, 1 do
|
|
robotForceForward()
|
|
saveMinerState()
|
|
end
|
|
|
|
miner.robot.turnLeft()
|
|
elseif robotState.z > 0 then
|
|
for i=1, robotState.z, 1 do
|
|
robotForceForward()
|
|
end
|
|
|
|
miner.robot.turnLeft()
|
|
miner.robot.turnLeft()
|
|
end
|
|
end
|
|
|
|
local function waitForUserConfirmation()
|
|
print('> startY: ' .. config.startY)
|
|
print('> targetY: ' .. config.targetY)
|
|
print('> height: ' .. config.height)
|
|
print('> size: ' .. config.size)
|
|
print('> type "yes" to start the mining process.')
|
|
|
|
local val = read()
|
|
|
|
if val == 'yes' then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
checkConfig()
|
|
loadMinerState()
|
|
|
|
if not miner.started then
|
|
while not waitForUserConfirmation() do end
|
|
end
|
|
|
|
minerStarted()
|
|
saveMinerState()
|
|
|
|
while not isProgramFinished() do
|
|
if miner.mission == 'unload' then
|
|
unloadProcedure()
|
|
elseif miner.mission == 'refuel' then
|
|
refuelProcedure()
|
|
elseif miner.mission == 'mine' then
|
|
mineProcedure()
|
|
saveMinerState()
|
|
elseif miner.mission == 'return-home' then
|
|
returnHomeProcedure()
|
|
saveMinerState()
|
|
elseif miner.mission == 'return-mine' then
|
|
returnMineProcedure()
|
|
saveMinerState()
|
|
end
|
|
end
|
|
|
|
minerFinished() |