Advertisement
OldDragon2A

Efficient Miner

Dec 20th, 2012
2,998
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.97 KB | None | 0 0
  1. -- Efficient Miner
  2.  
  3. -- Fuel will be pulled from the internal
  4. -- slot first, chest if equipped and then
  5. -- from the drop slots. When the drop
  6. -- slots are full the turtle will either
  7. -- use the ender chest or return and drop
  8. -- behind the starting point.
  9.  
  10. local position         = { 0, 0, 0, 3 }
  11. local drop_position    = { 0, 0, 0, 1 }
  12. local drop_slots       = { 1, 11 }
  13. local drop_chest_slot  = 12
  14. local torch_slot       = 13
  15. local torch_chest_slot = 14
  16. local fuel_slot        = 15
  17. local fuel_chest_slot  = 16
  18. local refuel_level     = 0
  19. local torch_spacing    = 7
  20.  
  21. local state = {
  22.   verbose          = 0,
  23.   use_torches      = true,
  24.   torch_wait       = false,
  25.   dig_mode         = false,
  26.   dropping         = false,
  27.   log_file         = nil
  28. }
  29. local log_handle       = nil
  30.  
  31. -- Function Definitions
  32. local dropOff, refuel
  33.  
  34. local function deepcopy(orig)
  35.   local orig_type = type(orig)
  36.   local copy
  37.   if orig_type == 'table' then
  38.     copy = {}
  39.     for orig_key, orig_value in next, orig, nil do
  40.       copy[deepcopy(orig_key)] = deepcopy(orig_value)
  41.     end
  42.     setmetatable(copy, deepcopy(getmetatable(orig)))
  43.   else
  44.     copy = orig
  45.   end
  46.   return copy
  47. end
  48. local function getopt(optstring, ...)
  49.   local opts = { }
  50.   local args = { ... }
  51.  
  52.   for optc, optv in optstring:gmatch"(%a)(:?)" do
  53.     opts[optc] = { hasarg = optv == ":" }
  54.   end
  55.  
  56.   return coroutine.wrap(function()
  57.     local yield = coroutine.yield
  58.     local i = 1
  59.  
  60.     while i <= #args do
  61.       local arg = args[i]
  62.  
  63.       i = i + 1
  64.  
  65.       if arg == "--" then
  66.         break
  67.       elseif arg:sub(1, 1) == "-" then
  68.         for j = 2, #arg do
  69.           local opt = arg:sub(j, j)
  70.  
  71.           if opts[opt] then
  72.             if opts[opt].hasarg then
  73.               if j == #arg then
  74.                 if args[i] then
  75.                   yield(opt, args[i])
  76.                   i = i + 1
  77.                 elseif optstring:sub(1, 1) == ":" then
  78.                   yield(':', opt)
  79.                 else
  80.                   yield('?', opt)
  81.                 end
  82.               else
  83.                 yield(opt, arg:sub(j + 1))
  84.               end
  85.  
  86.               break
  87.             else
  88.               yield(opt, false)
  89.             end
  90.           else
  91.             yield('?', opt)
  92.           end
  93.         end
  94.       else
  95.         yield(false, arg)
  96.       end
  97.     end
  98.  
  99.     for i = i, #args do
  100.       yield(false, args[i])
  101.     end
  102.   end)
  103. end
  104. local function writeLog(msg)
  105.   if state.log_file ~= nil then
  106.     writeLog = function (msg)
  107.       log_handle = fs.open(state.log_file, 'a')
  108.       log_handle.writeLine(msg)
  109.       log_handle.close()
  110.     end
  111.   else
  112.     writeLog = print
  113.   end
  114.   writeLog(msg)
  115. end
  116.  
  117. local function formatPosition(p)
  118.   return p[1]..","..p[2]..","..p[3]..(p[4] == nil and "" or "," .. p[4])
  119. end
  120. local function updatePosition(axis, value)
  121.   if axis == 4 then
  122.     position[axis] = (position[axis] + value) % 4
  123.   else
  124.     position[axis] = position[axis] + value
  125.   end
  126. end
  127. local function inPosition(p)
  128.   return p ~= nil and position[1] == p[1] and position[2] == p[2] and position[3] == p[3]
  129. end
  130.  
  131. local function getEmptySlots()
  132.   local numslots = 0
  133.   for i = drop_slots[1], drop_slots[2] do
  134.     if turtle.getItemCount(i) == 0 then
  135.       numslots = numslots + 1
  136.     end
  137.   end
  138.   return numslots
  139. end
  140.  
  141. local function dig(all)
  142.   if all == nil then all = true end
  143.   if not state.dig_mode then return end
  144.   while turtle.detect() do
  145.     while turtle.suck() do if getEmptySlots() < 2 then dropOff() end end
  146.     if turtle.dig() and getEmptySlots() < 2 then dropOff() end
  147.     if not all then break end
  148.     sleep(0.4)
  149.   end
  150. end
  151. local function digUp(all)
  152.   if all == nil then all = true end
  153.   if not state.dig_mode then return end
  154.   while turtle.detectUp() do
  155.     while turtle.suckUp() do if getEmptySlots() < 2 then dropOff() end end
  156.     if turtle.digUp() and getEmptySlots() < 2 then dropOff() end
  157.     if not all then break end
  158.     sleep(0.4)
  159.   end
  160. end
  161. local function digDown()
  162.   if not state.dig_mode then return end
  163.   while turtle.suckDown() do if getEmptySlots() < 2 then dropOff() end end
  164.   if turtle.digDown() and getEmptySlots() < 2 then dropOff() end
  165. end
  166.  
  167. local move = {}
  168. function move.forward()
  169.   turtle.attack()
  170.   dig()
  171.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  172.   if turtle.forward() then
  173.     if     (position[4] == 0) then updatePosition(3,1)
  174.     elseif (position[4] == 1) then updatePosition(1,-1)
  175.     elseif (position[4] == 2) then updatePosition(3,-1)
  176.     elseif (position[4] == 3) then updatePosition(1,1)
  177.     end
  178.     return true
  179.   else
  180.     return false
  181.   end
  182. end
  183. function move.back()
  184.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  185.   if turtle.back() then
  186.     if     (position[4] == 0) then updatePosition(3,-1)
  187.     elseif (position[4] == 1) then updatePosition(1,1)
  188.     elseif (position[4] == 2) then updatePosition(3,1)
  189.     elseif (position[4] == 3) then updatePosition(1,-1)
  190.     end
  191.     return true
  192.   else
  193.     return false
  194.   end
  195. end
  196. function move.up()
  197.   turtle.attackUp()
  198.   digUp()
  199.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  200.   local state = turtle.up()
  201.   if (state) then updatePosition(2,1) end
  202.   return state
  203. end
  204. function move.down()
  205.   turtle.attackDown()
  206.   digDown()
  207.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  208.   local state = turtle.down()
  209.   if (state) then updatePosition(2,-1) end
  210.   return state
  211. end
  212. function move.right()
  213.   updatePosition(4,1)
  214.   turtle.turnRight()
  215. end
  216. function move.left()
  217.   updatePosition(4,-1)
  218.   turtle.turnLeft()
  219. end
  220. function move.turn(d)
  221.   if (d == nil) then return end
  222.   while position[4] ~= d do
  223.     local diff = position[4] - d
  224.     if diff == 1 or diff == -3 then move.left() else move.right() end
  225.   end
  226. end
  227.  
  228. local function moveX(x, wait)
  229.   if (wait == nil) then wait = false end
  230.   local result = true
  231.   if (position[1] == x) then return result end
  232.   move.turn(position[1] < x and 3 or 1)
  233.   while position[1] ~= x do
  234.     result = move.forward()
  235.     if (not result and not wait) then break end
  236.   end
  237.   return result
  238. end
  239. local function moveY(y, wait)
  240.   if (wait == nil) then wait = false end
  241.   local result = true
  242.   if (position[2] == y) then return result end
  243.   while position[2] ~= y do
  244.     result = position[2] < y and move.up() or move.down()
  245.     if (not result and not wait) then break end
  246.   end
  247.   return result
  248. end
  249. local function moveZ(z, wait)
  250.   if (wait == nil) then wait = false end
  251.   local result = true
  252.   if (position[3] == z) then return result end
  253.   move.turn(position[3] < z and 0 or 2)
  254.   while position[3] ~= z do
  255.     result = move.forward()
  256.     if (not result and not wait) then break end
  257.   end
  258.   return result
  259. end
  260. local function gotoMine(p, wait)
  261.   moveX(p[1], wait)
  262.   moveZ(p[3], wait)
  263.   moveY(p[2], wait)
  264.   if (p[4] ~= nil) then move.turn(p[4]) end
  265. end
  266. local function gotoSimple(p, wait)
  267.   if (wait == nil) then wait = true end
  268.   while not inPosition(p) do
  269.     if(p[3] == nil) then
  270.       moveX(p[1], false)
  271.       moveZ(p[3], false)
  272.     else
  273.       moveX(p[1], false)
  274.       moveZ(p[3], false)
  275.       moveY(p[2], false)
  276.     end
  277.     if wait then sleep(0.1) else break end
  278.   end
  279.   if (p[4] ~= nil) then move.turn(p[4]) end
  280. end
  281. local function pathFind(level)
  282.   if level%5 == 0 then
  283.     move.left()
  284.     for cl = 0,level,1 do
  285.       move.forward()
  286.       cl=cl+1
  287.     end
  288.   elseif level%5 == 1 then
  289.     move.left()
  290.     for cl = 0,level,1 do
  291.       move.forward()
  292.       move.up()
  293.     end
  294.   elseif level%5 == 2 then
  295.     move.left()
  296.     for cl = 0,level,1 do
  297.       move.up()
  298.     end
  299.   elseif level%5 == 3 then
  300.     move.right()
  301.     for cl = 0,level,1 do
  302.       move.forward()
  303.       move.up()
  304.     end
  305.   elseif level%5 == 4 then
  306.     move.right()
  307.     for cl = 0,level,1 do
  308.       move.forward()
  309.     end
  310.   end
  311. end
  312. local function gotoSmart(p)
  313.   if (p == nil) then return false end
  314.  
  315.   local last
  316.   for tries = 0,8,1 do
  317.     if position[2] <= p[2] then moveY(p[2]) end
  318.     if (tries%2) == 0 then
  319.       moveX(p[1])
  320.       moveZ(p[3])
  321.     else
  322.       moveZ(p[3])
  323.       moveX(p[1])
  324.     end
  325.     if position[2] > p[2] then moveY(p[2]) end
  326.    
  327.     if inPosition(p) then break end
  328.    
  329.     if inPosition(last) then
  330.       pathFind(tries)
  331.     end
  332.     last = deepcopy(position)
  333.   end
  334.  
  335.   if not inPosition(p) then gotoSimple(p, false) end
  336.   if (p[4] ~= nil) then move.turn(p[4]) end
  337.   return inPosition(p)
  338. end
  339.  
  340. local function getOpenSpace()
  341.   local result = {}
  342.   if not turtle.detectUp() then
  343.     result.place  = turtle.placeUp
  344.     result.detect = turtle.detectUp
  345.     result.drop   = turtle.dropUp
  346.     result.suck   = turtle.suckUp
  347.     result.dig    = turtle.digUp
  348.   elseif not turtle.detectUp() then
  349.     result.place  = turtle.placeUp
  350.     result.detect = turtle.detectUp
  351.     result.drop   = turtle.dropUp
  352.     result.suck   = turtle.suckUp
  353.     result.dig    = turtle.digUp
  354.   elseif not turtle.detectDown() then
  355.     result.place  = turtle.placeDown
  356.     result.detect = turtle.detectDown
  357.     result.drop   = turtle.dropDown
  358.     result.suck   = turtle.suckDown
  359.     result.dig    = turtle.digDown
  360.   else
  361.     result        = nil
  362.   end
  363.   return result
  364. end
  365. local function useChest(slot, callback, param)
  366.   local chest = getOpenSpace()
  367.   local result = false
  368.   local op = false
  369.   if chest ~= nil then
  370.     turtle.select(slot)
  371.     if chest.place() then
  372.       result = true
  373.       if callback ~= nil then result = callback(chest, param) end
  374.       turtle.select(slot)
  375.       chest.dig()
  376.     else
  377.       op = true
  378.     end
  379.   end
  380.   if op then
  381.     move.left()
  382.     move.left()
  383.     if turtle.detect() then
  384.       turtle.select(slot)
  385.       if turtle.place() then
  386.         result = true
  387.         if callback ~= nil then result = callback(chest, param) end
  388.         turtle.select(slot)
  389.         turtle.dig()
  390.       end
  391.     end
  392.     move.left()
  393.     move.left()
  394.   end
  395.   return result
  396. end
  397. local function dropItemsInChest(chest)
  398.   local result = false
  399.   if chest.detect() then
  400.     for i = drop_slots[1], drop_slots[2] do
  401.       turtle.select(i)
  402.       chest.drop()
  403.     end
  404.     result = true
  405.   end
  406.   return result
  407. end
  408. local function getItemFromChest(chest, param)
  409.   turtle.select(param)
  410.   return chest.detect() and chest.suck()
  411. end
  412.  
  413. dropOff = function ()
  414.   if state.dropping then return true end
  415.   if state.verbose then writeLog("Drop Off") end
  416.   local nochest
  417.   state.dropping = true
  418.   state.dig_mode = false
  419.   local resume = deepcopy(position)
  420.   repeat
  421.     if not useChest(drop_chest_slot, dropItemsInChest) then
  422.       gotoSmart(drop_position)
  423.       if turtle.detect() then
  424.         for i = drop_slots[1], drop_slots[2] do
  425.           turtle.select(i)
  426.           turtle.drop()
  427.         end
  428.       else
  429.         writeLog("No Chest Found")
  430.         sleep(1)
  431.       end
  432.     end
  433.   until getEmptySlots() > 1
  434.   gotoSmart(resume)
  435.   state.dig_mode = true
  436.   state.dropping = false
  437.   turtle.select(drop_slots[1])
  438.   if state.verbose then writeLog("Resuming") end
  439. end
  440.  
  441. local function refuelFrom(slot)
  442.   local result
  443.   turtle.select(slot)
  444.   while turtle.getItemCount(slot) ~= 0 and (turtle.getFuelLevel() < refuel_level or turtle.getFuelLevel() == 0) do
  445.     if not turtle.refuel(1) then break end
  446.   end
  447. end
  448. refuel = function ()
  449.   if state.verbose then writeLog("Refueling") end
  450.   while turtle.getFuelLevel() == 0 do
  451.     if turtle.getItemCount(fuel_slot) ~= 0 or useChest(fuel_chest_slot, getItemFromChest, fuel_slot) then
  452.       if state.verbose > 1 then writeLog("Checking Fuel Slot") end
  453.       refuelFrom(fuel_slot)
  454.     else
  455.       if state.verbose > 1 then writeLog("Searching Drop Slots") end
  456.       for i = drop_slots[1], drop_slots[2] do
  457.         refuelFrom(i)
  458.         if turtle.getFuelLevel() >= refuel_level then break end
  459.       end
  460.     end
  461.     if turtle.getFuelLevel() == 0 then sleep(1) end
  462.   end
  463.   turtle.select(drop_slots[1])
  464.   if state.verbose then writeLog("Resuming") end
  465. end
  466.  
  467. local function placeTorch(face, surface)
  468.   local isDown, result
  469.   isDown = face == -1
  470.   if not isDown then move.turn(face) end
  471.   turtle.select(torch_slot)
  472.   result = isDown and turtle.placeDown() or turtle.place()
  473.   return result
  474. end
  475. local function torch(face, surface)
  476.   if not state.use_torches then return true end
  477.   if surface == nil then surface = face end
  478.   local placed = false
  479.   if state.verbose == 1 then writeLog("Torch")
  480.   elseif state.verbose > 1 then writeLog("Torch (" .. face .. "," .. surface .. ")") end
  481.   repeat
  482.     if turtle.getItemCount(torch_slot) ~= 0 or useChest(torch_chest_slot, getItemFromChest, torch_slot) then
  483.       placed = placeTorch(face, surface)
  484.     elseif state.torch_wait then
  485.       sleep(1)
  486.     end
  487.   until placed or not state.torch_wait
  488.   turtle.select(drop_slots[1])
  489. end
  490.  
  491. local function getDirection(s, e)
  492.   return {
  493.     s[1] - e[1] <= 0 and 1 or -1,
  494.     s[2] - e[2] <= 0 and 1 or -1,
  495.     s[3] - e[3] <= 0 and 1 or -1
  496.   }
  497. end
  498.  
  499. local function mine(size)
  500.   local current = deepcopy(position)
  501.   current[4] = nil
  502.   local initial = deepcopy(current)
  503.   local final   = { initial[1] + size[1], initial[2] + size[2], initial[3] + size[3] }
  504.   local rest    = deepcopy(position)
  505.  
  506.   local d          = getDirection(current, final)
  507.   local y,  ye, yf = initial[2], final[2] + d[2], math.min(initial[2], final[2])
  508.   local ya         = yf + 1
  509.   local xs, xe, xd = nil, nil, '?'
  510.   local zs, ze, zd = nil, nil, '?'
  511.   local xts        = math.ceil(math.min(final[1], torch_spacing)/2)
  512.   local zts        = math.ceil(math.min(final[3], torch_spacing)/2)
  513.   local xf, xfi, xff, xfb, zf, zfi, zff, zfb
  514.   local h, h2, h3
  515.   xf, zf = '?', '?'
  516.   if d[1] == 1 then xfi, xff = 1, 3 else xfi, xff = 3, 1 end
  517.   if d[3] == 1 then zfi, zff = 2, 0 else zfi, zff = 0, 2 end
  518.   if d[2] == 1 then h2, h3 = digDown, digUp else h2, h3 = digUp, digDown end
  519.  
  520.   if state.verbose > 0 then writeLog("Mining") end
  521.   state.dig_mode = true
  522.   if state.verbose > 1 then writeLog("yf: " .. yf .. "  xts: " .. xts .. "  zts: " .. zts) end
  523.   turtle.select(drop_slots[1])
  524.   -- Y axis
  525.   while y ~= final[2] + d[2] do
  526.     -- check if mining above and/or below would help
  527.     if y == final[2] then
  528.       h = 1
  529.     elseif y + d[2] == final[2] then
  530.       h = 2
  531.       y = y + d[2]
  532.     else
  533.       h = 3
  534.       y = y + d[2]
  535.     end
  536.     current[2] = y
  537.     gotoMine(current)
  538.     if state.verbose > 2 then writeLog("Y: " .. formatPosition(position) .. " h=" .. h .. " xf=" .. xf .." xd=" .. xd .. " zf=" .. zf .." zd=" .. zd) end
  539.  
  540.     -- Z axis
  541.     if current[3] == initial[3] then
  542.       zs, ze, zd = initial[3], final[3],  d[3]
  543.     else
  544.       zs, ze, zd = final[3], initial[3], -d[3]
  545.     end
  546.     if state.use_torches then
  547.       zfb = zd == 1 and 2 or 0
  548.     end
  549.  
  550.     for z = zs,ze,zd do
  551.       current[3] = z
  552.       gotoMine(current)
  553.       if state.verbose > 2 then writeLog("Z: " .. formatPosition(position) .. " h=" .. h .. " xf=" .. xf .." xd=" .. xd .. " zf=" .. zf .." zd=" .. zd) end
  554.  
  555.       -- X axis
  556.       if current[1] == initial[1] then
  557.         xs, xe, xd = initial[1], final[1],  d[1]
  558.       else
  559.         xs, xe, xd = final[1], initial[1], -d[1]
  560.       end
  561.       if state.use_torches then
  562.         xfb = xd == 1 and 1 or 3
  563.         zf = math.fmod(current[3], torch_spacing)
  564.       end
  565.      
  566.       for x = xs,xe,xd do
  567.         current[1] = x
  568.         gotoMine(current)
  569.         if h > 1 then h2() end
  570.         if h > 2 then h3() end
  571.         if state.verbose > 2 then writeLog("X: " .. formatPosition(position) .. " h=" .. h .. " xf=" .. xf .." xd=" .. xd .. " zf=" .. zf .." zd=" .. zd) end
  572.        
  573.         -- Over grown torch placement
  574.         if state.use_torches then
  575.           xf = math.fmod(current[1], torch_spacing)
  576.               if current[3] == initial[3]        and zd ~= d[3] and xf - xd == xts then torch(xfb)
  577.           elseif current[3] == final[3]          and zd == d[3] and xf - xd == xts then torch(xfb)
  578.           elseif current[3] == initial[3] + d[3] and zd == d[3] and xf      == xts then torch(zfi)
  579.           elseif current[3] == final[3]   - d[3] and zd ~= d[3] and xf      == xts then torch(zff)
  580.           elseif current[1] == initial[1]        and                zf - zd == zts then torch(zfb)
  581.           elseif current[1] == final[1]          and                zf - zd == zts then torch(zfb)
  582.           elseif current[2] == yf and zf == zts + zd and xf == xts then torch(zfb, -1)
  583.           elseif current[2] == yf and xf == xts + xd and zf == zts then torch(xfb, -1)
  584.           elseif current[2] == ya and zf == zts + zd and xf == xts then move.down() torch(zfb, -1) move.up()
  585.           elseif current[2] == ya and xf == xts + xd and zf == zts then move.down() torch(xfb, -1) move.up()
  586.           end
  587.         end
  588.        
  589.         sleep(0)
  590.       end
  591.     end
  592.  
  593.     -- adjust for height
  594.     if h == 3 then y = y + d[2] end
  595.     y = y + d[2]
  596.   end
  597.   state.dig_mode = false
  598.   gotoSmart(drop_position)
  599.   dropOff()
  600.   gotoSimple(rest)
  601.   if state.verbose then writeLog("Done") end
  602. end
  603.  
  604. local function usage()
  605.   print("usage: mine [options] -- <x> <y> <z>")
  606.   print()
  607.   print("  -f level  set minimum fuel level")
  608.   print("  -l file   log verbose output to file")
  609.   print("  -n        no torches")
  610.   print("  -s space  set the torch spacing")
  611.   print("  -t        wait for torches if out")
  612.   print("  -v level  enable verbose output")
  613.   print()
  614.   print("Drop EC: " .. drop_chest_slot)
  615.   print("Torch: " .. torch_slot .. " (EC: " .. torch_chest_slot .. ")")
  616.   print("Fuel: " .. fuel_slot .. " (EC: " .. fuel_chest_slot .. ")")
  617. end
  618. local function main(...)
  619.   local tArgs = {}
  620.   for opt, arg in getopt(":f:l:ns:tv:", ...) do
  621.     if     opt == 'f' then refuel_level = tonumber(arg)
  622.     elseif opt == 'l' then state.log_file = arg
  623.     elseif opt == 'n' then state.use_torches = false
  624.     elseif opt == 's' then torch_spacing = tonumber(arg)
  625.     elseif opt == 't' then state.torch_wait = true
  626.     elseif opt == 'v' then state.verbose = tonumber(arg)
  627.     else                   table.insert(tArgs, arg)
  628.     end
  629.   end
  630.   if #tArgs == 3 then
  631.     mine({tonumber(tArgs[1]), tonumber(tArgs[2]), tonumber(tArgs[3]), 0})
  632.   else
  633.     usage()
  634.   end
  635. end
  636.  
  637. main(...)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement