Advertisement
serafim7

geominer DOOB [OpenComputers]

Jun 19th, 2019
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 29.44 KB | None | 0 0
  1. --Дубокоп
  2. --https://computercraft.ru/topic/2544-dubokop/
  3. --https://youtu.be/fXvMzKBADLc
  4. --https://raw.githubusercontent.com/DOOBW/geominer/master/miner.lua
  5.  
  6. local component = require('component') -- подгрузить обертку из OpenOS
  7. local computer = require('computer')
  8. local chunks = 9 -- количество чанков для добычи
  9. local min, max = 2.2, 40 -- минимальная и максимальная плотность
  10. local port = 1 -- порт для взаимодействия с роботом
  11. local X, Y, Z, D, border = 0, 0, 0, 0 -- переменные локальной системы координат
  12. local steps, turns = 0, 0 -- debug
  13. local WORLD = {x = {}, y = {}, z = {}} -- таблица меток
  14. local E_C, W_R = 0, 0 -- энергозатраты на один шаг и скорость износа
  15.  
  16. local function arr2a_arr(tbl) -- преобразование списка в ассоциативный массив
  17.   for i = #tbl, 1, -1 do
  18.    tbl[tbl[i]], tbl[i] = true, nil
  19.   end
  20. end
  21.  
  22. local quads = {{-7, -7}, {-7, 1}, {1, -7}, {1, 1}}
  23. local workbench = {1,2,3,5,6,7,9,10,11}
  24. local wlist = {'enderstorage:ender_storage'}
  25. local fragments = {'redstone','coal','dye','diamond','emerald'}
  26. local tails = {'cobblestone','granite','diorite','andesite','marble','limestone','dirt','gravel','sand','stained_hardened_clay','sandstone','stone','grass','end_stone','hardened_clay','mossy_cobblestone','planks','fence','torch','nether_brick','nether_brick_fence','nether_brick_stairs','netherrack','soul_sand'}
  27. arr2a_arr(wlist)
  28. arr2a_arr(fragments)
  29. arr2a_arr(tails)
  30.  
  31. local function add_component(name) -- получение прокси компонента
  32.   name = component.list(name)() -- получить адрес по имени
  33.   if name then -- если есть адрес
  34.     return component.proxy(name) -- вернуть прокси
  35.   end
  36. end
  37.  
  38. -- загрузка компонентов --
  39. local controller = add_component('inventory_controller')
  40. local chunkloader = add_component('chunkloader')
  41. local generator = add_component('generator')
  42. local crafting = add_component('crafting')
  43. local geolyzer = add_component('geolyzer')
  44. local tunnel = add_component('tunnel')
  45. local modem = add_component('modem')
  46. local robot = add_component('robot')
  47. local inventory = robot.inventorySize()
  48. local energy_level, sleep, report, remove_point, check, step, turn, smart_turn, go, scan, calibration, sorter, home, main, solar, ignore_check
  49.  
  50. energy_level = function()
  51.   return computer.energy()/computer.maxEnergy()
  52. end
  53.  
  54. sleep = function(timeout)
  55.   local deadline = computer.uptime()+timeout
  56.   repeat
  57.     computer.pullSignal(deadline-computer.uptime())
  58.   until computer.uptime() >= deadline
  59. end
  60.  
  61. report = function(message, stop) -- рапорт о состоянии
  62.   message = '|'..X..' '..Y..' '..Z..'|\n'..message..'\nenergy level: '..math.floor(energy_level()*100)..'%' -- добавить к сообщению координаты и уровень энергии
  63.   if modem then -- если есть модем
  64.     modem.broadcast(port, message) -- послать сообщение через модем
  65.   elseif tunnel then -- если есть связанная карта
  66.     tunnel.send(message) -- послать сообщение через нее
  67.   end
  68.   computer.beep() -- пикнуть
  69.   if stop then -- если есть флаг завершения
  70.     if chunkloader then
  71.       chunkloader.setActive(false)
  72.     end
  73.     error(message,0) -- остановить работу программы
  74.   end
  75. end
  76.  
  77. remove_point = function(point) -- удаление меток
  78.   table.remove(WORLD.x, point) -- удалить метку из таблицы
  79.   table.remove(WORLD.y, point)
  80.   table.remove(WORLD.z, point)
  81. end
  82.  
  83. check = function(forcibly) -- проверка инструмента, батареи, удаление меток
  84.   if not ignore_check and (steps%32 == 0 or forcibly) then -- если пройдено 32 шага или включен принудительный режим
  85.     local delta = math.abs(X)+math.abs(Y)+math.abs(Z)+64 -- определить расстояние
  86.     local cx, cy, cz = X, Y, Z -- сохранить текущие координаты
  87.     if robot.durability()/W_R < delta then -- если инструмент изношен
  88.       report('tool is worn')
  89.       ignore_check = true
  90.       home(true) -- отправиться домой
  91.     end
  92.     if delta*E_C > computer.energy() then -- проверка уровня энергии
  93.       report('battery is low')
  94.       ignore_check = true
  95.       home(true) -- отправиться домой
  96.     end
  97.     go(cx, cy, cz) -- вернуться на место
  98.     if energy_level() < 0.3 then -- если энергии меньше 30%
  99.       local time = os.date('*t')
  100.       if generator and generator.count() == 0 and not forcibly then -- если есть генератор
  101.         report('refueling solid fuel generators')
  102.         for slot = 1, inventory do -- обойти инвентарь
  103.           robot.select(slot) -- выбрать слот
  104.           for gen in component.list('generator') do -- перебрать все генераторы
  105.             if component.proxy(gen).insert() then -- попробовать заправиться
  106.               break
  107.             end
  108.           end
  109.         end
  110.       elseif solar and geolyzer.isSunVisible() and -- проверить видимость солнца
  111.         (time.hour > 4 and time.hour < 17) then -- проверить время
  112.         while not geolyzer.canSeeSky() do -- пока не видно неба
  113.           step(1, true) -- сделать шаг вверх без проверки
  114.         end
  115.         report('recharging in the sun')
  116.         sorter(true)
  117.         while (energy_level() < 0.98) and geolyzer.isSunVisible() do
  118.           time = os.date('*t') -- время работы солнечной панели 05:30 - 18:30
  119.           if time.hour >= 5 and time.hour < 19 then
  120.             sleep(60)
  121.           else
  122.             break
  123.           end
  124.         end
  125.         report('return to work')
  126.       end
  127.     end
  128.   end
  129.   if #WORLD.x ~= 0 then -- если таблица меток не пуста
  130.     for i = 1, #WORLD.x do -- пройти по всем позициям
  131.       if WORLD.y[i] == Y and ((WORLD.x[i] == X and ((WORLD.z[i] == Z+1 and D == 0) or (WORLD.z[i] == Z-1 and D == 2))) or (WORLD.z[i] == Z and ((WORLD.x[i] == X+1 and D == 3) or (WORLD.x[i] == X-1 and D == 1)))) then
  132.         robot.swing(3)
  133.         remove_point(i)
  134.       end
  135.       if X == WORLD.x[i] and (Y-1 <= WORLD.y[i] and Y+1 >= WORLD.y[i]) and Z == WORLD.z[i] then
  136.         if WORLD.y[i] == Y+1 then -- добыть блок сверху, если есть
  137.           robot.swing(1)
  138.         elseif WORLD.y[i] == Y-1 then -- добыть блок снизу
  139.           robot.swing(0)
  140.         end
  141.         remove_point(i)
  142.       end
  143.     end
  144.   end
  145. end
  146.  
  147. step = function(side, ignore) -- функция движения на 1 блок
  148.   local result, obstacle = robot.swing(side)
  149.   if not result and obstacle ~= 'air' and robot.detect(side) then -- если блок нельзя разрушить
  150.     home(true) -- запустить завершающую функцию
  151.     report('insurmountable obstacle', true) -- послать сообщение
  152.   else
  153.     while robot.swing(side) do end -- копать пока возможно
  154.   end
  155.   if robot.move(side) then -- если робот сдвинулся, обновить координаты
  156.     steps = steps + 1 -- debug
  157.     if side == 0 then
  158.       Y = Y-1
  159.     elseif side == 1 then
  160.       Y = Y+1
  161.     elseif side == 3 then
  162.       if D == 0 then
  163.         Z = Z+1
  164.       elseif D == 1 then
  165.         X = X-1
  166.       elseif D == 2 then
  167.         Z = Z-1
  168.       else
  169.         X = X+1
  170.       end
  171.     end
  172.   end
  173.   if not ignore then
  174.     check()
  175.   end
  176. end
  177.  
  178. turn = function(side) -- поворот в сторону
  179.   side = side or false
  180.   if robot.turn(side) and D then -- если робот повернулся, обновить переменную  направления
  181.     turns = turns+1 -- debug
  182.     if side then
  183.       D = (D+1)%4
  184.     else
  185.       D = (D-1)%4
  186.     end
  187.     check()
  188.   end
  189. end
  190.  
  191. smart_turn = function(side) -- поворот в определенную сторону света
  192.   while D ~= side do
  193.     turn((side-D)%4==1)
  194.   end
  195. end
  196.  
  197. go = function(x, y, z) -- переход по указанным координатам
  198.   if border and y < border then
  199.     y = border
  200.   end
  201.   while Y ~= y do
  202.     if Y < y then
  203.       step(1)
  204.     elseif Y > y then
  205.       step(0)
  206.     end
  207.   end
  208.   if X < x then
  209.     smart_turn(3)
  210.   elseif X > x then
  211.     smart_turn(1)
  212.   end
  213.   while X ~= x do
  214.     step(3)
  215.   end
  216.   if Z < z then
  217.     smart_turn(0)
  218.   elseif Z > z then
  219.     smart_turn(2)
  220.   end
  221.   while Z ~= z do
  222.     step(3)
  223.   end
  224. end
  225.  
  226. scan = function(xx, zz) -- сканирование квадрата x8 относительно робота
  227.   local raw, index = geolyzer.scan(xx, zz, -1, 8, 8, 1), 1 -- получить сырые данные, установить индекс в начало таблицы
  228.   for z = zz, zz+7 do -- развертка данных по z
  229.     for x = xx, xx+7 do -- развертка данных по х
  230.       if raw[index] >= min and raw[index] <= max then -- если обнаружен блок с подходящей плотностью
  231.         table.insert(WORLD.x, X+x) --| записать метку в список
  232.         table.insert(WORLD.y, Y-1) --| с коррекцией локальных
  233.         table.insert(WORLD.z, Z+z) --| координат геосканера
  234.       elseif raw[index] < -0.31 then -- если обнаружен блок с отрицательной плотностью
  235.         border = Y -- сделать отметку
  236.       end
  237.       index = index + 1 -- переход к следующему индексу сырых даннх
  238.     end
  239.   end
  240. end
  241.  
  242. calibration = function() -- калибровка при запуске
  243.   if not controller then -- проверить наличие контроллера инвентаря
  244.     report('inventory controller not detected', true)
  245.   elseif not geolyzer then -- проверить наличие геосканера
  246.     report('geolyzer not detected', true)
  247.   elseif not robot.detect(0) then
  248.     report('bottom solid block is not detected', true)
  249.   elseif not robot.durability() then
  250.     report('there is no suitable tool in the manipulator', true)
  251.   end
  252.   local clist = computer.getDeviceInfo()
  253.   for i, j in pairs(clist) do
  254.     if j.description == 'Solar panel' then
  255.       solar = true
  256.       break
  257.     end
  258.   end
  259.   if chunkloader then -- если есть чанклоадер
  260.     chunkloader.setActive(true) -- включить
  261.   end
  262.   if modem then -- если есть модем
  263.     --modem.open(port)
  264.     modem.setWakeMessage('') -- установить сообщение пробуждения
  265.     modem.setStrength(400) -- установить силу сигнала
  266.   elseif tunnel then -- если есть туннель
  267.     tunnel.setWakeMessage('') -- установить сообщение пробуждения
  268.   end
  269.   for slot = 1, inventory do -- пройти по слотам инвентаря
  270.     if robot.count(slot) == 0 then -- если слот пуст
  271.       robot.select(slot) -- выбрать слот
  272.       break
  273.     end
  274.   end
  275.   local energy = computer.energy() -- получить уровень энергии
  276.   step(0) -- сделать шаг
  277.   E_C = math.ceil(energy-computer.energy()) -- записать уровень потребления
  278.   energy = robot.durability() -- получить уровень износа/разряда инструмента
  279.   while energy == robot.durability() do -- пока не обнаружена разница
  280.     robot.place(3) -- установить блок
  281.     robot.swing(3) -- разрушить блок
  282.   end
  283.   W_R = energy-robot.durability() -- записать результат
  284.   local sides = {2, 1, 3, 0} -- линки сторон света, для сырых данных
  285.   D = nil -- обнуление направления
  286.   for s = 1, #sides do -- проверка всех направлений
  287.     if robot.detect(3) or robot.place(3) then -- проверить наличие блока перед носом
  288.       local A = geolyzer.scan(-1, -1, 0, 3, 3, 1) -- сделать первый скан
  289.       robot.swing(3) -- сломать блок
  290.       local B = geolyzer.scan(-1, -1, 0, 3, 3, 1) -- сделать второй скан
  291.       for n = 2, 8, 2 do -- обойти смежные блоки в таблице
  292.         if math.ceil(B[n])-math.ceil(A[n])<0 then -- если блок исчез
  293.           D = sides[n/2] -- установить новое направление
  294.           break -- выйти из цикла
  295.         end
  296.       end
  297.     else
  298.       turn() -- задействовать простой поворот
  299.     end
  300.   end
  301.   if not D then
  302.     report('calibration error', true)
  303.   end
  304. end
  305.  
  306. sorter = function(pack) -- сортировка лута
  307.   robot.swing(0) -- освободить место для мусора
  308.   robot.swing(1) -- освободить место для буфера
  309.   ------- сброс мусора -------
  310.   local empty, available = 0, {} -- создать счетчик пустых слотов и доступных для упаковки
  311.   for slot = 1, inventory do -- пройти по слотам инвентаря
  312.     local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
  313.     if item then -- если есть предмет
  314.       local name = item.name:gsub('%g+:', '')
  315.       if tails[name] then -- проверить на совпадение в списке отходов
  316.         robot.select(slot) -- выбрать слот
  317.         robot.drop(0) -- выбросить к отходам
  318.         empty = empty + 1 -- обновить счетчик
  319.       elseif fragments[name] then -- если есть совпадение в списке фрагментов
  320.         if available[name] then -- если уже создан счетчик
  321.           available[name] = available[name] + item.size -- обновить количество
  322.         else -- иначе
  323.           available[name] = item.size -- задать счетчик для имени
  324.         end
  325.       end
  326.     else -- обнаружен пустой слот
  327.       empty = empty + 1 -- обновить счетчик
  328.     end
  329.   end
  330.   -- упаковка предметов в блоки --
  331.   if crafting and (empty < 12 or pack) then -- если есть верстак и меньше 12 свободных слотов или задана принудительная упаковка
  332.     -- перенос лишних предметов в буфер --
  333.     if empty < 10 then -- если пустых слотов меньше 10
  334.       empty = 10-empty -- увеличить количество пустых слотов для обратного отсчета
  335.       for slot = 1, inventory do -- просканировать инвентарь
  336.         local item = controller.getStackInInternalSlot(slot)
  337.         if item then -- если слот не пуст
  338.           if not wlist[item.name] then -- проверка имени, чтобы не выкинуть важный предмет в лаву
  339.             local name = item.name:gsub('%g+:', '') -- отформатировать имя
  340.             if available[name] then -- если есть в счетчике
  341.               available[name] = available[name] - item.size -- обновить счетчик
  342.             end
  343.             robot.select(slot) -- выбрать слот
  344.             robot.drop(1) -- выбросить в буфер
  345.             empty = empty - 1 -- обновить счетчик
  346.           end
  347.         end
  348.         if empty == 0 then -- если место освободилось
  349.           break -- прервать цикл
  350.         end
  351.       end
  352.     end
  353.     ------- основной цикл крафта -------
  354.     for o, m in pairs(available) do
  355.       if m > 8 then
  356.         for l = 1, math.ceil(m/576) do
  357.           -- очистка рабочей зоны --
  358.           for i = 1, 9 do -- пройти по слотам верстака
  359.             if robot.count(workbench[i]) > 0 then -- если слот не пуст
  360.               robot.select(workbench[i]) -- выбрать слот
  361.               for slot = 4, inventory do -- перебор слотов инвентаря
  362.                 if slot == 4 or slot == 8 or slot > 11 then -- исключить слоты верстака
  363.                   robot.transferTo(slot) -- попробовать переместить предметы
  364.                   if robot.count(slot) == 0 then -- если слот освободился
  365.                     break -- прервать цикл
  366.                   end
  367.                 end
  368.               end
  369.               if robot.count() > 0 then -- если обнаружена перегрузка
  370.                 while robot.suck(1) do end -- забрать предметы из буфера
  371.                 return -- прекратить упаковку
  372.               end
  373.             end
  374.           end
  375.           for slot = 4, inventory do -- цикл поиска фрагментов
  376.             local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
  377.             if item and (slot == 4 or slot == 8 or slot > 11) then -- если есть предмет вне рабочей зоны
  378.               if o == item.name:gsub('%g+:', '') then -- если предмет совпадает
  379.                 robot.select(slot) -- при совпадении выбрать слот
  380.                 for n = 1, 10 do -- цикл заполнения рабочей зоны
  381.                   robot.transferTo(workbench[n%9+1], item.size/9) -- разделить текущий стак на 9 частей и перенести в верстак
  382.                 end
  383.                 if robot.count(1) == 64 then -- сброс при заполнении верстака
  384.                   break
  385.                 end
  386.               end
  387.             end
  388.           end
  389.           robot.select(inventory) -- выбор последнего слота
  390.           crafting.craft() -- создание блока
  391.           -- цикл сортировки остатков
  392.           for A = 1, inventory do -- основной проход
  393.             local size = robot.count(A) -- получить количество предметов
  394.             if size > 0 and size < 64 then -- если слот не пуст и не полон
  395.               for B = A+1, inventory do -- проход сравнения
  396.                 if robot.compareTo(B) then -- если предметы одинаковые
  397.                   robot.select(A) -- выбрать слот
  398.                   robot.transferTo(B, 64-robot.count(B)) -- перенести до заполнения
  399.                 end
  400.                 if robot.count() == 0 then -- если слот освободился
  401.                   break -- прервать сравнение
  402.                 end
  403.               end
  404.             end
  405.           end
  406.         end
  407.       end
  408.     end
  409.   end
  410.   while robot.suck(1) do end --- забрать предметы из буфера
  411.   local items = 0
  412.   for slot = 1, inventory do
  413.     if robot.count(slot) > 0 then
  414.       items = items + 1
  415.     end
  416.   end
  417.   if inventory-items < 5 or items/inventory > 0.9 then
  418.     home()
  419.   end
  420. end
  421.  
  422. home = function(forcibly) -- переход к начальной точке и сброс лута
  423.   local x, y, z
  424.   report('ore unloading')
  425.   local enderchest -- обнулить слот с эндерсундуком
  426.   for slot = 1, inventory do -- просканировать инвентарь
  427.     local item = controller.getStackInInternalSlot(slot) -- получить информацию о слоте
  428.     if item then -- если есть предмет
  429.       if item.name == 'enderstorage:ender_storage' then -- если есть эндерсундук
  430.         enderchest = slot -- задать слот
  431.         break -- прервать поиск
  432.       end
  433.     end
  434.   end
  435.   if enderchest and not forcibly then -- если есть сундук и нет принудительного возвращения домой
  436.     -- step(1) -- подняться на 1 блок
  437.     robot.swing(3) -- освободить место для сундука
  438.     robot.select(enderchest) -- выбрать сундук
  439.     robot.place(3) -- поставить сундук
  440.   else
  441.     x, y, z = X, Y, Z
  442.     go(0, -2, 0)
  443.     go(0, 0, 0)
  444.   end
  445.   sorter() -- сортировка инвентаря
  446.   local size = nil -- обнулить размер контейнера
  447.   while true do -- войти в бесконечный цикл
  448.     for side = 1, 4 do -- поиск контейнера
  449.       size = controller.getInventorySize(3) -- получение размера инвентаря
  450.       if size and size>26 then -- если контейнер найден
  451.         break -- прервать поиск
  452.       end
  453.       turn() -- повернуться
  454.     end
  455.     if not size or size<26 then -- если контейнер не найден
  456.       report('container not found') -- послать сообщение
  457.       sleep(30)
  458.     else
  459.       break -- продолжить работу
  460.     end
  461.   end
  462.   for slot = 1, inventory do -- обойти весь инвентарь
  463.     local item = controller.getStackInInternalSlot(slot)
  464.     if item then -- если слот не пуст
  465.       if not wlist[item.name] then -- если предмет не в белом списке
  466.         robot.select(slot) -- выбрать слот
  467.         local a, b = robot.drop(3) -- сбросить в контейнер
  468.         if not a and b == 'inventory full' then -- если контейнер заполнен
  469.           while not robot.drop(3) do -- ждать, пока не освободится
  470.             report(b) -- послать сообщение
  471.             sleep(30) -- подождать
  472.           end
  473.         end
  474.       end
  475.     end
  476.   end
  477.   if crafting then -- если есть верстак, забрать предметы из сундука и упаковать
  478.     for slot = 1, size do -- обход слотов контейнера
  479.       local item = controller.getStackInSlot(3, slot) -- получить информацию о пердмете
  480.       if item then -- если есть предмет
  481.         if fragments[item.name:gsub('%g+:', '')] then -- если есть совпадение
  482.           controller.suckFromSlot(3, slot) -- забрать предметы
  483.         end
  484.       end
  485.     end
  486.     sorter(true) -- упаковать
  487.     for slot = 1, inventory do -- обойти весь инвентарь
  488.       local item = controller.getStackInInternalSlot(slot)
  489.       if item then -- если слот не пуст
  490.         if not wlist[item.name] then -- если предмет не в белом списке
  491.           robot.select(slot) -- выбрать слот
  492.           robot.drop(3) -- сбрость в контейнер
  493.         end
  494.       end
  495.     end
  496.   end
  497.   if generator and not forcibly then -- если есть генератор
  498.     for slot = 1, size do -- просканировать контейнер
  499.       local item = controller.getStackInSlot(3, slot) -- получить информацию о пердмете
  500.       if item then -- если есть предмет
  501.         if item.name:sub(11, 15) == 'coal' then -- если в слоте уголь
  502.           controller.suckFromSlot(3, slot) -- взять
  503.           break -- выйти из цикла
  504.         end
  505.       end
  506.     end
  507.   end
  508.   if forcibly then
  509.     report('tool search in container')
  510.     if robot.durability() < 0.3 then -- если прочность инструмента меньше 30%
  511.       robot.select(1) -- выбрать первый слот
  512.       controller.equip() -- поместить инструмент в инвентарь
  513.       local tool = controller.getStackInInternalSlot(1) -- получить данные инструмента
  514.       for slot = 1, size do
  515.         local item = controller.getStackInSlot(3, slot)
  516.         if item then
  517.           if item.name == tool.name and item.damage < tool.damage then
  518.             robot.drop(3)
  519.             controller.suckFromSlot(3, slot)
  520.             break
  521.           end
  522.         end
  523.       end
  524.       controller.equip() -- экипировать
  525.     end
  526.     report('attempt to repair tool')
  527.     if robot.durability() < 0.3 then -- если инструмент не заменился на лучший
  528.       for side = 1, 3 do -- перебрать все стороны
  529.         local name = controller.getInventoryName(3) -- получить имя инвенторя
  530.         if name == 'opencomputers:charger' or name == 'tile.oc.charger' then -- сравнить имя
  531.           robot.select(1) -- выбрать слот
  532.           controller.equip() -- достать инструмент
  533.           if robot.drop(3) then -- если получилось засунуть инструмент в зарядник
  534.             local charge = controller.getStackInSlot(3, 1).charge
  535.             local max_charge = controller.getStackInSlot(3, 1).maxCharge
  536.             while true do
  537.               sleep(30)
  538.               local n_charge = controller.getStackInSlot(3, 1).charge -- получить заряд
  539.               if charge then
  540.                 if n_charge == max_charge then
  541.                   robot.suck(3) -- забрать предмет
  542.                   controller.equip() -- экипировать
  543.                   break -- остановить зарядку
  544.                 else
  545.                   report('tool is '..math.floor((n_charge+1)/max_charge*100)..'% charged')
  546.                 end
  547.               else -- если инструмент не чинится
  548.                 report('tool could not be charged', true) -- остановить работу
  549.               end
  550.             end
  551.           else
  552.             report('tool could not be repaired', true) -- остановить работу
  553.           end
  554.         else
  555.           turn() -- повернуться
  556.         end
  557.       end
  558.       while robot.durability() < 0.3 do
  559.         report('need a new tool')
  560.         sleep(30)
  561.       end
  562.     end
  563.   end
  564.   if enderchest and not forcibly then
  565.     robot.swing(3) -- забрать сундук
  566.   else
  567.     while energy_level() < 0.98 do -- ждать полного заряда батареи
  568.       report('charging')
  569.       sleep(30)
  570.     end
  571.   end
  572.   ignore_check = nil
  573.   report('return to work')
  574.   go(0, -2, 0)
  575.   go(x, y, z)
  576. end
  577.  
  578. main = function()
  579.   border = nil
  580.   while not border do
  581.     step(0)
  582.     for q = 1, 4 do
  583.       scan(table.unpack(quads[q]))
  584.     end
  585.     check(true)
  586.   end
  587.   while #WORLD.x ~= 0 do
  588.     local n_delta, c_delta, current = math.huge, math.huge
  589.     for index = 1, #WORLD.x do
  590.       n_delta = math.abs(X-WORLD.x[index])+math.abs(Y-WORLD.y[index])+math.abs(Z-WORLD.z[index])-border+WORLD.y[index]
  591.       if (WORLD.x[index] > X and D ~= 3) or
  592.       (WORLD.x[index] < X and D ~= 1) or
  593.       (WORLD.z[index] > Z and D ~= 0) or
  594.       (WORLD.z[index] < Z and D ~= 2) then
  595.         n_delta = n_delta + 1
  596.       end
  597.       if n_delta < c_delta then
  598.         c_delta, current = n_delta, index
  599.       end
  600.     end
  601.     if WORLD.x[current] == X and WORLD.y[current] == Y and WORLD.z[current] == Z then
  602.       remove_point(current)
  603.     else
  604.       local yc = WORLD.y[current]
  605.       if yc-1 > Y then
  606.         yc = yc-1
  607.       elseif yc+1 < Y then
  608.         yc = yc+1
  609.       end
  610.       go(WORLD.x[current], yc, WORLD.z[current])
  611.     end
  612.   end
  613.   sorter()
  614. end
  615.  
  616. calibration() -- запустить калибровку
  617. calibration = nil -- освободить память от функции калибровки
  618. local Tau = computer.uptime() -- записать текущее время
  619. local pos = {0, 0, 0, [0] = 1} -- таблица для хранения координат чанков
  620. for o = 1, 10 do -- цикл ограничения спирали
  621.   for i = 1, 2 do -- цикл обновления координат
  622.     for a = 1, o do -- цикл перехода по линии спирали
  623.       main() -- запуск функции сканирования и добычи
  624.       report('chunk #'..pos[3]+1 ..' processed') -- сообщить о завершении работы в чанке
  625.       pos[i], pos[3] = pos[i] + pos[0], pos[3] + 1 -- обновить координаты
  626.       if pos[3] == chunks then -- если достигнут последний чанк
  627.         home(true) -- возврат домой
  628.         report(computer.uptime()-Tau..' seconds\npath length: '..steps..'\nmade turns: '..turns, true) -- сообщить о завершении работы
  629.       else -- иначе
  630.         go(pos[1]*16, -2, pos[2]*16) -- перейти к следующему чанку
  631.         go(X, 0, Z) -- перейти в стартовую точку сканирования
  632.       end
  633.     end
  634.   end
  635.   pos[0] = 0-pos[0] -- обновить направление спирали
  636. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement