Skip to content

Instantly share code, notes, and snippets.

@JCThePants
Created February 13, 2015 07:42
Show Gist options
  • Save JCThePants/db2038b6368d2f231aed to your computer and use it in GitHub Desktop.
Save JCThePants/db2038b6368d2f231aed to your computer and use it in GitHub Desktop.
Simple ComputerCraft turtle mining script
args = { ... }
-- hasModem hasEnderChest size depth [startDepth]
-- Used to denote the current direction relative to the direction the
-- turtle was facing when the program starts. The start direction is FORWARD.
direction = {}
direction.FORWARD = 0
direction.RIGHT = 1
direction.BACKWARD = 2
direction.LEFT = 3
-- Tasks the tutle performs
task = {}
task.MINESHAFT = 0
task.MINEXZ = 1
task.MINEXZ_TURN = 2
task.NEXT_LEVEL = 3
task.NEXT_LEVEL_TURN = 4
task.FINISH = 5
task.UNLOAD = 6
task.DIG = 7
task.REFUEL = 8
-- Specifies the direction a tutle turns as well as provides the turn value.
turnDirection = {
LEFT = -1,
RIGHT = 1
}
-- State variables
local size = 0
local depth = 0
local startDepth = 0
local facing = direction.FORWARD
local currTask = task.MINESHAFT
local xzTurnMoves = 0
local mineDirection = 0
local mineX = 1
local mineZ = 1
local nextLevel = 1 -- counter for digging down to the next mining level
local level = 1
local stepsForward = 0
local stepsRight = 0
local stepsDown = 0
local savedForward = 0
local savedRight = 0
local savedDown = 0
local savedFacing = 0
local isPaused = false
local hasModem = 0
local hasEnderChest = 0
local maxSlot = 16
-- save the current state to a file
function save()
local file = fs.open("snapshot", "w")
file.writeLine(currTask)
file.writeLine(size)
file.writeLine(depth)
file.writeLine(startDepth)
file.writeLine(nextLevel)
file.writeLine(mineDirection)
file.writeLine(mineX)
file.writeLine(mineZ)
file.writeLine(xzTurnMoves)
file.writeLine(level)
file.writeLine(stepsForward)
file.writeLine(stepsRight)
file.writeLine(stepsDown)
file.writeLine(savedForward)
file.writeLine(savedRight)
file.writeLine(savedDown)
file.writeLine(facing)
file.writeLine(hasModem)
file.writeLine(hasEnderChest)
file.writeLine(maxSlot)
file.close()
end
-- resume the state saved in a snapshot file
function resume()
local file = fs.open("snapshot", "r")
if file == nil then
print("Failed to open snapshot file. Cannot resume.")
return
end
currTask = tonumber(file.readLine())
size = tonumber(file.readLine())
depth = tonumber(file.readLine())
startDepth = tonumber(file.readLine())
nextLevel = tonumber(file.readLine())
mineDirection = tonumber(file.readLine())
mineX = tonumber(file.readLine())
mineZ = tonumber(file.readLine())
xzTurnMoves = tonumber(file.readLine())
level = tonumber(file.readLine())
stepsForward = tonumber(file.readLine())
stepsRight = tonumber(file.readLine())
stepsDown = tonumber(file.readLine())
savedForward = tonumber(file.readLine())
savedRight = tonumber(file.readLine())
savedDown = tonumber(file.readLine())
facing = tonumber(file.readLine())
hasModem = tonumber(file.readLine())
hasEnderChest = tonumber(file.readLine())
maxSlot = tonumber(file.readLine())
file.close()
end
-- Parse Arguments
if args[1] == "resume" then
resume()
elseif args[1] == nil or args[2] == nil or args[3] == nil or args[4] == nil then
print("hasModem hasEnderChest size depth [startDepth]")
print("Ender chest, if any, should be in slot 16")
return
else
hasModem = tonumber(args[1])
hasEnderChest = tonumber(args[2])
size = tonumber(args[3])
depth = tonumber(args[4])
startDepth = 0
if args[5] ~= nil then
startDepth = tonumber(args[5])
end
if hasEnderChest ~= 0 then
maxSlot = 15
end
end
-- update the direction the turtle is facing
function updateFacing(turnDir)
facing = facing + turnDir
if facing > 3 then
facing = 0
elseif facing < 0 then
facing = 3
end
end
-- move the turlte forward one block and dig any block in its path
function forward()
while not turtle.forward() do
os.sleep(0)
turtle.dig()
end
if facing == direction.FORWARD then
stepsForward = stepsForward + 1
elseif facing == direction.RIGHT then
stepsRight = stepsRight + 1
elseif facing == direction.BACKWARD then
stepsForward = stepsForward - 1
elseif facing == direction.LEFT then
stepsRight = stepsRight - 1
end
save()
end
-- move the turlte down one block and dig any block in its path
function down()
count = 0
while not turtle.down() do
os.sleep(0)
turtle.digDown()
if not turtle.digDown() and turtle.detectDown() then
currTask = task.FINISH
stepsDown = stepsDown - 1
print("Failed to dig down. Going home.")
break
end
count = count + 1
end
stepsDown = stepsDown + 1
save()
end
-- move the turtle up one block and dig any block in its path
function up()
while not turtle.up() do
os.sleep(0)
turtle.digUp()
end
stepsDown = stepsDown - 1
save()
end
-- turn the turtle to the left
function turnLeft()
turtle.turnLeft()
updateFacing(turnDirection.LEFT)
save()
end
-- turn the turtle to the right
function turnRight()
turtle.turnRight()
updateFacing(turnDirection.RIGHT)
save()
end
-- turn the turtle until it is facing the specified direction.
function setFacing(faceDir)
while facing ~= faceDir do
turnRight();
end
end
-- save the turtle current position into buffer variables
function savePosition()
savedForward = stepsForward
savedRight = stepsRight
savedDown = stepsDown
savedFacing = facing
end
-- start the refuel task
function refuel()
for turn=1, 3 do
local hasInventory = false
turnLeft()
for slot=1, maxSlot do
if turtle.suck() then
hasInventory = true
end
while turtle.refuel(slot) do
end
end
if hasInventory then
for slot=1, maxSlot do
turtle.select(slot)
turtle.drop()
end
end
end
if checkNeedsFuel() then
currTask = task.FINISH
end
end
-- return to the saved dig location and continue digging
function returnToDig()
while savedDown ~= stepsDown do
if savedDown < stepsDown then
up()
elseif savedDown > stepsDown then
down()
end
end
if savedRight < stepsRight then
setFacing(direction.LEFT)
elseif savedRight > stepsRight then
setFacing(direction.RIGHT)
end
while savedRight ~= stepsRight do
forward()
end
if savedForward < stepsForward then
setFacing(direction.BACKWARD)
elseif savedForward > stepsForward then
setFacing(direction.FORWARD)
end
while savedForward ~= stepsForward do
forward()
end
setFacing(savedFacing)
currTask = task.MINEXZ
end
-- unload the turtles ender chest
function enderUnload()
savePosition()
turtle.select(16)
turtle.digUp()
while not turtle.placeUp() do
turtle.digUp()
end
for slot=1, maxSlot do
turtle.select(slot)
turtle.dropUp()
end
turtle.select(16)
turtle.drop()
turtle.digUp()
turtle.select(1)
currTask = task.DIG
end
-- return back to the location the turtle was at when the program was started
function returnHome()
savePosition()
if stepsForward > 0 then
setFacing(direction.BACKWARD)
elseif stepsForward < 0 then
setFacing(direction.FORWARD)
end
while stepsForward ~= 0 do
forward()
end
if stepsRight > 0 then
setFacing(direction.LEFT)
elseif stepsRight < 0 then
setFacing(direction.RIGHT)
end
while stepsRight ~= 0 do
forward()
end
while stepsDown ~= 0 do
if stepsDown > 0 then
up()
elseif stepsDown < 0 then
down()
end
end
setFacing(direction.BACKWARD)
for slot=1, maxSlot do
turtle.select(slot)
turtle.drop()
end
if currTask == task.FINISH then
setFacing(direction.FORWARD)
return
end
if currTask == task.UNLOAD or currTask == task.REFUEL then
currTask = task.DIG
refuel()
end
end
-- determine if inventory is full (or near full)
function isInventoryFull()
local used = 0
for slot=1, maxSlot do
used = used + turtle.getItemCount(slot)
end
if used > 400 then
return true
end
return false
end
-- estimate the distance, and therefore the amount of fuel needed to return home
function estimateDistanceHome()
return math.abs(stepsForward) + math.abs(stepsRight) + math.abs(stepsDown) + 16;
end
-- determine if the turtle should refuel
function checkNeedsFuel()
local fuel = turtle.getFuelLevel()
if fuel ~= nil and fuel <= estimateDistanceHome() + 10 then
return true
end
return false
end
-- dig along the X/Z axis
function mineXZ()
local turnFlag = mineDirection % 2 == 1
turtle.digUp()
turtle.digDown()
forward()
turtle.digUp()
turtle.digDown()
if checkNeedsFuel() then
currTask = task.UNLOAD
return
end
if isInventoryFull() then
currTask = task.UNLOAD
return
end
mineZ = mineZ + 1
if mineZ >= size then
mineZ = 1
mineX = mineX + 1
mineDirection = mineDirection + 1
if mineX > size then
currTask = task.NEXT_LEVEL_TURN
else
currTask = task.MINEXZ_TURN
end
save()
return
end
if mineX > size then
mineX = 1
mineZ = 1
--mineDirection = 0
currTask = task.NEXT_LEVEL
save()
end
end
-- turn while digging on the X/Z axis
function mineXZ_Turn(moveForward)
local turnFlag = mineDirection % 2 == 1
if xzTurnMoves > 4 then
xzTurnMoves = 0
currTask = task.MINEXZ
return
end
if turnFlag then
if xzTurnMoves == 0 then
turnLeft()
end
if xzTurnMoves == 4 then
turnLeft()
end
else
if xzTurnMoves == 0 then
turnRight()
end
if xzTurnMoves == 4 then
turnRight()
end
end
if xzTurnMoves == 1 and moveForward then
forward()
end
if xzTurnMoves == 2 then
turtle.digUp()
end
if xzTurnMoves == 3 then
turtle.digDown()
end
xzTurnMoves = xzTurnMoves + 1
end
-- dig the initial mineshaft to reach the dig start point
function digMineShaft()
if stepsDown == startDepth then
currTask = task.MINEXZ
return
end
down()
end
-- move down to the next layer
function mineNextLevel()
if level >= depth then
currTask = task.FINISH
return
end
if nextLevel > 3 then
mineX = 1
mineZ = 1
mineDirection = mineDirection + 1
level = level + 1
currTask = task.MINEXZ
nextLevel = 1
turtle.digDown()
return
end
nextLevel = nextLevel + 1
down()
end
-- process messages from wireless computer
function processMessages()
if hasModem == 0 or hasModem == nil then
return
end
rednet.open("right")
local senderId, message = rednet.receive(0.1)
if message == nil then
return
end
print("Received " .. message)
if message == "finishMining" then
isPaused = false
currTask = task.FINISH
print("Received command to finish.")
end
if message == "unloadMining" then
isPaused = false
currTask = task.UNLOAD
print("Received command to unload inventory at home base.")
end
if message == "pauseMining" then
isPaused = true
save()
print("Received command to pause.")
end
if message == "resumeMining" then
isPaused = false
print("Received command to resume.")
end
if message == "refuelMining" then
isPaused = false
currTask = task.REFUEL
print("Received command to refuel.")
end
rednet.send(senderId, "acknowledged")
end
-- main program loop
while true do
if not isPaused then
if currTask == task.MINESHAFT then
digMineShaft()
end
if currTask == task.MINEXZ then
mineXZ()
end
if currTask == task.MINEXZ_TURN then
mineXZ_Turn(true)
end
if currTask == task.NEXT_LEVEL then
mineNextLevel()
end
if currTask == task.NEXT_LEVEL_TURN then
mineXZ_Turn(false)
if currTask == task.MINEXZ then
currTask = task.NEXT_LEVEL
end
end
if currTask == task.UNLOAD then
if hasEnderChest == 0 then
returnHome()
else
enderUnload()
end
end
if currTask == task.REFUEL then
returnHome()
end
if currTask == task.DIG then
returnToDig()
end
if currTask == task.FINISH then
break
end
end
processMessages()
if not isPaused then
save()
end
end
returnHome()
setFacing(direction.FORWARD)
save()
-- Computer script to send wireless commands to mining turtle
args = { ... }
-- turtleid unload|finish|pause|restart [top|left|right|back]
local turtleId = 0
local cmd = ""
local position = "top"
local ack = nil
if args[1] == nil or args[2] == nil then
print("turtleId unload|finish|pause|restart [top|left|right|back]")
return
end
turtleId = tonumber(args[1])
cmd = args[2]
if args[3] ~= nil then
position = args[3]
end
cmd = cmd .. "Mining"
print("Sending command " .. cmd .. " to turtle " .. turtleId .. " on " .. position .. " modem.")
rednet.open(position)
while true do
rednet.send(turtleId, cmd)
local senderId, message = rednet.receive(0.5)
if message == "acknowledged" then
break
end
os.sleep(0.1)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment