Skip to content

Instantly share code, notes, and snippets.

@kyle1elyk
Last active March 2, 2021 17:57
Work in progress mining turtle script for ComputerCraft Tweaked 1.12.2
--[[
newmine.lua
kyle1elyk 2021-02-27
CraftOS 1.8
Uses: mpeterv/argparse (with minor conversion to CraftOS 1.8)
https://raw.githubusercontent.com/mpeterv/argparse/master/src/argparse.lua
]]
--[Current Position]
local curPos, curDir = vector.new(0, 0, 0), 0
--[Initial Position and Direction]
local iniPos, iniDir = vector.new(0, 0, 0), 0
inventory = {}
inventoryNamed = {}
local status = "Not Set."
local facing = {[0] = "South", "West", "North", "East"}
local mineLevel, mineHeight, corridorLength, branchLength = 0, 0, 0, 0
local useRednet = false
local rednetTarget = nil
local includesList, excludesList = nil, nil
local reportAllOre, excludeTrashBlocks = nil, nil
local argparse = require "argparse"
--[Setting up argument parsing]
local parser = argparse("newmine", "Mining program by kyle1elyk")
parser:option("-l --mine-level", "Mine Level", 12)
parser:option("-m --mine-height", "Mine Height", 3)
parser:option("-c --corridor-length", "Corridor Length", 16)
parser:option("-b --branch-length", "Branch Length", 16)
parser:option("-d --direction", "Initial direction", 0)
parser:mutex(
parser:option("-p --pos", "Start Position", {0,0,0}) :args(3),
parser:flag("--gps", "GPS Position")
)
parser:option("-r --rednet", "Enable rednet, b for broadcast")
parser:mutex(
parser:option("-e --exclude", "Exclude blocks to be mined") :args("+"),
parser:option("-i --include", "Seek blocks to be mined") :args("+")
)
local args = parser:parse()
--[End argument parsing setup]
term.clear()
term.setCursorPos(0, 0)
function cloneVector(v)
return vector.new(v.x,v.y,v.z)
end
--[Handle Rednet flag]
local function getModemSide()
local sides = {"left", "right"}
for i, side in ipairs(sides) do
if peripheral.getType(side) == "modem" then
return side
end
end
end
if args.rednet then
local side = peripheral.find("modem")
if side then
if args.rednet == "b" then
rednetTarget = nil
elseif isnumber(args.rednet) then
rednetTarget = isnumber(args.rednet)
else
error("Invalid Rednet Target")
end
rednet.open(getModemSide())
useRednet = true
print("Using Rednet")
else
error("No Modem, can not use Rednet")
end
else
print("No rednet")
end
--[Handle position argument]
if not args.gps then
local x,y,z = unpack(args.pos)
if string.sub(x, 1, 1) == "_" then x = "-" .. string.sub(x, 2) end
if string.sub(y, 1, 1) == "_" then y = "-" .. string.sub(y, 2) end
if string.sub(z, 1, 1) == "_" then z = "-" .. string.sub(z, 2) end
curPos = vector.new(tonumber(x), tonumber(y), tonumber(z))
else
local x,y,z = gps.locate()
if not x then
error("Failed to get GPS")
end
curPos = vector.new(x,y,z)
end
--[Handle Direction argument]
if tonumber(args.direction) then
local d = tonumber(args.direction)
if d >= 0 and d < 4 then
curDir = d
else
error("Direction must be 0 to 3")
end
else
local c = string.lower(string.sub(args.direction, 1, 1))
if c == "s" then
curDir = 0
elseif c == "w" then
curDir = 1
elseif c == "n" then
curDir = 2
elseif c == "e" then
curDir = 3
else
error("Invalid direction")
end
end
print("Position set to", curPos, "facing", facing[curDir])
iniPos = cloneVector(curPos)
iniDir = curDir
--[Handle Include/Exclude list]
if args.include then
includesList = {}
print("Only reporting:")
for i, block in ipairs(args.include) do
if block == "ore" then
reportAllOre = true
else
includesList[block] = block
io.write(block, " ")
end
end
elseif args.exclude then
excludesList = {}
print("Reporting everything, except:")
for i, block in ipairs(args.exclude) do
if block == "trash" then
excludeTrashBlocks = true
else
excludesList[block] = block
io.write(block, " ")
end
end
end
print()
mineLevel = tonumber(args.mine_level) or error("Mine Level is not a number")
mineHeight = tonumber(args.mine_height) or error("Mine Height is not a number")
corridorLength = tonumber(args.corridor_length) or error("Corridor Length is not a number")
branchLength = tonumber(args.branch_length) or error("Branch Length is not a number")
print("Mining at", mineLevel)
print("Tunnel Height", mineHeight)
print("Corridor length", corridorLength)
print("Branch Height", branchLength)
--[[
TURTLE FUNCTIONS
--]]
function syncInventory()
local differences = {}
inventoryNamed = {}
for i=16, 1, -1 do
local thisItemSlot = turtle.getItemDetail(i)
if inventory[i] and thisItemSlot then
if inventory[i].name ~= thisItemSlot.name or inventory[i].count ~= thisItemSlot.count or inventory[i].damage ~= thisItemSlot.damage then
table.insert(differences, i)
end
elseif inventory[i] ~= thisItemSlot then
table.insert(differences, i)
end
inventory[i] = thisItemSlot
if thisItemSlot then
inventoryNamed[thisItemSlot.name] = i
end
end
return differences
end
function waitOnFuel(amount) -- [This function is blocking until inventory changes]
amount = amount or 1
local fuel = {
["minecraft:coal"] = 80,
["minecraft:coal_block"] = 800,
["minecraft:lava_bucket"] = 1000
}
fueled = 0
while fueled < amount do
for i=1, 16 do
if turtle.getItemCount(i) > 0 then
local itemName = turtle.getItemDetail(i).name
if fuel[itemName] then
local halfStack = math.min(turtle.getItemCount(i), math.ceil((amount - fueled) / fuel[itemName]))
fueled = fueled + fuel[itemName] * halfStack
turtle.select(i)
turtle.refuel(halfStack)
print ("Fueled", fuel[itemName] * halfStack, "with", halfStack,itemName)
if fueled < amount then
print ("Waiting on", amount - fueled , "fuel")
end
break
end
end
end
if fueled < amount then
print ("Waiting on", amount, "fuel")
os.pullEvent("turtle_inventory")
end
end
end
function forward(n, noDig)
if n and n < 0 then return back(-n, noDig) end
for i=1, n or 1 do
if turtle.getFuelLevel() < 1 then
waitOnFuel()
end
if not turtle.forward() then
repeat
if not noDig then turtle.dig() end
turtle.attack()
until turtle.forward()
end
if curDir == 0 then
curPos.z = curPos.z + 1
elseif curDir == 1 then
curPos.x = curPos.x - 1
elseif curDir == 2 then
curPos.z = curPos.z - 1
elseif curDir == 3 then
curPos.x = curPos.x + 1
end
end
return true
end
function up(n, noDig)
if n and n < 0 then return down(-n, noDig) end
for i=1, n or 1 do
if turtle.getFuelLevel() < 1 then
waitOnFuel()
end
if not turtle.up() then
repeat
if not noDig then turtle.digUp() end
turtle.attackUp()
until turtle.up()
end
curPos.y = curPos.y + 1
end
return true
end
function down(n, noDig)
if n and n < 0 then return up(-n, noDig) end
for i=1, n or 1 do
if turtle.getFuelLevel() < 1 then
waitOnFuel()
end
if not turtle.down() then
repeat
if not noDig then turtle.digDown() end
turtle.attackDown()
until turtle.down()
end
curPos.y = curPos.y - 1
end
return true
end
function turnRight(n) --[turns Right n times]
n = n or 1
if n and n < 0 then return turnLeft(-n) end
for i=n,1,-1 do
turtle.turnRight()
curDir = curDir + 1
if curDir == 4 then curDir = 0 end
end
end
function turnLeft(n) --[Turns left n times]
n = n or 1
if n and n < 0 then return turnRight(-n) end
for i=n,1,-1 do
turtle.turnLeft()
curDir = curDir - 1
if curDir == -1 then curDir = 3 end
end
end
function dig()
turtle.dig()
end
-- forward(1, true)
-- turnLeft()
-- turnLeft(2)
-- turnRight(-1) -> turnLeft(1)
function mine()
local branches = math.ceil(corridorLength / 3)
local cycles = math.ceil(branches / 2)
local branch = 0
forward() -- TODO: uncomment
local mineStartPos, mineDir = cloneVector(curPos), curDir
function atCorridorEnd(n, db)
n = n or 0
local checkVal = nil
local endX, endZ = curPos.x, curPos.z
if curDir == 0 then
endZ = endZ + n
elseif curDir == 1 then
endX = endX - n
elseif curDir == 2 then
endZ = endZ - n
elseif curDir == 3 then
endX = endX + n
end
if mineDir == 0 then
checkVal = mineStartPos.z + (corridorLength - 1)
return endZ >= checkVal
elseif mineDir == 1 then
checkVal = mineStartPos.x - (corridorLength - 1)
return endX <= checkVal
elseif mineDir == 2 then
checkVal = mineStartPos.z - (corridorLength - 1)
return endZ <= checkVal
elseif mineDir == 3 then
checkVal = mineStartPos.x + (corridorLength - 1)
return endX >= checkVal
end
end
function atCorridorStart()
if mineDir % 2 == 0 then
return curPos.z == mineStartPos.z
else
return curPos.x == mineStartPos.x
end
end
function atBottom()
return curPos.y == mineStartPos.y
end
function atTop()
return curPos.y == mineStartPos.y + mineHeight - 1
end
local placeTorch = 0
function digWallInfront()
local goUp = atBottom()
dig()
if goUp then
while not atTop() do
up()
repeat
dig()
os.sleep(0.15)
until not turtle.detect()
end
else
while not atBottom() do
down()
repeat
dig()
os.sleep(0.15)
until not turtle.detect()
end
syncInventory()
local torchSlot = inventoryNamed["minecraft:torch"]
if torchSlot and turtle.getItemCount(torchSlot) > 0 and turtle.getItemDetail(torchSlot).name:find("torch") then
if placeTorch <= 0 then
turtle.digUp()
turtle.select(torchSlot)
if turtle.placeUp() then
placeTorch = 2
end
turtle.select(1)
else
placeTorch = placeTorch - 1
end
end
end
end
function digBranch()
branch = branch + 1
print("Branch", branch, "/", branches)
if branchLength % 2 == 1 then
digWallInfront()
forward()
end
for iBranch=1, math.floor(branchLength / 2) do
digWallInfront()
forward(2)
end
end
-- print(atCorridorStart(), atCorridorEnd())
-- forward(1, true)
-- print(atCorridorStart(), atCorridorEnd())
-- forward(1, true)
-- print(atCorridorStart(), atCorridorEnd())
-- digWallInfront()
-- forward(2)
-- digWallInfront()
local branchFuelCost = (branchLength * mineHeight) - ((mineHeight - 1) * math.floor((branchLength - 1) / 2 ))
local cycleFuelCost = (2 * branchFuelCost) + (2 * (mineHeight - 1) + 3)
for cycle=1, cycles do
if (cycleFuelCost > turtle.getFuelLevel()) then
waitOnFuel(cycleFuelCost - turtle.getFuelLevel())
end
-- if not at corridor end
-- mine main corridor ahead
if not atCorridorEnd() then
digWallInfront()
end
-- turn left and go to end
turnLeft()
digBranch()
-- turn left to mine behind if not at corridor start
if not atCorridorStart() then
turnLeft()
digWallInfront()
turnRight()
end
-- [facing away from corridor here]
-- if not corridor end
-- go to next branch location
-- mine ahead
turnRight()
if not atCorridorEnd(2) then
digWallInfront()
forward(2)
digWallInfront()
forward()
if not atCorridorEnd() then
digWallInfront()
end
turnRight()
else
turnRight()
end
-- [facing corridor here]
-- head back to main corridor
digBranch()
-- mine behind in main corridor
turnRight()
digWallInfront()
turnLeft()
-- if not corridor end
-- go to next branch location
turnLeft()
for i=1,3 do
if not atCorridorEnd() then
digWallInfront()
forward()
end
end
end
--[[for i=1, mineHeight - 2 do
print(corridorLength, branches)
end]]
end
mine()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment