Spytox

StripMining

Apr 5th, 2025
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.98 KB | Gaming | 0 0
  1. --[[
  2. Minr - Automatic strip mining program for ComputerCraft turtles.
  3.  
  4. MIT License
  5.  
  6. Copyright (c) 2017 Martin W.
  7.  
  8. Permission is hereby granted, free of charge, to any person obtaining a copy
  9. of this software and associated documentation files (the "Software"), to deal
  10. in the Software without restriction, including without limitation the rights
  11. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. copies of the Software, and to permit persons to whom the Software is
  13. furnished to do so, subject to the following conditions:
  14.  
  15. The above copyright notice and this permission notice shall be included in all
  16. copies or substantial portions of the Software.
  17.  
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. SOFTWARE.
  25. --]]
  26.  
  27. -- Constants.
  28. local DEFAULT_TUNNEL_DEPTH = 50
  29. local DEFAULT_TUNNEL_HEIGHT = 3
  30.  
  31. -- Defines which materials get ignored while scanning.
  32. IGNORED_MATERIALS = {
  33.     "minecraft:stone",
  34.     "minecraft:gravel",
  35.     "minecraft:dirt",
  36.     "minecraft:sand",
  37.     "minecraft:cobblestone"
  38. }
  39.  
  40. -- Defines materials which drop items different from the block they originate
  41. -- from.
  42. BLOCK_DROPS = {
  43.     ["minecraft:stone"] = "minecraft:cobblestone",
  44.     ["minecraft:redstone_ore"] = "minecraft:redstone",
  45.     ["minecraft:diamond_ore"] = "minecraft:diamond",
  46.     ["minecraft:lapis_ore"] = "minecraft:dye",
  47.     ["minecraft:coal_ore"] = "minecraft:coal"
  48. }
  49.  
  50. -- Variables.
  51. local tunnel_depth = 0
  52. local tunnel_height = 0
  53. local automatic_refuel = true
  54.  
  55. -- Functions.
  56. local function prompt_user(prompt, default)
  57.     --[[
  58.     Prompts the user to enter a value. If a default value is given, that can be
  59.     accepted by just pressing enter.
  60.  
  61.     @param prompt:  Message to the user describing what value is asked for.
  62.     @param default: [optional] Default value to be offered to the user.
  63.  
  64.     @return         Value given by the user.
  65.     --]]
  66.  
  67.     -- Compose message.
  68.     local message = prompt
  69.  
  70.     if default then -- Add default value in parantheses if given.
  71.         message = message.." ("..default..')'
  72.     end
  73.  
  74.     message = message..": "
  75.  
  76.     -- Print the message to the screen and receive user input. Repeat if neither
  77.     -- an input nor a default value is given.
  78.     local output = nil
  79.     local input = nil
  80.  
  81.     while not output do
  82.         write(message)
  83.         input = io.read()
  84.  
  85.         if input == "" then
  86.             if default then output = default end
  87.         else
  88.             output = input
  89.         end
  90.     end
  91.  
  92.     return output
  93. end
  94.  
  95. local function estimate_needed_fuel()
  96.     --[[
  97.     Estimates and returns the amount of fuel needed to dig the desired mines.
  98.  
  99.     @return     Estimated fuel consumption.
  100.     --]]
  101.     local estimate = 1
  102.  
  103.     estimate = estimate * tunnel_depth -- fuel needed to cover the length of the tunnel
  104.     estimate = estimate * tunnel_height * 2 -- the turtle needs to go both up and down every row
  105.     estimate = estimate + tunnel_depth -- way back
  106.     estimate = estimate * 1.05 -- 5 per cent tolerance
  107.  
  108.     return estimate
  109. end
  110.  
  111. local function refuel()
  112.     --[[
  113.     Looks for burnable items inside the turtle's inventory and uses one of them
  114.     as fuel.
  115.  
  116.     @return     True if refuel was successful, false if not.
  117.     --]]
  118.  
  119.     for i = 1, 16 do
  120.         turtle.select(i)
  121.         if turtle.refuel(1) then
  122.             return true
  123.         end
  124.     end
  125.     return false -- no fuel found
  126. end
  127.  
  128. local function forward()
  129.     --[[
  130.     Moves the turtle one block forward. Automatically clears sand and gravel.
  131.  
  132.     @return     True if successful, false if the turtle cannot move.
  133.     --]]
  134.  
  135.     if turtle.forward() then
  136.         return true
  137.     else
  138.         is_block, block = turtle.inspect()
  139.  
  140.         if block.name == "minecraft:gravel" or block.name == "minecraft:sand" then
  141.             while block.name == "minecraft:gravel" or block.name == "minecraft:sand" do
  142.                 turtle.dig()
  143.                 is_block, block = turtle.inspect()
  144.             end
  145.             if forward() then return true end
  146.         else
  147.             return false -- Turtle got stuck
  148.         end
  149.     end
  150. end
  151.  
  152. local function back()
  153.     --[[
  154.     Moves the turtle on block backwards. Automatically clears sand and gravel.
  155.  
  156.     @return     True if successful, false if the turtle cannot move.
  157.     --]]
  158.     local successful = true
  159.  
  160.     if turtle.back() then
  161.         return true
  162.     else
  163.         turtle.turnRight()
  164.         turtle.turnRight()
  165.  
  166.         if not forward() then
  167.             successful = false
  168.         end
  169.  
  170.         turtle.turnRight()
  171.         turtle.turnRight()
  172.  
  173.         return successful
  174.     end
  175. end
  176.  
  177. local function get_possible_slot(item, quantity)
  178.     --[[
  179.     Checks if the inventory offers space for a given item (and quantity).
  180.  
  181.     @param item         Item identifier of the item to be stored.
  182.     @param quantity     [optional] Amount of items to be stored. If not given, 1
  183.                         will be assumed.
  184.  
  185.     @return             Number of the first slot offering space for the desired
  186.                         item and quantity, nil if there is none.
  187.     --]]
  188.  
  189.     -- Scan inventory and compare its contents to the given item and quantity.
  190.     local slot_item = nil
  191.  
  192.     for i = 1, 16 do
  193.         slot_item = turtle.getItemDetail(i)
  194.         if not slot_item then
  195.             return i -- empty slot_item
  196.         elseif slot_item.name == item then -- existing item stack found
  197.             -- check for space in the stack
  198.             local needed_space = 1
  199.             if quantity then needed_space = quantity end
  200.  
  201.             if turtle.getItemSpace(i) >= needed_space then
  202.                 return i -- item can be stored in found stack
  203.             end
  204.         end
  205.     end
  206.  
  207.     return nil -- no slot found
  208. end
  209.  
  210. local function is_ignored_material(material)
  211.     --[[
  212.     Returns if a given material is one of the ignored materials defined in
  213.     IGNORED_MATERIALS
  214.  
  215.     @param material     Identifier of the material to be looked up.
  216.  
  217.     @return             True if the material is ignored, false if not.
  218.     --]]
  219.  
  220.     for index, ignored_material in pairs(IGNORED_MATERIALS) do
  221.         if ignored_material == material then return true end
  222.     end
  223.  
  224.     return false
  225. end
  226.  
  227. local function get_block_drop(material)
  228.     --[[
  229.     Returns the identifier of the item a given block drops when mined.
  230.  
  231.     @param block    Identifier of the block to be looked up
  232.  
  233.     @return         Identifier of the dropped item
  234.     --]]
  235.  
  236.     for block, drop in pairs(BLOCK_DROPS) do
  237.         if material == block then
  238.             return drop
  239.         end
  240.     end
  241.  
  242.     return material -- Dropped item equals mined material
  243. end
  244.  
  245. local function return_to_ground(height)
  246.     --[[
  247.     Lets the turtle return to the ground from a given height.
  248.  
  249.     @param height   Height the turtle should return to the ground from.
  250.     --]]
  251.  
  252.     while height > 1 do
  253.         turtle.down()
  254.         height = height - 1
  255.     end
  256. end
  257.  
  258. local function mine_block(direction)
  259.     --[[
  260.     Mines one block and stores it in the turtle's inventory. Checks for
  261.     inventory space first, dropping items from the IGNORED_MATERIALS list if
  262.     it is full. If the inventory is full but the block in question is on the
  263.     IGNORED_MATERIALS list, it is mined without being picked up.
  264.  
  265.     @param direction    [optional] Either "up" or "down", used to mine above or
  266.                         below the turtle.
  267.  
  268.     @return             False if inventory is full and cannot be emptied,
  269.                         otherwise true.
  270.     --]]
  271.  
  272.     -- Store respective inspect and dig functions in a local variable according
  273.     -- to direction parameter
  274.     local inspect = nil
  275.     local dig = nil
  276.  
  277.     if direction == "up" then
  278.         inspect = turtle.inspectUp
  279.         dig = turtle.digUp
  280.     elseif direction == "down" then
  281.         inspect = turtle.inspectDown
  282.         dig = turtle.digDown
  283.     else
  284.         inspect = turtle.inspect
  285.         dig = turtle.dig
  286.     end
  287.  
  288.     -- Identify block to be mined
  289.     is_block, block = inspect()
  290.  
  291.     -- Return true if there is no block to be mined
  292.     if not is_block then return true end
  293.  
  294.     -- Check for inventory space and mine the block. If there is no space, try
  295.     -- to drop one of the ignored materials and then mine the block.
  296.     if get_possible_slot(get_block_drop(block.name)) then
  297.         dig()
  298.         return true -- Return true as the block has been mined
  299.     else
  300.         if is_ignored_material(block.name) then
  301.             dig()
  302.             return true -- Mined block was an ignored block, so it is omitted
  303.         end
  304.         for i = 1, 16 do
  305.             if is_ignored_material(turtle.getItemDetail(i).name) then
  306.                 turtle.select(i)
  307.                 turtle.drop()
  308.                 dig()
  309.                 return true -- Return true as the block has been mined
  310.             end
  311.         end
  312.         return false -- No suitable slot could be found
  313.     end
  314. end
  315.  
  316. local function mine_row()
  317.     --[[
  318.     Mines a vertical row of blocks before the turtle. The height of the column
  319.     is defined in tunnel_height.
  320.  
  321.     @return     True if all blocks were mined successfully, otherwise false.
  322.     --]]
  323.     local height = 1 -- ground level
  324.     local successful = true
  325.  
  326.     while height < tunnel_height do
  327.         if not mine_block() then
  328.             successful = false
  329.             break -- Mining unsuccessful, do not continue
  330.         end
  331.         turtle.up()
  332.         height = height + 1
  333.     end
  334.  
  335.     if successful then mine_block() end -- Mine topmost block
  336.  
  337.     return_to_ground(height)
  338.  
  339.     return successful
  340. end
  341.  
  342. local function scan_block(direction)
  343.     --[[
  344.     Scans the block in front of the turtle and mines it if it isn't part of
  345.     IGNORED_MATERIALS
  346.  
  347.     @param direction    [optional] Either "up" or "down", changes the direction
  348.                         in which the turtle should scan and dig.
  349.  
  350.     @return             False if mine_block() fails, otherwise true.
  351.     --]]
  352.  
  353.     -- Choose correct inspect function depending on the given direction
  354.     local inspect = nil
  355.  
  356.     if direction == "up" then
  357.         inspect = turtle.inspectUp
  358.     elseif direction == "down" then
  359.         inspect = turtle.inspectDown
  360.     else
  361.         inspect = turtle.inspect
  362.     end
  363.  
  364.     is_block, block = inspect() -- Scan block in front of the turtle
  365.  
  366.     if is_block then
  367.         if not is_ignored_material(block.name) then
  368.             if not mine_block(direction) then
  369.                 return false
  370.             end
  371.         end
  372.     end
  373.  
  374.     return true
  375. end
  376.  
  377. local function scan_walls()
  378.     --[[
  379.     Scans the walls left and right of the turtle as well as the floor and
  380.     ceiling for blocks not in IGNORED_MATERIALS and mines them.
  381.  
  382.     @return     False if scan_block() fails at any time, e.g. the inventory is
  383.                 full, otherwise true.
  384.     --]]
  385.     local height = 1 -- ground level
  386.  
  387.     -- floor
  388.     if not scan_block("down") then
  389.         return false -- Failed attempt at mining a block
  390.     end
  391.  
  392.     turtle.turnLeft()
  393.  
  394.     -- way up
  395.     while height < tunnel_height do
  396.         if not scan_block() then
  397.             turtle.turnRight()
  398.             return_to_ground(height)
  399.             return false -- Failed attempt at mining a block
  400.         end
  401.  
  402.         turtle.up()
  403.         height = height + 1
  404.     end
  405.  
  406.     -- topmost left block
  407.     if not scan_block() then
  408.         turtle.turnRight()
  409.         return_to_ground(height)
  410.         return false -- Failed attempt at mining a block
  411.     end
  412.  
  413.     turtle.turnRight()
  414.  
  415.     -- ceiling
  416.     if not scan_block("up") then
  417.         return_to_ground(height)
  418.         return false -- Failed attempt at mining a block
  419.     end
  420.  
  421.     turtle.turnRight()
  422.  
  423.     -- way back down
  424.     while height > 1 do
  425.         if not scan_block() then
  426.             turtle.turnLeft()
  427.             return_to_ground(height)
  428.             return false -- Failed attempt at mining a block
  429.         end
  430.  
  431.         turtle.down()
  432.         height = height - 1
  433.     end
  434.  
  435.     -- bottommost right block
  436.     if not scan_block() then
  437.         turtle.turnLeft()
  438.         return false -- Failed attempt at mining a block
  439.     end
  440.  
  441.     turtle.turnLeft()
  442.     return true -- Scanning successful
  443. end
  444.  
  445. local function go_to_position_in_strip(position, destination)
  446.     --[[
  447.     Moves to the given position inside a mined strip.
  448.  
  449.     @param position     The position the turtle is at inside the strip.
  450.     @param destination  The position the turtle is supposed to go to
  451.     --]]
  452.  
  453.     if destination > position then
  454.         while destination > position do
  455.             forward()
  456.             position = position + 1
  457.         end
  458.     else
  459.         while destination < position do
  460.             back()
  461.             position = position - 1
  462.         end
  463.     end
  464. end
  465.  
  466. local function go_back_in_strip(position)
  467.     --[[
  468.     Moves back to the beginning of a mined strip.
  469.  
  470.     @param position     The position the turtle is at inside the strip.
  471.     --]]
  472.  
  473.     go_to_position_in_strip(position, 0)
  474. end
  475.  
  476. local function mine_strip(scanning_enabled)
  477.     --[[
  478.     Digs a tunnel with lenght tunnel_depth and height tunnel_height. If not
  479.     told otherwise, scans the walls, floor and ceiling for materials not part of
  480.     IGNORED_MATERIALS as well. If the path is blocked or the inventory is full,
  481.     it will return to the starting position.
  482.  
  483.     @param scanning_enabled     [optional] If set to false, the turtle will not
  484.                                 scan the walls, floor and ceiling. If not set,
  485.                                 it will be assumed to be true.
  486.     --]]
  487.  
  488.     local position = 0
  489.  
  490.     while position < tunnel_depth do
  491.         -- check for fuel
  492.         while automatic_refuel and turtle.getFuelLevel() < 50 do
  493.             refuel()
  494.         end
  495.  
  496.         if not mine_row() then
  497.             go_back_in_strip(position) -- inventory is full
  498.             position = 0
  499.             break
  500.         end
  501.  
  502.         if not forward() then
  503.             go_back_in_strip(position) -- path is blocked
  504.             position = 0
  505.             break
  506.         end
  507.         position = position + 1
  508.  
  509.         if not scan_walls() then
  510.             go_back_in_strip(position) -- inventory is full
  511.             position = 0
  512.             break
  513.         end
  514.     end
  515.  
  516.     go_back_in_strip(position)
  517. end
  518.  
  519. local function greet()
  520.     --[[
  521.     Greets the user.
  522.     --]]
  523.  
  524.     -- Clear terminal.
  525.     term.clear()
  526.     term.setCursorPos(1,1)
  527.  
  528.     -- Greet user.
  529.     print([[
  530. Welcome to Minr, the intelligent
  531. strip mining program for ComputerCraft!
  532. ---------------------------------------]])
  533. end
  534.  
  535. -- Main body.
  536. greet()
  537.  
  538. -- Fetch information from user
  539. tunnel_depth = tonumber(prompt_user("Please enter the desired tunnel depth",
  540.                                     DEFAULT_TUNNEL_DEPTH))
  541. tunnel_height = tonumber(prompt_user("Please enter the desired tunnel height",
  542.                                     DEFAULT_TUNNEL_HEIGHT))
  543.  
  544.  
  545. local fuel = turtle.getFuelLevel()
  546. local estimated_fuel_need = estimate_needed_fuel()
  547. local fuel_okay = false
  548.  
  549. if fuel == "unlimited" then -- fuel need disabled
  550.     fuel_okay = true
  551. else -- fuel needed
  552.     if fuel > estimated_fuel_need then
  553.         fuel_okay = true
  554.     else
  555.         local fuel_answer = prompt_user("The turtle might not have enough fuel for that! Continue?", "N")
  556.         if fuel_answer:lower() == "yes" or fuel_answer:lower() == "y" then
  557.             fuel_okay = true
  558.         end
  559.     end
  560.  
  561.     local refuel_answer = prompt_user("Automatically refuel from gathered resources?", "Y")
  562.     if refuel_answer:lower() == "no" or refuel_answer:lower() == "n" then
  563.         automatic_refuel = false
  564.     end
  565. end
  566.  
  567. mine_strip()
Add Comment
Please, Sign In to add comment