Advertisement
OldDragon2A

Hollow

Jan 5th, 2013
339
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.14 KB | None | 0 0
  1. -- Hollow
  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 drop_slots       = { 1, 13 }
  11. local fuel_slot        = 14
  12. local fuel_chest_slot  = 15
  13. local drop_chest_slot  = 16
  14. local verbose          = 0
  15. local refuel_level     = 0
  16. local mode             = { dig = false, safe = false, drop = true }
  17. local marks            = { start = 1, edge = 2, block = 3, empty = 4, entry = 5 }
  18. local lip_range        = 5
  19. local log_file         = nil
  20.  
  21. local position         = { 0, 0, 0, 3 }
  22. local drop_position    = { 0, 0, 0, 1 }
  23. local drop_waypoint    = nil
  24. local direction        = { [0] = {  0, 0,  1, 0 },
  25.                            [1] = { -1, 0,  0, 0 },
  26.                            [2] = {  0, 0, -1, 0 },
  27.                            [3] = {  1, 0,  0, 0 } }
  28. local block            = {}
  29. local bounds           = { lower = { 0, 0, 0 }, upper = { 0, 0, 0 } }
  30. local dropping         = false
  31. local log_handle       = nil
  32.  
  33. function deepcopy(orig)
  34.   local orig_type = type(orig)
  35.   local copy
  36.   if orig_type == 'table' then
  37.     copy = {}
  38.     for orig_key, orig_value in next, orig, nil do
  39.       copy[deepcopy(orig_key)] = deepcopy(orig_value)
  40.     end
  41.     setmetatable(copy, deepcopy(getmetatable(orig)))
  42.   else
  43.     copy = orig
  44.   end
  45.   return copy
  46. end
  47. function getopt(optstring, ...)
  48.   local opts = { }
  49.   local args = { ... }
  50.  
  51.   for optc, optv in optstring:gmatch"(%a)(:?)" do
  52.     opts[optc] = { hasarg = optv == ":" }
  53.   end
  54.  
  55.   return coroutine.wrap(function()
  56.     local yield = coroutine.yield
  57.     local i = 1
  58.  
  59.     while i <= #args do
  60.       local arg = args[i]
  61.  
  62.       i = i + 1
  63.  
  64.       if arg == "--" then
  65.         break
  66.       elseif arg:sub(1, 1) == "-" then
  67.         for j = 2, #arg do
  68.           local opt = arg:sub(j, j)
  69.  
  70.           if opts[opt] then
  71.             if opts[opt].hasarg then
  72.               if j == #arg then
  73.                 if args[i] then
  74.                   yield(opt, args[i])
  75.                   i = i + 1
  76.                 elseif optstring:sub(1, 1) == ":" then
  77.                   yield(':', opt)
  78.                 else
  79.                   yield('?', opt)
  80.                 end
  81.               else
  82.                 yield(opt, arg:sub(j + 1))
  83.               end
  84.  
  85.               break
  86.             else
  87.               yield(opt, false)
  88.             end
  89.           else
  90.             yield('?', opt)
  91.           end
  92.         end
  93.       else
  94.         yield(false, arg)
  95.       end
  96.     end
  97.  
  98.     for i = i, #args do
  99.       yield(false, args[i])
  100.     end
  101.   end)
  102. end
  103. function writeLog(msg)
  104.   if log_file ~= nil then
  105.     writeLog = function (msg)
  106.       log_handle = fs.open(log_file, 'a')
  107.       log_handle.writeLine(msg)
  108.       log_handle.close()
  109.     end
  110.   else
  111.     writeLog = print
  112.   end
  113.   writeLog(msg)
  114. end
  115.  
  116. function formatPosition(p)
  117.   return p[1]..","..p[2]..","..p[3]..(p[4] == nil and "" or "," .. p[4])
  118. end
  119. function updatePosition(axis, value)
  120.   if axis == 4 then
  121.     position[axis] = (position[axis] + value) % 4
  122.   else
  123.     position[axis] = position[axis] + value
  124.   end
  125. end
  126. function inPosition(p)
  127.   return p ~= nil and position[1] == p[1] and position[2] == p[2] and position[3] == p[3]
  128. end
  129. function directionLessPosition(p)
  130.   local p = deepcopy(p)
  131.   p[4] = nil
  132.   return p
  133. end
  134. function getDirection(s, e)
  135.   return {
  136.     s[1] - e[1] <= 0 and 1 or -1,
  137.     s[2] - e[2] <= 0 and 1 or -1,
  138.     s[3] - e[3] <= 0 and 1 or -1
  139.   }
  140. end
  141.  
  142. function dig()
  143.   if mode.dig and turtle.dig() and mode.drop and getEmptySlots() == 0 then dropOff() end
  144. end
  145. function digUp()
  146.   if mode.dig and turtle.digUp() and mode.drop and getEmptySlots() == 0 then dropOff() end
  147. end
  148. function digDown()
  149.   if mode.dig and turtle.digDown() and mode.drop and getEmptySlots() == 0 then dropOff() end
  150. end
  151.  
  152. function forward()
  153.   turtle.attack()
  154.   if mode.safe and isMarkForward(marks.edge) then return false end
  155.   if turtle.detect() then dig() end
  156.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  157.   if turtle.forward() then
  158.     if     (position[4] == 0) then updatePosition(3,1)
  159.     elseif (position[4] == 1) then updatePosition(1,-1)
  160.     elseif (position[4] == 2) then updatePosition(3,-1)
  161.     elseif (position[4] == 3) then updatePosition(1,1)
  162.     end
  163.     return true
  164.   else
  165.     return false
  166.   end
  167. end
  168. function back()
  169.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  170.   if turtle.back() then
  171.     if     (position[4] == 0) then updatePosition(3,-1)
  172.     elseif (position[4] == 1) then updatePosition(1,1)
  173.     elseif (position[4] == 2) then updatePosition(3,1)
  174.     elseif (position[4] == 3) then updatePosition(1,-1)
  175.     end
  176.     return true
  177.   else
  178.     return false
  179.   end
  180. end
  181. function up()
  182.   turtle.attackUp()
  183.   if mode.safe and isMarkUp(marks.edge) then return false end
  184.   if turtle.detectUp() then digUp() end
  185.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  186.   local state = turtle.up()
  187.   if (state) then updatePosition(2,1) end
  188.   return state
  189. end
  190. function down()
  191.   turtle.attackDown()
  192.   if mode.safe and isMarkDown(marks.edge) then return false end
  193.   if turtle.detectDown() then digDown() end
  194.   if turtle.getFuelLevel() <= refuel_level then refuel() end
  195.   local state = turtle.down()
  196.   if (state) then updatePosition(2,-1) end
  197.   return state
  198. end
  199. function right()
  200.   updatePosition(4,1)
  201.   turtle.turnRight()
  202. end
  203. function left()
  204.   updatePosition(4,-1)
  205.   turtle.turnLeft()
  206. end
  207. function turn(d)
  208.   if (d == nil) then return end
  209.   while position[4] ~= d do
  210.     diff = position[4] - d
  211.     if diff == 1 or diff == -3 then left() else right() end
  212.   end
  213. end
  214.  
  215. function moveX(x, wait)
  216.   if (wait == nil) then wait = false end
  217.   result = true
  218.   if (position[1] == x) then return result end
  219.   turn(position[1] < x and 3 or 1)
  220.   while position[1] ~= x do
  221.     result = forward()
  222.     if (not result and not wait) then break end
  223.   end
  224.   return result
  225. end
  226. function moveY(y, wait)
  227.   if (wait == nil) then wait = false end
  228.   result = true
  229.   if (position[2] == y) then return result end
  230.   while position[2] ~= y do
  231.     result = position[2] < y and up() or down()
  232.     if (not result and not wait) then break end
  233.   end
  234.   return result
  235. end
  236. function moveZ(z, wait)
  237.   if (wait == nil) then wait = false end
  238.   result = true
  239.   if (position[3] == z) then return result end
  240.   turn(position[3] < z and 0 or 2)
  241.   while position[3] ~= z do
  242.     result = forward()
  243.     if (not result and not wait) then break end
  244.   end
  245.   return result
  246. end
  247. function gotoMine(p, wait)
  248.   moveX(p[1], wait)
  249.   moveY(p[2], wait)
  250.   moveZ(p[3], wait)
  251.   if (p[4] ~= nil) then turn(p[4]) end
  252. end
  253. function goto(p, wait)
  254.   if(p[3] == nil) then
  255.     moveX(p[1], wait)
  256.     moveZ(p[3], wait)
  257.   elseif(position[2] > p[2]) then
  258.     moveY(p[2], wait)
  259.     moveZ(p[3], wait)
  260.     moveX(p[1], wait)
  261.   else
  262.     moveX(p[1], wait)
  263.     moveZ(p[3], wait)
  264.     moveY(p[2], wait)
  265.   end
  266.   if (p[4] ~= nil) then turn(p[4]) end
  267. end
  268. function gotoSmart(p)
  269.   if (p == nil) then return false end
  270.  
  271.   local last
  272.   for tries = 0,8,1 do
  273.     if position[2] <= p[2] then moveY(p[2]) end
  274.     if (tries%2) == 0 then
  275.       moveX(p[1])
  276.       moveZ(p[3])
  277.     else
  278.       moveZ(p[3])
  279.       moveX(p[1])
  280.     end
  281.     if position[2] > p[2] then moveY(p[2]) end
  282.    
  283.     if inPosition(p) then break end
  284.    
  285.     if inPosition(last) then
  286.       pathFind(tries)
  287.     end
  288.     last = deepcopy(position)
  289.   end
  290.  
  291.   if (p[4] ~= nil) then turn(p[4]) end
  292.   return true
  293. end
  294. function gotoPath(path)
  295.   for k,v in pairs(path) do
  296.     goto(v, false)
  297.   end
  298. end
  299. function pathFind(level)
  300.   if level%5 == 0 then
  301.     left()
  302.     for cl = 0,level,1 do
  303.       forward()
  304.       cl=cl+1
  305.     end
  306.   elseif level%5 == 1 then
  307.     left()
  308.     for cl = 0,level,1 do
  309.       forward()
  310.       up()
  311.     end
  312.   elseif level%5 == 2 then
  313.     left()
  314.     for cl = 0,level,1 do
  315.       up()
  316.     end
  317.   elseif level%5 == 3 then
  318.     right()
  319.     for cl = 0,level,1 do
  320.       forward()
  321.       up()
  322.     end
  323.   elseif level%5 == 4 then
  324.     right()
  325.     for cl = 0,level,1 do
  326.       forward()
  327.     end
  328.   end
  329. end
  330.  
  331. function getEmptySlots()
  332.   numslots = 0
  333.   for i = drop_slots[1], drop_slots[2] do
  334.     if turtle.getItemCount(i) == 0 then
  335.       numslots = numslots + 1
  336.     end
  337.   end
  338.   return numslots
  339. end
  340. function getOpenSpace()
  341.   local result = {}
  342.   if not turtle.detect() then
  343.     result.place  = turtle.place
  344.     result.detect = turtle.detect
  345.     result.drop   = turtle.drop
  346.     result.suck   = turtle.suck
  347.     result.dig    = turtle.dig
  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. function useChest(slot, callback, param)
  366.   local chest = getOpenSpace()
  367.   local result = false
  368.   if chest.place ~= nil then
  369.     turtle.select(slot)
  370.     if chest.place() then
  371.       result = true
  372.       if callback ~= nil then result = callback(chest) end
  373.       turtle.select(slot)
  374.       chest.dig()
  375.     end
  376.   end
  377.   return result
  378. end
  379. function dropItemsInChest(chest)
  380.   result = false
  381.   if chest.detect() then
  382.     for i = drop_slots[1], drop_slots[2] do
  383.       turtle.select(i)
  384.       chest.drop()
  385.     end
  386.     result = true
  387.   end
  388.   return result
  389. end
  390. function getItemFromChest(chest, param)
  391.   turtle.select(param)
  392.   return chest.detect() and chest.suck()
  393. end
  394.  
  395. function dropOff()
  396.   if dropping then return true end
  397.   if verbose then writeLog("Drop Off") end
  398.   dropping = true
  399.   repeat
  400.     if not useChest(drop_chest_slot, dropItems) then
  401.       local resume = deepcopy(position)
  402.       mode.dig = false
  403.       gotoSmart(drop_waypoint)
  404.       local old_mode = mode.safe
  405.       mode.safe = false
  406.       gotoSmart(drop_position)
  407.       repeat
  408.         if turtle.detect() then
  409.           for i = drop_slots[1], drop_slots[2] do
  410.             turtle.select(i)
  411.             turtle.drop()
  412.           end
  413.         else
  414.           sleep(1)
  415.         end
  416.       until getEmptySlots() ~= 0
  417.       gotoSmart(drop_waypoint)
  418.       mode.safe = old_mode
  419.       gotoSmart(resume)
  420.       mode.dig = true
  421.     end
  422.   until getEmptySlots() ~= 0
  423.   dropping = false
  424.   turtle.select(drop_slots[1])
  425.   if verbose then writeLog("Resuming") end
  426. end
  427. function refuelFrom(slot)
  428.   local result
  429.   turtle.select(slot)
  430.   while turtle.getItemCount(slot) ~= 0 and (turtle.getFuelLevel() < refuel_level or turtle.getFuelLevel() == 0) do
  431.     if not turtle.refuel(1) then break end
  432.   end
  433. end
  434. function refuel()
  435.   if verbose then writeLog("Refueling") end
  436.   while turtle.getFuelLevel() == 0 do
  437.     if turtle.getItemCount(fuel_slot) ~= 0 or useChest(fuel_chest_slot, getFuelFromChest, fuel_slot) then
  438.       if verbose > 1 then writeLog("Checking Fuel Slot") end
  439.       refuelFrom(fuel_slot)
  440.     else
  441.       if verbose > 1 then writeLog("Searching Drop Slots") end
  442.       for i = drop_slots[1], drop_slots[2] do
  443.         refuelFrom(i)
  444.         if turtle.getFuelLevel() >= refuel_level then break end
  445.       end
  446.     end
  447.     if turtle.getFuelLevel() == 0 then sleep(1) end
  448.   end
  449.   turtle.select(drop_slots[1])
  450.   if verbose then writeLog("Resuming") end
  451. end
  452.  
  453. function addPoint(a, b)
  454.   local c = {}
  455.   for i = 1, math.min(#a, #b) do
  456.     if a[i] == nil then
  457.       c[i] = b[i]
  458.     elseif b[i] == nil then
  459.       c[i] = a[i]
  460.     else
  461.       c[i] = a[i] + b[i]
  462.     end
  463.   end
  464.   return c
  465. end
  466. function strPoint(point)
  467.   return point[1] .. ',' .. point[2] .. ',' .. point[3]
  468. end
  469. function adjustBounds(point)
  470.   for i = 1,3 do
  471.     if point[i] < bounds.lower[i] then bounds.lower[i] = point[i] end
  472.     if point[i] > bounds.upper[i] then bounds.upper[i] = point[i] end
  473.   end
  474. end
  475. function setMark(mark, adjust, point, map)
  476.   if map == nil then map = block end
  477.   if point == nil then point = position end
  478.   if adjust ~= nil then point = addPoint(point, adjust) end
  479.   adjustBounds(point)
  480.   map[strPoint(point)] = mark
  481. end
  482. function setMarkForward(mark)
  483.   setMark(mark, direction[position[4]])
  484. end
  485. function getMark(point, map)
  486.   if map == nil then map = block end
  487.   if point == nil then point = position end
  488.   return map[strPoint(point)]
  489. end
  490. function isMark(mark, adjust, point, map)
  491.   if map == nil then map = block end
  492.   if point == nil then point = position end
  493.   if adjust ~= nil then point = addPoint(point, adjust) end
  494.   return getMark(point, map) == mark
  495. end
  496. function isMarkForward(mark)
  497.   return isMark(mark, direction[position[4]])
  498. end
  499. function isMarkUp(mark)
  500.   return isMark(mark, {0,1,0,0})
  501. end
  502. function isMarkDown(mark)
  503.   return isMark(mark, {0,-1,0,0})
  504. end
  505. function isBetweenMark(mark)
  506.   local point = deepcopy(position)
  507.   local found = { upper = false, lower = false }
  508.   for x = point[1], bounds.lower[1], -1 do
  509.     if isMark(mark, { x, 0, 0 }, point) then
  510.       found.lower = true
  511.       break
  512.     end
  513.   end
  514.   for x = point[1], bounds.upper[1], 1 do
  515.     if isMark(mark, { x, 0, 0 }, point) then
  516.       found.upper = true
  517.       break
  518.     end
  519.   end
  520.   return found.upper and found.lower
  521. end
  522.  
  523. function floodRecursiveXZ(replace, with, point)
  524.   if verbose > 1 then writeLog("Flood (Dig): " .. formatPosition(point) .. " Mark: " .. getMark(point)) end
  525.   if not isMark(replace, nil, point) then return end
  526.   if verbose > 1 then writeLog("Dig: " .. formatPosition(point)) end
  527.   gotoMine(point)
  528.   setMark(with, nil, point)
  529.   floodRecursiveXZ(replace, with, addPoint(point, direction[2]))
  530.   floodRecursiveXZ(replace, with, addPoint(point, direction[3]))
  531.   floodRecursiveXZ(replace, with, addPoint(point, direction[0]))
  532.   floodRecursiveXZ(replace, with, addPoint(point, direction[1]))
  533.   goto(point)
  534. end
  535. function floodQueueXZ(replace, with, point)
  536.   local queue = { point }
  537.   local node  = nil
  538.  
  539.   while #queue ~= 0 do
  540.     node = table.remove(queue)
  541.     if isMark(replace, nil, node) then
  542.       setMark(with, nil, node)
  543.       goto(node, false)
  544.       for k,v in pairs(direction) do
  545.         table.insert(queue, addPoint(node, v))
  546.       end
  547.     end
  548.   end
  549. end
  550.  
  551. function walkEdge()
  552.   left()
  553.   if turtle.detect() then
  554.     setMarkForward(marks.edge)
  555.   elseif forward() then
  556.     right()
  557.     if turtle.detect() then
  558.       setMarkForward(marks.edge)
  559.     elseif forward() then
  560.       right()
  561.       if turtle.detect() then
  562.         setMarkForward(marks.edge)
  563.       else
  564.         if verbose > 0 then writeLog("Could not find way around") end
  565.         return false
  566.       end
  567.     end
  568.   end
  569.   return true
  570. end
  571. function findLip(detect, move, message)
  572.   local lip = 0
  573.   while detect() do
  574.     move()
  575.     if lip == lip_range then
  576.       if verbose > 0 then writeLog(message) end
  577.       return false
  578.     end
  579.     lip = lip + 1
  580.   end
  581.   return true
  582. end
  583. function hollow(levels)
  584.   local rest  = deepcopy(position)
  585.   local start = nil
  586.   local lip   = 0
  587.   local ret   = nil
  588.  
  589.   if verbose > 0 then writeLog("Mapping") end
  590.   while not turtle.detect() do forward() end
  591.   start = deepcopy(position)
  592.   for y = 1, levels do
  593.     if not findLip(function () return not turtle.detect() end, forward, "No edge after " .. lip_range) then return end
  594.     setMark(marks.start)
  595.     setMarkForward(marks.edge)
  596.     while isMark(marks.start) do if not walkEdge() then return end end
  597.     while not isMark(marks.start) do if not walkEdge() then return end end
  598.     if y ~= levels then
  599.       if not findLip(turtle.detectUp, back, "No way up after " .. lip_range) then return end
  600.       up()
  601.     end
  602.   end
  603.   gotoSmart(start)
  604.  
  605.   if verbose > 0 then writeLog("Clearing") end
  606.   mode.dig = true
  607.   turtle.select(drop_slots[1])
  608.   forward()
  609.   setMark(marks.entry)
  610.   forward()
  611.   mode.safe = true
  612.   drop_waypoint = deepcopy(position)
  613.  
  614.   for y = 1, levels do
  615.     -- floodRecursiveXZ(nil, marks.empty, point) - imagine this runs out of stack space on large areas
  616.     ret = deepcopy(position)    
  617.     floodQueueXZ(nil, marks.empty, directionLessPosition(position))
  618.     gotoSmart(ret)
  619.     if y ~= levels then
  620.       if verbose > 0 then writeLog("Next Level") end
  621.       if isBetweenMark(marks.edge) then -- inside next level
  622.         up()
  623.       else
  624.         while not isMarkUp(marks.edge) do forward() end -- outside next level
  625.         forward()
  626.         up()
  627.       end
  628.     end
  629.   end
  630.  
  631.   gotoSmart(drop_waypoint)
  632.   if mode.drop then dropOff() end
  633.   mode.safe = false
  634.   mode.dig = false
  635.   goto(rest)
  636.   if verbose then writeLog("Done") end
  637. end
  638.  
  639. local tArgs = {}
  640. for opt, arg in getopt(":nl:v:", ...) do
  641.   if     opt == 'n' then mode.drop = false
  642.   elseif opt == 'l' then log_file = arg
  643.   elseif opt == 'v' then verbose = tonumber(arg)
  644.   else                   table.insert(tArgs, arg)
  645.   end
  646. end
  647. if #tArgs == 1 then
  648.   if verbose > 0 then writeLog("Starting") end
  649.   hollow(tonumber(tArgs[1]))
  650. else
  651.   print("usage: hollow [options] -- <levels>")
  652.   print()
  653.   print("  -n        No drop")
  654.   print("  -l file   log verbose oupput to file")
  655.   print("  -v level  enable verbose output")
  656. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement