Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Author: KROM
- --
- -- NOTE: This is still buggy, turtle might run off :|
- --
- -- v0.1 - first code
- -- v0.2 - added cave mode, x|y can be set independently
- -- v0.2a - disabled rednet
- --
- -- known bugs:
- -- * moves one step to far on y, when resuming after abort on 1st floor.
- -- * x/y dimensions need to be uneven
- -- * calc. of energy requirement somewhat strange/not exact
- -- * reserved slots not implemented
- -- --------------------------------
- local sBotLabel = "MiningBot 01"
- -- those are reserved at end of inventory
- local nReservedSlots = 2
- -- where's the fuel?
- local nBatterySlot = 1
- -- set this to ID of master computer
- -- get id by: lua(); os.getComputerID(); exit();
- local nMasterComputerID = 31
- -- when should me unloadz?
- local nEmptySlotsMargin = 1
- -- internal vars
- local nRuns = 0
- local nEnergy = 0
- local nEnergySafetyMargin = 30
- local bNoError = true
- local bRedNet = false
- local nRadius = 0 -- should be obsolete
- local nMaxDepth = 0
- local bResume = false
- local startX,startY,startZ = 0,0,0
- local currentX,currentY,currentZ = 0,0,0
- local nDepth = 0
- local nMined = 0
- local stopCause = 0
- local xDir,yDir = 0,-1
- local nDigDir = -1 -- -1 = down, 1 = up
- local nRadiusX, nRadiusY = 0,0
- local tmpDepth = -1 -- backup, when returning home
- -- ----------------------------------------------------------
- function saySingle(str)
- write(str)
- end
- -- ----------------------------------------------------------
- local function say(message)
- if bRedNet == true then
- rednet.send(nMasterComputerID, message)
- end
- print(message)
- -- sleep(0.2)
- end
- -- ----------------------------------------------------------
- local function turnLeft()
- turtle.turnLeft()
- xDir, yDir = -yDir, xDir
- end
- -- ----------------------------------------------------------
- local function turnRight()
- turtle.turnRight()
- xDir, yDir = yDir, -xDir
- end
- -- ----------------------------------------------------------
- local function recharge()
- say("trying to recharge")
- turtle.select(nBatterySlot)
- local e = turtle.getFuelLevel()
- turtle.refuel()
- nEnergy = turtle.getFuelLevel()
- say("fuel: "..e.." -> "..nEnergy)
- if nEnergy > e then
- return true
- end
- return false
- end
- -- ----------------------------------------------------------
- local function unloadCargo()
- local ende = 16 - nReservedSlots
- for invloop=1,16 do
- if invloop ~= nBatterySlot then
- -- say("Drop item in Slot "..invloop)
- turtle.select(invloop)
- turtle.drop()
- end
- end
- end
- -- ----------------------------------------------------------
- local function getFreeSlots()
- local nSpace = 0
- for invloop=1,16 do
- local items = turtle.getItemCount(invloop)
- if items == 0 then
- nSpace = nSpace + 1
- end
- end
- return nSpace
- end
- -- ----------------------------------------------------------
- local function collect()
- nMined = nMined + 1
- if math.fmod(nMined, 25) == 0 then
- say( "Mined "..nMined.." blocks." )
- end
- if getFreeSlots() > 0 then
- return true
- end
- say( "No empty slots left." )
- return false
- end
- -- ----------------------------------------------------------
- local function attackMode()
- local bAttacked = false
- while turtle.attack() do
- say("Attacking!!1")
- bAttacked = true
- end
- return bAttacked
- end
- -- ----------------------------------------------------------
- local function tryForwards()
- local nMaxTries = 10
- local nTries = 0
- stopCause = 0
- while not turtle.forward() do
- if nTries > 0 then
- say("Try to move forward, "..nTries.." try.")
- end
- if turtle.dig() then
- if not collect() then
- say("abort reason 2")
- stopCause = 2
- return false
- end
- else
- if attackMode() then
- -- attacking should not reduce tries
- nTries = nTries - 1
- if nTries < 0 then
- nTries = 0
- end
- end
- end
- -- give sand a chance to fall
- sleep(0.8)
- nTries = nTries + 1
- if nTries >= nMaxTries then
- say("abort reason 2")
- return false
- end
- end
- --xPos = xPos + xDir
- --zPos = zPos + zDir
- return true
- end
- -- ----------------------------------------------------------
- local function tryDown()
- stopCause = 0
- if currentZ == nMaxDepth then
- say("tryDown: already at max depth")
- return false
- end
- if not turtle.down() then
- if turtle.digDown() then
- if not collect() then
- stopCause = 2
- return false
- end
- end
- if not turtle.down() then
- stopCause = 1
- return false
- end
- end
- currentZ = currentZ + 1
- --if math.fmod( nDepth, 10 ) == 0 then
- say( ">>> Descended "..currentZ.." metres. <<<" )
- return true
- end
- -- ----------------------------------------------------------
- local function tryUp()
- stopCause = 0
- if currentZ == nMaxDepth then
- say("tryDown: already at max depth")
- return false
- end
- if not turtle.up() then
- if turtle.digUp() then
- if not collect() then
- stopCause = 2
- return false
- end
- end
- if not turtle.up() then
- stopCause = 1
- return false
- end
- end
- currentZ = currentZ + 1
- --if math.fmod( nDepth, 10 ) == 0 then
- say( ">>> Ascended "..currentZ.." metres. <<<" )
- return true
- end
- -- ----------------------------------------------------------
- -- ----------------------------------------------------------
- -- S T A R T
- -- ----------------------------------------------------------
- say("Mining Bot v0.1 - Welcome!")
- say("Turtle "..sBotLabel.." ready for action.")
- say("")
- saySingle("Radius Y (forward, uneven): ")
- nRadiusY = read()
- saySingle("Radius X (to the right, uneven, Y default): ")
- nRadiusX = read()
- saySingle("Radius Z (up/down): ")
- nMaxDepth = read()
- saySingle("Dig (d)own or (u)p? (default down) ")
- nDigDir = read()
- saySingle("Is this a resume? (y/n): ")
- bResume = read()
- -- todo: verify input. for now just convert
- -- nRadius = tonumber( nRadius )
- nMaxDepth = tonumber( nMaxDepth )
- if bResume == "y" then
- bResume = true
- else
- bResume = false
- end
- if nMaxDepth < 1 then
- say("Depth provided too shallow" )
- return
- end
- nRadiusX = tonumber( nRadiusX )
- if nRadiusX == 0 then
- nRadiusX = nRadiusY
- end
- if nDigDir ~= nil then
- if nDigDir == "u" then
- nDigDir = 1
- else
- nDigDir = -1
- end
- else
- nDigDir = -1
- end
- -- Repeat what we understood
- say("I should mine in a radius of "..nRadiusX..","..nRadiusY.."to a nDepth of "..nMaxDepth)
- if bResume == true then
- say("This is a resume operation")
- else
- say("This is not a resume operation")
- end
- -- ----------------------------------------------------------
- -- -------------------------
- -- init wireless
- ----------------------------
- -- bRedNet = rednet.open("right")
- -- if bRedNet ~= true then
- -- bRedNet = rednet.open("left")
- -- end
- bRedNet = false
- if bRedNet == true then
- say("Rednet enabled")
- rednet.send(nMasterComputerID, sBotLabel.." reporting in.")
- else
- say("no rednet available")
- end
- -- ----------------------------------------------------------
- local function isOperational()
- -- get energy
- local nEnergyLevel = turtle.getFuelLevel()
- -- get needed energy for way back home
- local nSteps = currentX + currentY + currentZ
- local required = 0
- if nEnergyLevel < nSteps then
- say("ALERT: Not enough energy to return home.")
- say("Current Energy: "..nEnergyLevel.."E")
- say("Needed :"..nSteps.."E")
- say("We will do what we can... :-/")
- return false
- end
- -- y*(x + 2) for movement
- required = required + (nRadiusX * (nRadiusY+2))
- -- + (x*y) for dig
- required = required + (nRadiusX * nRadiusY)
- -- + energy for way back home
- required = required + nSteps
- -- + safety margin
- required = required + nEnergySafetyMargin
- -- = energy requirement
- say("Energy: "..required.."E req. "..nEnergyLevel.."E avail.")
- if nEnergyLevel <= required then
- say("Not enough energy for a full cycle.")
- -- Try to recharge
- if recharge() == true then
- -- recheck energy
- if nEnergyLevel <= required then
- say("Still not enough energy for a full cycle.")
- return false
- end
- else
- -- failed to recharge, abort.
- say("Could not recharge.")
- return false
- end
- end
- -- check inventory
- local emptySlots = getFreeSlots()
- if emptySlots < nEmptySlotsMargin then
- say(emptySlots.." Slots left. Need "..nEmptySlotsMargin)
- return false
- end
- -- all cool
- return true
- end
- -- ----------------------------------------------------------
- local function saveStatus()
- -- save which depth we have been on
- -- for sake of simplicity, we will restart on that layer
- -- when resuming, not returning to exact last position.
- tmpDepth = currentZ
- end
- -- ----------------------------------------------------------
- local function waitForEnergy()
- local count = 0
- local hasEnergy = false
- say("Waiting for energy in Slot "..nBatterySlot)
- while not hasEnergy do
- if recharge() == true then
- hasEnergy = true
- return true
- else
- sleep(5)
- count = count + 1
- if count == 5 then
- say("Waiting for energy in Slot "..nBatterySlot)
- count = 0
- end
- end
- end
- return true
- end
- -- ----------------------------------------------------------
- local function goHome(vDir, bResume)
- say("Going Home :)")
- say("Dir: "..xDir..","..yDir)
- -- needs to face left
- if yDir == -1 then
- if xDir == 1 then
- turnRight()
- elseif xDir == -1 then
- turnLeft()
- else
- turnLeft()
- turnLeft()
- end
- elseif yDir == 0 then
- if xDir > 0 then
- turnLeft()
- else
- turnRight()
- end
- elseif xDir > 0 or xDir < 0 then
- if xDir > 0 then
- turnRight()
- else
- turnLeft()
- end
- end
- -- if energy too low, go to a wait-for-recharge loop
- nEnergy = turtle.getFuelLevel()
- if nEnergy < 5 then
- waitForEnergy()
- end
- say("I am at "..currentX..","..currentY..","..currentZ)
- if nDigDir == 1 then
- while currentZ > 0 do
- if not turtle.down() then
- say("ALERT: Failed to move down while returning")
- return false
- end
- currentZ = currentZ - 1
- end
- else
- while currentZ > 0 do
- if not turtle.up() then
- say("ALERT: Failed to move up while returning")
- return false
- end
- currentZ = currentZ - 1
- end
- end
- if currentX > 0 then
- turnRight()
- while currentX > 0 do
- if not tryForwards() then
- say("ALERT: Failed to move forward(X) while returning")
- return false
- end
- currentX = currentX - 1
- end
- turnLeft()
- end
- while currentY > 0 do
- if not tryForwards() then
- say("ALERT: Failed to move forward(Y) while returning")
- return false
- end
- currentY = currentY - 1
- end
- say("Should be at home. hopefully. :)")
- return true
- end
- -- ----------------------------------------------------------
- local function waitForInput()
- local id,message,distance = rednet.receive(0.05)
- if id ~= nil then
- if message == "terminate" then
- say("Message: Terminate")
- exit()
- elseif message == "home" then
- say("Message: Go home")
- goHome()
- exit()
- end
- end
- end
- -- ----------------------------------------------------------
- -- 0 = normal, like 1st layer
- -- 1 = reverse direction, every 2nd layer
- layerdirection = 1
- startX,startY,startZ = 0,0,0
- local v
- local function work(nHowDeep, nSizeX, nSizeY, nDir)
- local depth,x,y
- local startZ = currentZ
- say("StartZ: "..startZ)
- local bFirstLoop = false
- for depth=startZ,nHowDeep do
- -- full check each layer
- if not isOperational() then
- say("Depth-Check: returning home")
- saveStatus()
- goHome(v, true)
- return true
- end
- for x=0,(nSizeX-1) do
- -- waitForInput()
- -- first row has no turn move
- -- which needs to be offset
- local startY = 1
- if x == 0 and startZ == 0 and depth == 0 then
- startY = 0
- elseif bFirstLoop == true then
- startY = 0
- end
- if x == 0 then
- say("SY: "..startY)
- end
- for y=startY,(nSizeY-1) do
- local start = currentX..","..currentY..","..currentZ
- v = math.fmod(x,2)
- -- v == 0 = facing away. like start
- -- v == 1 = facing to start
- -- say("V: "..v.." LD: "..layerdirection.." SY: "..startY.." xyz: "..x..","..y..","..depth)
- -- checks
- -- simple inventory check here
- local emptySlots = getFreeSlots()
- if emptySlots < nEmptySlotsMargin then
- say(emptySlots.." Slots left. Need "..nEmptySlotsMargin)
- saveStatus()
- goHome(v, true)
- return true
- end
- if not tryForwards() then
- if stopCause == 2 then
- -- inventory full?!
- say("Failed to move forward. Inv. full?!")
- saveStatus()
- goHome(v, true)
- return true
- else
- say("Failed to move forward.")
- saveStatus()
- goHome(v, false)
- return false
- end
- end
- if layerdirection == 1 then
- if v == 0 then
- currentY = currentY + 1
- else
- currentY = currentY - 1
- end
- else
- if v == 0 then
- currentY = currentY - 1
- else
- currentY = currentY + 1
- end
- end
- -- say("P: "..start.." -> "..currentX..","..currentY..","..currentZ)
- -- say("Dir: "..xDir..","..yDir)
- -- end y loop
- end
- bFirstLoop = false;
- say("completed one line")
- -- if not on last line
- if x < nSizeX-1 then
- -- move to next line (turn, move, turn)
- if v == 0 then
- say("Moving to next row (1)")
- turnRight()
- -- to be on the safe side:
- if not isOperational() then
- saveStatus()
- goHome(v, true)
- return true
- end
- if not tryForwards() then
- if stopCause == 2 then
- -- inventory full?!
- say("Failed to move forward. Inv. full?!")
- saveStatus()
- goHome(v, true)
- return true
- else
- saveStatus()
- goHome(v, false)
- return false
- end
- end
- turnRight()
- else
- say("Moving to next row (2)")
- turnLeft()
- -- to be on the safe side:
- if not isOperational() then
- saveStatus()
- goHome(v, true)
- return true
- end
- if not tryForwards() then
- if stopCause == 2 then
- -- inventory full?!
- say("Failed to move forward. Inv. full?!")
- saveStatus()
- goHome(v, true)
- return true
- else
- saveStatus()
- goHome(v, false)
- return false
- end
- end
- turnLeft()
- end
- if layerdirection == 1 then
- currentX = currentX + 1
- else
- currentX = currentX - 1
- end
- end
- -- end x loop
- end
- say("completed one layer")
- -- checks if depth reached
- if depth < nHowDeep then
- if nDir == 1 then
- if not tryUp() then
- -- unable to move down?
- -- assume we hit bedrock
- goHome(v, false)
- return true
- end
- else
- if not tryDown() then
- -- unable to move down?
- -- assume we hit bedrock
- goHome(v, false)
- return true
- end
- end
- if layerdirection == 1 then
- layerdirection = 0
- else
- layerdirection = 1
- end
- turnLeft()
- turnLeft()
- else
- say("finished all layer")
- -- finished
- saveStatus()
- goHome(v, false)
- return true
- end
- -- end z loop
- end
- say("should not hit this code line")
- end
- -- ----------------------------------------------------------
- local function resume()
- local depthcounter = 0
- -- move away from start
- tryForwards()
- currentY = currentY + 1
- -- if tmpZ isgiven, go down to that Z
- if tmpDepth == -1 then
- if nDigDir == 1 then
- while turtle.up() == true do
- depthcounter = depthcounter + 1
- end
- say("Resume: We hit ceiling at "..depthcounter)
- else
- while turtle.down() == true do
- depthcounter = depthcounter + 1
- end
- say("Resume: We hit ground at "..depthcounter)
- end
- -- find ground
- currentZ = depthcounter
- else
- -- resuming last position
- while depthcounter < tmpDepth do
- if nDigDir == 1 then
- if turtle.up() == true then
- depthcounter = depthcounter + 1
- else
- -- we hit something.
- say("We hit something while going up.")
- say("Starting a new, full cycle at this position.")
- currentZ = depthcounter
- return
- end
- else
- if turtle.down() == true then
- depthcounter = depthcounter + 1
- else
- -- we hit something.
- say("We hit something while going down.")
- say("Starting a new, full cycle at this position.")
- currentZ = depthcounter
- return
- end
- end
- end
- currentZ = depthcounter
- end
- end
- -- ----------------------------------------------------------
- -- END MAIN LOOP FUNCTION
- -- ----------------------------------------------------------
- local done = false
- while not done do
- sleep(5)
- -- determine min. energy for next cycle
- local required = 0
- -- z for going back down
- required = required + tmpDepth
- -- + enough for at least two full layers
- required = required + (2 * (nRadiusX * (nRadiusY+2)))
- required = required + (2 * (nRadiusX * nRadiusY))
- -- + energy for way back home
- required = required + (nRadiusX + nRadiusY + nMaxDepth)
- -- + safety margin
- required = required + nEnergySafetyMargin
- nEnergy = turtle.getFuelLevel()
- say("Need about "..required.."E for resuming. Have: "..nEnergy.."E")
- -- recharge if needed.
- while nEnergy < required do
- if not recharge() then
- waitForEnergy()
- end
- end
- -- first run, still in original position
- -- fill face other direction when returning
- if tmpDepth == -1 then
- turnLeft()
- turnLeft()
- end
- -- unload cargo
- say("Unloading Cargo")
- unloadCargo()
- turnLeft()
- turnLeft()
- -- reset vars
- layerdirection = 1
- startX,startY,startZ = 0,0,0
- -- if resuming by prompt or resuming running operation
- if bResume == true or tmpDepth > -1 then
- resume()
- end
- -- start normal operation
- local status = work(nMaxDepth, nRadiusX, nRadiusY, nDigDir)
- if not status then
- -- either something went wrong, or we have finished
- done = true
- if tmpDepth == nMaxDepth then
- say("**** Successfully finished ****")
- else
- say("Something went wrong")
- end
- else
- -- we assume a successful cycle.
- say("Finished a successful cycle")
- if tmpDepth == nMaxDepth then
- done = true
- say("**** Successfully finished ****")
- say("Unloading Cargo")
- unloadCargo()
- turnLeft()
- turnLeft()
- else
- -- resume
- say("Resuming")
- end
- end
- nRuns = nRuns + 1
- end
- say( "Mined "..nMined.." blocks total in "..nRuns.." runs." )
Add Comment
Please, Sign In to add comment