Advertisement
serafim7

geominer kopalka v0.5.1 [OpenComputers]

Aug 16th, 2016
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.91 KB | None | 0 0
  1. -- http://computercraft.ru/topic/1031-geokopatel-ili-stan-millionerom/
  2. -- kopalka v0.5.1
  3. --с зади робота ставим сундук
  4. --в сундук ложим запастную кирку
  5. --запуск например kopalka 16 16
  6.  
  7. local shell = require "shell"
  8. local sides = require("sides")
  9. local term = require("term")
  10. local r = require("robot")
  11. local comp = require("component")
  12. local event = require("event")
  13. local computer = require("computer")
  14. local inv = comp.inventory_controller
  15. local KOPALKA = {}
  16. local inv_size = r.inventorySize()
  17. local inv_side = sides.back
  18. local charge_side = sides.left
  19. local battery_side = sides.bottom
  20. local temp_state = {x=0, y=0, z=0, dr=3}
  21. local lc = {x=0, y=0, z=0, dr=3, xMax = 0, zMax = 0}
  22. local way = 0
  23. local ore_count = 0
  24. local warp = false
  25. local bedrockWidth = 5
  26. local back_to_the_future_mode = false
  27. local minHardness = 2.05
  28. local maxHardness = 40
  29. local directives = {
  30.   pause = false,
  31.   home = false,
  32.   report = false,
  33.   move = false    
  34. }
  35.  
  36. local scrap = {
  37.   "minecraft:stone",
  38.   "minecraft:cobblestone",
  39.   "minecraft:dirt",
  40.   "minecraft:gravel",
  41.   "minecraft:sand",
  42.   "minecraft:grass",
  43.   "minecraft:sandstone",
  44.   "minecraft:mossy_cobblestone",
  45.   "minecraft:stonebrick",
  46.   "minecraft:brown_mushroom",
  47.   "minecraft:red_mushroom",
  48.   "minecraft:netherrack"
  49. }
  50.  
  51. local fuel_list = {
  52.   "minecraft:fence",
  53.   "minecraft:planks",
  54.   "minecraft:log",
  55.   "minecraft:coal_block",
  56.   "minecraft:coal"
  57. }
  58.  
  59. local mining_tools_list = {
  60.   "minecraft:iron_pickaxe",
  61.   "minecraft:golden_pickaxe",
  62.   "appliedenergistics2:item.ToolCertusQuartzPickaxe",
  63.   "appliedenergistics2:item.ToolNetherQuartzPickaxe",
  64.   "IC2:itemToolBronzePickaxe",
  65.   "Forestry:bronzePickaxe",
  66.   "minecraft:diamond_pickaxe",
  67.   "IC2:itemToolDrill",
  68.   "IC2:itemToolDDrill",
  69.   "IC2:itemToolIridiumDrill",
  70.   "GraviSuite:advDDrill"
  71. }
  72.  
  73. local function sprintf(s, ...)
  74.   return s:format(...)
  75. end
  76.  
  77. function pause()
  78.   os.sleep(0)
  79. end
  80.  
  81. local function sendSt(message) -- ОТПРАВКА СТАТУСНОГО СООБЩЕНИЯ ЧЕРЕЗ ТУННЕЛЬ
  82.   print(message)
  83.   if warp == true then
  84.     pcall(comp.tunnel.send(message))
  85.   end
  86. end
  87.  
  88. function KOPALKA.duster(tmr)
  89.   while true do
  90.     for i=1,7 do
  91.       local temp = inv.getStackInSlot(3,i)
  92.       if temp then
  93.         if temp.name == "IC2:itemDustSmall" and math.floor(temp.size/9) > 0 then
  94.           for j=1,3 do
  95.             r.select(j)
  96.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  97.           end
  98.           for j=5,7 do
  99.             r.select(j)
  100.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  101.           end
  102.           for j=9,11 do
  103.             r.select(j)
  104.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  105.           end
  106.             r.select(4)
  107.             require("component").crafting.craft(math.floor(temp.size/9))
  108.             r.drop()
  109.         end
  110.       end
  111.     end
  112.     os.sleep(tmr)
  113.   end
  114. end
  115.  
  116. function KOPALKA.charge(charge_side)
  117.   while computer.energy() < (computer.maxEnergy()/2) do
  118.     term.clear()
  119.     KOPALKA.use(charge_side)
  120.     sendSt("Зарядка...")
  121.     os.sleep(60)
  122.     KOPALKA.use(charge_side)
  123.   end
  124.   sendSt("Батарея заряжена")
  125.   return true
  126. end
  127.  
  128. function KOPALKA.charge_tool(chargerSide, slot)
  129.   local side = 3
  130.   local tool = nil
  131.  
  132.   if chargerSide == 1 then
  133.     side=1
  134.   elseif chargerSide == 0 then
  135.     side=0
  136.   end
  137.  
  138.   if r.durability() == nil then
  139.     return false
  140.   end
  141.  
  142.   if r.durability() < 0.3 then
  143.     r.select(slot)
  144.     inv.equip()
  145.     tool = inv.getStackInInternalSlot(slot)
  146.     inv.equip()
  147.     if not(lc.x == 0 and lc.y == 0 and lc.z == 0) then
  148.       return true
  149.     end
  150.   else
  151.     return false
  152.   end
  153.  
  154.   local function isElectric(device)
  155.     if device.maxCharge ~= nil then
  156.       return true
  157.     else
  158.       return false
  159.     end
  160.   end
  161.  
  162.   local function find_new_tool()
  163.     KOPALKA.rot(inv_side)
  164.     local temp = KOPALKA.inv_scaner(mining_tools_list, false, start_slot)
  165.     sendSt("Поиск замены инструменту в сундуке.")
  166.     while temp ~= 0 do
  167.       local temp_device = inv.getStackInSlot(3, temp)
  168.       if isElectric(temp_device) then
  169.         if temp_device.charge/temp_device.maxCharge > 0.6 then
  170.           break
  171.         else
  172.           temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  173.         end
  174.       else
  175.         if temp_device.damage/temp_device.maxDamage < 0.4 then
  176.           break
  177.         else
  178.           temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  179.         end
  180.       end
  181.     end
  182.     return temp
  183.   end
  184.  
  185.   local function service(device)
  186.     if isElectric(device) then
  187.       KOPALKA.rot(chargerSide)  
  188.       if not inv.getInventorySize(3) ~= nil then
  189.         sendSt("Зарядник не найден. Установите зарядник.")
  190.         while not inv.getInventorySize(3) ~= nil do
  191.           os.sleep(5)
  192.         end
  193.       end
  194.       r.select(slot)
  195.       inv.equip()
  196.       inv.dropIntoSlot(3,1)
  197.       sendSt("Зарядка инструмента.")
  198.       while inv.getStackInSlot(3,1).charge < device.maxCharge do
  199.         os.sleep(10)
  200.       end
  201.       inv.suckFromSlot(3,1)
  202.       inv.equip()            
  203.     else
  204.       sendSt("Поиск инструмента в сундуке.")
  205.       KOPALKA.rot(inv_side)
  206.       while true do
  207.         local temp = find_new_tool()
  208.         if temp ~= 0 then
  209.           r.select(slot)
  210.           inv.equip()
  211.           if not r.drop() then
  212.             sendSt("Нет места в сундуке. Освободите место.")
  213.             while not r.drop() do
  214.               os.sleep(10)
  215.             end
  216.           end
  217.           inv.suckFromSlot(3, temp)
  218.           inv.equip()
  219.           r.select(1)
  220.           break
  221.         end
  222.       end
  223.     end
  224.   end
  225.  
  226.   if lc.x == 0 and lc.y == 0 and lc.z == 0 then
  227.     sendSt("Сервис инструмента.")
  228.     service(tool)
  229.   else
  230.     return false
  231.   end  
  232. end
  233.  
  234. function KOPALKA.use(s)
  235.   if s == 1 then
  236.     r.useUp()
  237.   elseif s == 2 then
  238.     r.turnAround()
  239.     r.use()
  240.     r.turnAround()
  241.   elseif s == 3 then
  242.     r.use()
  243.   elseif s == 4 then
  244.     r.turnRight()
  245.     r.use()
  246.     r.turnLeft()
  247.   elseif s==5 then
  248.     r.turnLeft()
  249.     r.use()
  250.     r.turnRight()
  251.   else
  252.     r.useDown()
  253.   end
  254. end
  255.  
  256. function KOPALKA.drop() --функция дропа всего инвентаря в сундук, если таковой стоит перед носом
  257.   while true do
  258.     if r.detect() then
  259.       if inv.getInventorySize(3) ~= nil then
  260.         for i=1,inv_size-1 do
  261.           if inv.getStackInInternalSlot(i) ~= nil then
  262.             r.select(i)
  263.             if not r.drop() then
  264.               sendSt("Сундук переполнен. Освободите место под складирование.")
  265.               while not r.drop() do
  266.                 os.sleep(5)
  267.               end
  268.             end
  269.           end
  270.         end
  271.         break
  272.       else
  273.         sendSt("Блок не является сундуком.")
  274.         os.sleep(5)
  275.       end
  276.     else
  277.       sendSt("Установите сундук!")
  278.       os.sleep(5)
  279.     end
  280.   end
  281. end
  282.  
  283. function KOPALKA.isScrap(name) -- ПРОВЕРКА ПРЕДМЕТА, ЯВЛЯЕТСЯ ЛИ ОН МУСОРОМ
  284.   for i, nm in pairs(scrap) do
  285.     if name == nm then  
  286.       return true
  287.     end
  288.   end
  289.   return false
  290. end
  291.  
  292. function KOPALKA.ore_analyze(arg) -- АНАЛИЗ БЛОКА, ЯВЛЯЕТСЯ ЛИ ОН МУСОРОМ
  293.   if arg ~= nil then
  294.     if comp.isAvailable("geolyzer") then
  295.       local lyz = comp.geolyzer
  296.       if KOPALKA.isScrap(lyz.analyze(arg).name) then
  297.         return false
  298.       else
  299.         return true
  300.       end
  301.     else
  302.       print("Геолайзер не обнаружен в системе.")
  303.       return false
  304.     end
  305.   else
  306.     print("Не указан аргумент(сторона проверки).")
  307.   end
  308. end
  309.  
  310. function KOPALKA.drop_scrap()
  311.   for i=1, inv_size do  
  312.     local slot = inv.getStackInInternalSlot(i)
  313.     if slot ~= nil then  
  314.       if KOPALKA.isScrap(slot.name) then
  315.         r.select(i)
  316.         r.dropDown()
  317.       end
  318.     end
  319.   end
  320.   return KOPALKA.inv_sorting()  
  321. end
  322.  
  323.  
  324. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [BEGIN]
  325. local function hiver(a_side) --ДОБЫЧА УЛЬЯ
  326.   if comp.geolyzer.analyze(a_side).name == "ExtraBees:hive" then
  327.     if pcall(r.select, KOPALKA.inv_scaner("Forestry:scoop", true)) then
  328.       inv.equip()
  329.       comp.robot.swing(a_side)
  330.       inv.equip()
  331.       r.select(1)
  332.     end
  333.   end
  334. end
  335.  
  336. function KOPALKA.mUp()
  337.   local try = 1
  338.   repeat
  339.     r.swingUp()
  340.     try = try + 1
  341.     if try >= 15 then
  342.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr=вверх"..lc.dr)
  343.       local _, det = r.detectUp()
  344.       sendSt(det.." сверху.")
  345.       sendSt(comp.geolyzer.analyze(1).name)
  346.       KOPALKA.mTo(lc.x+2,lc.y,lc.z)
  347.       if not back_to_the_future_mode then
  348.         os.exit(1)
  349.         --KOPALKA.back_to_the_future()
  350.         return false
  351.       else
  352.     try = 1
  353.       end
  354.     elseif try > 12 then
  355.       hiver(1)
  356.     end
  357.   until not r.detectUp()
  358.   while try < 15 and not r.up() do
  359.     r.swingUp()
  360.     try = try + 1
  361.   end
  362.   if try < 15 then
  363.     lc.y = lc.y + 1
  364.     way = way + 1
  365.     return true
  366.    end
  367. end
  368.  
  369. function KOPALKA.mDown(action, arg)
  370.   local try = 1
  371.   if action ~= nil then
  372.     action(arg)
  373.   end
  374.   repeat
  375.     r.swingDown()
  376.     try = try + 1
  377.     if try >= 15 then
  378.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr= вниз"..lc.dr)
  379.       local _, det = r.detectDown()
  380.       sendSt(det.." снизу.")
  381.       sendSt(comp.geolyzer.analyze(0).name)
  382.       if not back_to_the_future_mode then
  383.         os.exit(1)
  384.         --KOPALKA.back_to_the_future()
  385.         return false
  386.       else
  387.     try = 1
  388.       end
  389.     elseif try > 12 then
  390.       hiver(0)
  391.     end
  392.   until not r.detectDown()
  393.   while try < 15 and not r.down() do
  394.     r.swingDown()
  395.     try = try + 1
  396.   end
  397.   if try < 15 then
  398.     lc.y = lc.y - 1
  399.     way = way + 1
  400.     return true
  401.   end
  402. end
  403.  
  404. function KOPALKA.mForw(action, arg)
  405.   local try = 1
  406.   if action ~= nil then
  407.     action(arg)
  408.   end
  409.   repeat
  410.     r.swing()
  411.     try = try + 1
  412.     if try >= 15 then
  413.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr="..lc.dr)
  414.       local _, det = r.detect()
  415.       sendSt(det.." спереди.")
  416.       sendSt(comp.geolyzer.analyze(3).name)
  417.       if not back_to_the_future_mode then
  418.         os.exit(1)
  419.         --KOPALKA.back_to_the_future()
  420.         return false
  421.       else
  422.     try = 1
  423.       end
  424.     elseif try > 12 then
  425.       hiver(3)
  426.     end
  427.   until not r.detect()
  428.   while try < 15 and not r.forward() do
  429.     r.swing()
  430.     try = try + 1
  431.   end
  432.   if try < 15 then
  433.     way = way + 1
  434.     if lc.dr==2 then
  435.       lc.x = lc.x - 1
  436.     elseif lc.dr==3 then
  437.       lc.x = lc.x + 1
  438.     elseif lc.dr==4 then
  439.       lc.z = lc.z + 1
  440.     elseif lc.dr==5 then
  441.       lc.z = lc.z - 1
  442.     end
  443.     return true
  444.   end
  445. end
  446. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [END]
  447.  
  448.  
  449. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [BEGIN]
  450. function KOPALKA.turnLeft()
  451.   r.turnLeft()
  452.   if lc.dr == 3 then
  453.     lc.dr = 5
  454.   elseif lc.dr == 4 then
  455.     lc.dr = 3
  456.   elseif lc.dr == 2 then
  457.     lc.dr = 4
  458.   elseif lc.dr == 5 then
  459.     lc.dr = 2
  460.   end
  461. end
  462.  
  463. function KOPALKA.turnRight()
  464.   r.turnRight()
  465.   if lc.dr == 3 then
  466.     lc.dr = 4
  467.   elseif lc.dr == 4 then
  468.     lc.dr = 2
  469.   elseif lc.dr == 2 then
  470.     lc.dr = 5
  471.   elseif lc.dr == 5 then
  472.     lc.dr = 3
  473.   end
  474. end
  475.  
  476. function KOPALKA.turnAround()
  477.   r.turnAround()
  478.   if lc.dr == 3 then
  479.     lc.dr = 2
  480.   elseif lc.dr == 4 then
  481.     lc.dr = 5
  482.   elseif lc.dr == 2 then
  483.     lc.dr = 3
  484.   elseif lc.dr == 5 then
  485.     lc.dr = 4
  486.   end
  487. end
  488.  
  489. function KOPALKA.rot(side) -- ВРАЩЕНИЕ С ЗАПОМИНАНИЕМ НАПРАВЛЕНИЯ
  490.   if (side ~= 1) and (side ~= 0) and lc.dr-side ~=0 then
  491.     if lc.dr == 3 then
  492.       if side == 4 then
  493.         KOPALKA.turnRight()
  494.       elseif side == 2 then
  495.         KOPALKA.turnAround()
  496.       elseif side == 5 then
  497.         KOPALKA.turnLeft()
  498.       end
  499.     elseif lc.dr == 4 then
  500.       if side == 2 then
  501.         KOPALKA.turnRight()
  502.       elseif side == 5 then
  503.         KOPALKA.turnAround()
  504.       elseif side == 3 then
  505.         KOPALKA.turnLeft()
  506.       end
  507.     elseif lc.dr == 2 then
  508.       if side == 5 then
  509.         KOPALKA.turnRight()
  510.       elseif side == 3 then
  511.         KOPALKA.turnAround()
  512.       elseif side == 4 then
  513.         KOPALKA.turnLeft()
  514.       end
  515.     else
  516.       if side == 3 then
  517.         KOPALKA.turnRight()
  518.       elseif side == 4 then
  519.         KOPALKA.turnAround()
  520.       elseif side == 2 then
  521.         KOPALKA.turnLeft()
  522.       end
  523.     end
  524.   end
  525. end
  526. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [END]
  527.  
  528.  
  529. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [BEGIN]
  530. function KOPALKA.mTo(x, y, z, action, arg)
  531.   if directives.pause then
  532.     KOPALKA.execDirective()
  533.   end
  534.   if lc.x > x then
  535.     KOPALKA.rot(sides.back)
  536.     while lc.x > x do
  537.       KOPALKA.mForw(action,arg)
  538.     end
  539.   end
  540.   if lc.x < x then
  541.     KOPALKA.rot(sides.forward)
  542.     while lc.x < x do
  543.       KOPALKA.mForw(action,arg)
  544.     end
  545.   end
  546.   if lc.z > z then
  547.     KOPALKA.rot(sides.left)
  548.     while lc.z > z do
  549.       KOPALKA.mForw(action,arg)
  550.     end  
  551.   end
  552.   if lc.z < z then
  553.     KOPALKA.rot(sides.right)
  554.     while lc.z < z do
  555.       KOPALKA.mForw(action,arg)
  556.     end
  557.   end
  558.   while lc.y > y do
  559.     KOPALKA.mDown(action,arg)
  560.   end
  561.   while lc.y < y do
  562.     KOPALKA.mUp(action,arg)
  563.   end
  564. end
  565.  
  566. function KOPALKA.home(action, arg)
  567.   temp_state.x = lc.x
  568.   temp_state.y = lc.y
  569.   temp_state.z = lc.z
  570.   temp_state.dr = lc.dr
  571.   KOPALKA.mTo(0, 0, 0, action, arg)
  572.   KOPALKA.rot(2)
  573.   KOPALKA.drop_scrap()
  574.   KOPALKA.drop()
  575.   --KOPALKA.rot(3)
  576. end
  577.  
  578. function KOPALKA.back_to_mine(action, arg)
  579.   KOPALKA.mTo(0, temp_state.y, 0, action, arg)
  580.   KOPALKA.mTo(temp_state.x, temp_state.y, temp_state.z, action, arg)
  581.   KOPALKA.rot(temp_state.dr)
  582.   temp_state.x = 0
  583.   temp_state.y = 0
  584.   temp_state.z = 0
  585.   temp_state.dr = 3
  586. end
  587.  
  588. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [END]
  589.  
  590.  
  591. function KOPALKA.check_inv()
  592.   return r.inventorySize()
  593. end
  594.  
  595. function KOPALKA.inv_sorting()
  596.   local items_stored = 0
  597.  
  598.   for i=1, inv_size-1 do
  599.     if r.count(i) == 0 then
  600.       for j=inv_size-1, 1, -1 do
  601.         if r.count(j) > 0 then
  602.           if j<i then
  603.             break
  604.           end
  605.           r.select(j)
  606.           r.transferTo(i)
  607.           break
  608.         end
  609.       end
  610.     end
  611.   end
  612.   for i=1,inv_size do
  613.     if r.count(i) > 0 then
  614.       items_stored = items_stored + 1
  615.     end
  616.   end
  617.   r.select(1)
  618.   return items_stored/inv_size
  619. end
  620.  
  621. function KOPALKA.check_state()
  622.   sendSt(sprintf("keep-alive %d", computer.uptime()))
  623.   local need_fuel = computer.energy() < (computer.maxEnergy()*0.90)
  624.  
  625.   local function inventory()
  626.     local need_to_home = false
  627.     if (r.count(inv_size-2) > 0) then  
  628.       if KOPALKA.drop_scrap() > 0.9 then
  629.         need_to_home = true
  630.       else
  631.         need_to_home = false
  632.       end
  633.     end
  634.     return need_to_home
  635.   end
  636.  
  637.   local function fuel(internal)
  638.     local need_to_home = false
  639.     if need_fuel and comp.isAvailable("generator") and comp.generator.count() == 0 then
  640.       local slt = KOPALKA.inv_scaner(fuel_list, internal)
  641.       if slt ~= 0 and not internal then
  642.         r.select(inv_size-2)
  643.         inv.suckFromSlot(3, slt)
  644.         comp.generator.insert()
  645.         r.select(1)
  646.         need_to_home = false
  647.       else
  648.         slt = KOPALKA.inv_scaner(fuel_list, internal)
  649.         if slt ~= 0 and internal then  
  650.           r.select(slt)
  651.           comp.generator.insert()
  652.           r.select(1)
  653.           need_to_home = false
  654.         else
  655.           need_to_home = true
  656.         end
  657.       end
  658.     elseif not comp.isAvailable("generator") and need_fuel then
  659.       need_to_home = true
  660.     end
  661.     return need_to_home
  662.   end
  663.  
  664.   if inventory() or fuel(true) or KOPALKA.charge_tool(charge_side, inv_size-2) then
  665.     KOPALKA.home()
  666.     os.sleep(15)
  667.     KOPALKA.charge_tool(charge_side, inv_size-2)  
  668.     fuel(false)
  669.     KOPALKA.back_to_mine()
  670.   end    
  671. end
  672.  
  673. function KOPALKA.inv_scaner(filter, internal, start_slot) --автопоисковик заданного итема в своем инвентаре по системному имени. возвращает номер ячейки итема, первого найденного от начала ивентаря.
  674.   ins = inv.getInventorySize(3)
  675.   if start_slot == nil then
  676.     start_slot = 1
  677.   end
  678.   if filter == "empty" then
  679.     if internal then
  680.       for i=start_slot, inv_size do
  681.         if inv.getStackInInternalSlot(i) == nil then
  682.           return i
  683.         end
  684.       end
  685.     else
  686.       for i=start_slot, inv.getInventorySize(3) do
  687.         if inv.getStackInSlot(3, i) == nil then
  688.           return i
  689.         end
  690.       end
  691.     end
  692.   end  
  693.   if internal then
  694.     for i=start_slot, inv_size do
  695.       if inv.getStackInInternalSlot(i) ~= nil then
  696.         if pcall(pairs, filter) then
  697.           for j, name in pairs(filter) do
  698.             if inv.getStackInInternalSlot(i).name == name then
  699.               return i
  700.             end
  701.           end
  702.         else
  703.           if inv.getStackInInternalSlot(i).name == filter then
  704.             return i
  705.           end
  706.         end
  707.       end
  708.     end
  709.     return 0  
  710.   else
  711.     if ins ~= nil  then
  712.       for i=start_slot, ins do
  713.         if inv.getStackInSlot(3, i) ~= nil then
  714.           if pcall(pairs, filter) then
  715.             for j, name in pairs(filter) do
  716.               if inv.getStackInSlot(3, i).name == name then
  717.                 return i
  718.               end
  719.             end
  720.           else
  721.             if inv.getStackInSlot(3, i).name == filter then
  722.               return i
  723.             end
  724.           end
  725.         end
  726.       end
  727.       return 0
  728.     else
  729.       return 0
  730.     end
  731.   end
  732. end
  733.  
  734. function KOPALKA.distance(blockA, blockB)
  735.   local dist = math.sqrt(math.pow(blockA.x - blockB.x,2) +
  736.   math.pow(blockA.z - blockB.z,2) + math.pow(blockA.y - blockB.y,2))
  737.   return dist
  738. end
  739.  
  740. function KOPALKA.closest_point(point, points)
  741.   local cl_num = 1
  742.   local length = KOPALKA.distance(point, points[1])
  743.   for i=1, #points do
  744.     local l = KOPALKA.distance(point, points[i])
  745.     if l < length then
  746.       cl_num = i
  747.       length = l
  748.     end
  749.   end
  750.   return cl_num
  751. end
  752.  
  753. function KOPALKA.waypoints(ores_table, last)
  754.   local yeildGuard = 0
  755.   local way_table = {}
  756.   local count = #ores_table
  757.   table.insert(way_table, {x=lc.x, z=lc.z, y=lc.y})
  758.   while count ~= #way_table - 1 do
  759.     yeildGuard = yeildGuard + 1
  760.     if yeildGuard == 100 then
  761.       yeildGuard = 0
  762.       pause()
  763.     end
  764.     local j = KOPALKA.closest_point(way_table[#way_table], ores_table)
  765.     table.insert(way_table, ores_table[j])
  766.     table.remove(ores_table, j)
  767.   end
  768.   return way_table, last
  769. end
  770.  
  771. function KOPALKA.scanVolume(xn, zn, bedrock, side, hight_border) --сканирование карьерного "этажа" заданного радиуса -10 блоков вниз+сканер+10 блоков вверх; bedrock - верхний уровень бедрока
  772.   local geo = comp.geolyzer
  773.   local ores_table = {}
  774.   local last = false
  775.   local x_limit = 0
  776.   local z_limit = 0
  777.   local x_increment = 1
  778.   local z_increment = 1
  779.   if side == "north" or side == "север" then
  780.     x_limit = zn
  781.     x_increment = 1
  782.     z_limit = -xn
  783.     z_increment = -1
  784.   elseif side == "west" or side == "запад" then
  785.     x_limit = -xn
  786.     x_increment = -1
  787.     z_limit = -zn
  788.     z_increment = -1
  789.   elseif side == "south" or side == "юг" then
  790.     x_limit = -zn
  791.     x_increment = -1
  792.     z_limit = xn
  793.     z_increment = 1
  794.    elseif side == "east" or side == "восток" or side == nil then
  795.      x_limit = xn
  796.      x_increment = 1
  797.     z_limit = zn
  798.     z_increment = 1
  799.   end
  800.  
  801.   for xt=0,x_limit,x_increment do
  802.     for zt=0,z_limit,z_increment do
  803.       local scan = geo.scan(xt,zt,true)
  804.       for yt=hight_border+33, 33+math.abs(hight_border) do
  805.         if scan[yt] > minHardness and scan[yt] < maxHardness and ((yt-33)+lc.y) > bedrock then
  806.           if side == "north" or side == "север" then
  807.             table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y=(yt-33)+lc.y})
  808.           elseif side == "west" or side == "запад" then
  809.             table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y=(yt-33)+lc.y})
  810.           elseif side == "south" or side == "юг" then
  811.             table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y=(yt-33)+lc.y})
  812.           elseif side == "east" or side == "восток" or side == nil then
  813.             table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y=(yt-33)+lc.y})
  814.           end    
  815.         end
  816.       end
  817.     end
  818.   end
  819.   return ores_table
  820. end
  821.  
  822. function KOPALKA.whatsSide()
  823.   local geo = comp.geolyzer
  824.   local function isBlock(dens)
  825.     if dens ~= nil and dens ~= 0 then
  826.       return 1
  827.     elseif dens == 0 then
  828.       return 0
  829.     end
  830.   end
  831.  
  832.   local function check(fig, front)
  833.     local figure1 = {
  834.       east = isBlock(geo.scan(1,0)[33]),
  835.       south = isBlock(geo.scan(0,1)[33]),
  836.       west = isBlock(geo.scan(-1,0)[33]),  
  837.       north = isBlock(geo.scan(0,-1)[33])
  838.     }  
  839.     if front then
  840.       if fig.east > figure1.east  then
  841.         return "east"
  842.       elseif fig.south > figure1.south then
  843.         return "south"
  844.       elseif fig.west > figure1.west then
  845.         return "west"
  846.       elseif fig.north > figure1.north then
  847.         return "north"
  848.       end
  849.     elseif not front then
  850.       if fig.east < figure1.east  then
  851.         return "east"
  852.       elseif fig.south < figure1.south then
  853.         return "south"
  854.       elseif fig.west < figure1.west then
  855.         return "west"
  856.       elseif fig.north < figure1.north then
  857.         return "north"
  858.       end  
  859.     end
  860.   end
  861.   local figure = {
  862.     east = isBlock(geo.scan(1,0)[33]),
  863.     south = isBlock(geo.scan(0,1)[33]),
  864.     west = isBlock(geo.scan(-1,0)[33]),  
  865.     north = isBlock(geo.scan(0,-1)[33])
  866.   }
  867.   KOPALKA.rot(3)
  868.   while true do
  869.     if r.detect() then
  870.       r.swing()
  871.       local direction = check(figure, true)
  872.       r.place()
  873.       return direction
  874.     elseif r.detectDown() then
  875.       r.swingDown()
  876.       r.place()
  877.       local direction = check(figure, false)
  878.       r.swing()
  879.       r.placeDown()
  880.       return direction
  881.     end
  882.     sendSt("Для ориентирования в пространстве недостаточно данных.")
  883.     sendSt("Пожалуйста установите любой блок перед или под роботом и повторите попытку")
  884.     os.exit(1)
  885.   end
  886. end
  887.  
  888. function KOPALKA.findoutBedrockLevel() -- нижний уровень бедрока
  889.   local bedrock = -1
  890.   local start_level = lc.y
  891.   local geo = comp.geolyzer
  892.   local function scan()
  893.     local tempr=geo.scan(0,0)
  894.     for i = 10, 1, -1 do
  895.       if tempr[33 - i] < -0.3 then
  896.         return lc.y - i, true
  897.       end
  898.     end
  899.     return 0, false
  900.   end
  901.   for i = lc.y, -256, -10 do
  902.     local bed, catch = scan()
  903.     if not catch then
  904.       KOPALKA.mTo(lc.x, i, lc.z)
  905.     else
  906.       bedrock = bed
  907.       break
  908.     end
  909.   end
  910.   KOPALKA.mTo(lc.x, start_level, lc.z)
  911.   return bedrock
  912. end
  913.  
  914. function KOPALKA.clusterDigger(start_point, x, z, bedrock, side)
  915.   sendSt(sprintf("cluster: %d %d %d (%d %d %d) %s", start_point.x, start_point.y, start_point.z, x, bedrock, z, side))
  916.   sendSt("Сканирование заданного объема, может занять несколько минут...")
  917.   if side == nil then
  918.     side = KOPALKA.whatsSide()
  919.   end
  920.   if start_point == nil then
  921.     start_point = lc
  922.   end
  923.   KOPALKA.mTo(start_point.x, start_point.y, start_point.z)
  924.   for Y=lc.y, bedrock+bedrockWidth+1, -1 do
  925.     if Y%21 == 0 or Y == bedrock + 9 then
  926.       KOPALKA.mTo(start_point.x, Y, start_point.z)
  927.       KOPALKA.rot(3)
  928.       arr=KOPALKA.waypoints(KOPALKA.scanVolume(x-1,z-1, bedrock+bedrockWidth-1, side, -11))
  929.       ore_count = ore_count + (#arr-1)
  930.       for i=1, #arr do
  931.         KOPALKA.mTo(arr[i].x, arr[i].y, arr[i].z)
  932.         if i%10 == 0 then
  933.           KOPALKA.check_state()
  934.         end
  935.         if way%30 == 0 then
  936.           KOPALKA.check_state()
  937.         end
  938.       end
  939.     end
  940.   end
  941. end
  942.  
  943. function KOPALKA.geoMiner(x, z, bedrock, side, x_lim, z_lim)
  944.   if bedrock == nil then
  945.     sendSt("Проверка уровня бедрока. Вертикальная шахта до дна и обратно.")
  946.     bedrock = KOPALKA.findoutBedrockLevel()
  947.   end
  948.   sendSt(sprintf("bedrock= %d\n", bedrock))
  949.   local start_point = {x=0, y=0, z=0}
  950.   local x_limit = x_lim
  951.   local z_limit = z_lim
  952.   if x_lim == nil then
  953.     x_limit = 32
  954.   end
  955.   if z_lim == nil then
  956.     z_limit = 32
  957.   end
  958.   if side == nil then
  959.     side = KOPALKA.whatsSide()
  960.   end
  961.  
  962.   local function z_glide()
  963.     if z/z_limit < 1 then
  964.       KOPALKA.clusterDigger(start_point, x_limit, z, bedrock, side)
  965.     else
  966.       for j=1, math.floor(z/z_limit) do
  967.         KOPALKA.clusterDigger(start_point, x_limit, z_limit, bedrock, side)
  968.         start_point.z = j*z_limit+1
  969.       end
  970.       if z%z_limit > 0 then
  971.         KOPALKA.clusterDigger(start_point, x_limit, z%z_limit, bedrock, side)
  972.       end
  973.       start_point.z = 0
  974.     end
  975.   end
  976.  
  977.   if x/x_limit < 1 then
  978.     local temp = x_limit
  979.     x_limit = x
  980.     z_glide()
  981.     x_limit = temp
  982.   else
  983.     for i=1, math.floor(x/x_limit) do
  984.       z_glide()
  985.       start_point.x = i*x_limit+1
  986.     end
  987.     if x%x_limit > 0 then
  988.       x_limit = x%x_limit
  989.       z_glide()
  990.     end
  991.   end
  992.   KOPALKA.home()
  993.   KOPALKA.rot(3)
  994.   sendSt("Итого руды добыто: "..ore_count)
  995.   sendSt("Всего блоков пройдено: "..way)
  996.   sendSt('Робот '..r.name()..' завершил работу.')
  997. end
  998.  
  999. function KOPALKA.check_components()
  1000.   local function stop()
  1001.     print('> ')
  1002.     if tonumber(io.read()) ~= 1 then
  1003.       os.exit()
  1004.     end
  1005.   end
  1006.   if comp.isAvailable("tunnel") then
  1007.     warp = true
  1008.     print("\t Связанная карта....доступна.")
  1009.   else
  1010.     print("\t Связанная карта не обнаружена. Начать работу? (0/1)")
  1011.     stop()
  1012.   end
  1013.   if comp.isAvailable("chunkloader") then
  1014.     comp.chunkloader.setActive(true)
  1015.     print("\t Чанклоадер....доступен.")
  1016.   else
  1017.     print("\t Чанклоадер не обнаружен, возможны проблемы и ошибки. Начать работу без чанклоадера? (0/1)")
  1018.     stop()
  1019.   end
  1020.   if comp.isAvailable("inventory_controller") then
  1021.     print("\t Контроллер инвентаря....доступен.")
  1022.   else
  1023.     print("\t Контроллер инвентаря не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1024.     os.exit()
  1025.   end
  1026.   if comp.isAvailable("generator") then
  1027.     print("\t Генератор....доступен.")
  1028.   else
  1029.     print("\t Генератор не обнаружен, возможны проблемы и ошибки. Начать работу без генератора? (0/1)")
  1030.     stop()
  1031.   end
  1032.   if comp.isAvailable("geolyzer") then
  1033.     print("\t Геосканер....доступен.")
  1034.   else
  1035.     print("\t Геосканер не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1036.     os.exit()
  1037.   end
  1038.   if pcall(r.select,KOPALKA.inv_scaner("Forestry:scoop", true)) then
  1039.     r.transferTo(inv_size)
  1040.     r.select(1)
  1041.     print("\t Сачок....доступен.")
  1042.   else
  1043.     print("\t Сачок не обнаружен, возможны проблемы и ошибки. Начать работу без сачка?")
  1044.     stop()
  1045.   end
  1046.   if r.durability() ~= nil then
  1047.     print("\t Инструмент....доступен.")
  1048.   else
  1049.     print("\t Инструмент не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1050.     os.exit()
  1051.   end
  1052.   print("\n Все компоненты в наличии.\n Программа может быть запущена.")
  1053. end
  1054.  
  1055. function KOPALKA.mine(x, z, bedrock, side, x_lim, z_lim)
  1056.   KOPALKA.check_components()
  1057.   lc.xMax = x
  1058.   lc.zMax = z
  1059.   way = 0
  1060.   term.clear()
  1061.   sendSt("Старт карьера: "..x.."x"..z.." блоков.")
  1062.   KOPALKA.check_state()
  1063.   local side = KOPALKA.whatsSide()
  1064.   local ok, err = pcall(KOPALKA.geoMiner, x, z, bedrock, side, x_lim, z_lim)
  1065.   if not ok then
  1066.     if type(err) ~= "table" then
  1067.       sendSt(err)
  1068.     end
  1069.     back_to_the_future_mode = true
  1070.     sendSt('Ошибка/препятствие. Возврат робота.')
  1071.     KOPALKA.mTo(lc.x, 0, lc.z)
  1072.     KOPALKA.home()
  1073.     KOPALKA.rot(3)
  1074.   end
  1075. end
  1076.  
  1077. function main(tArgs, options)
  1078.   local function argNumber(x)
  1079.     local v = tonumber(x)
  1080.     if type(v) ~= 'number' then
  1081.       io.write("Аргументы должны быть заданы в виде чисел.\n")
  1082.       os.exit(1)
  1083.     end
  1084.     return v
  1085.   end
  1086.  
  1087.   local function getNumberOption(name)
  1088.     local v = options[name]
  1089.     if v then
  1090.       v = argNumber(v)
  1091.     end
  1092.     return v
  1093.   end
  1094.  
  1095.   if #tArgs == 2 then
  1096.     bedrockWidth = getNumberOption("bedrock-width") or bedrockWidth
  1097.     minHardness = getNumberOption("min-hardness") or minHardness
  1098.     maxHardness = getNumberOption("max-hardness") or maxHardness
  1099.     local x = argNumber(tArgs[1])
  1100.     local z = argNumber(tArgs[2])
  1101.     KOPALKA.mine(x, z, getNumberOption("bedrock"))
  1102.   else
  1103.     io.write("Запуск: kopalka размер_вперёд размер_справа\n")
  1104.     io.write("Опции:\n")
  1105.     io.write("--min-hardness=<мин. плотность>\n")
  1106.     io.write("--max-hardness=<макс. плотность>\n")
  1107.     io.write("--bedrock=<нижний уровень бедрока относительно робота> ")
  1108.     io.write("= высота_нижнего_слоя_бедрока-высота_на_которой_стоит_робот> - \n")
  1109.     io.write("--bedrock-width=<ширина слоя бедрока>\n")
  1110.     io.write("Робот будет добывать блоки,\nплотность которых находится \nв интервале (<мин. плотность>, <макс. плотность>).\n")
  1111.     io.write("Значение по умолчанию: ("..minHardness..", "..maxHardness..").\n")
  1112.   end
  1113. end
  1114.  
  1115. main(shell.parse(...))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement