Перейти к содержимому

some blog name

  • записей
    15
  • комментарий
    41
  • просмотров
    17 626

Робот с геосканером. Часть #6 [приучаем к порядку]

Doob

723 просмотра

Добытые ресурсы надобно рассортировать.

Для этого дела задействуем контроллер инвентаря. Надобно пройти по всем слотам, получить информацию о содержимом и сравнить название со списком ненужных предметов (который предварительно составим), при совпадении опустошать.

 

Но это не вся функция. У нас есть еще верстак, который может помочь, очень сильно ужать, некоторые ресурсы (уголь, редстоун, алмазы, изумруды, лазурит). Верстак занимает в инвентаре 9 слотов, еще 1 слот добавим на результат, если не все влезет в блок.

Поэтому, пока робот ищет мусор, пусть считает пустые слоты, для верстака. В начале уберем блоки сверху и снизу, чтобы случайно не перемешать мусор с излишками добра.

для удобоваримости сократил некоторые имена: inventory - размер инвентаря, получим в начале работы программы, controller - контроллер инвентаря, tails - список названий лишних предметов (без префикса "minecraft:", можно добавлять названия из любого мода)

  robot.swing(0) -- освободить место для мусора
  robot.swing(1) -- освободить место для буфера
  ------- сброс мусора -------
  local empty = 0 -- создать счетчик пустых слотов
  for slot = 1, inventory do -- пройти по слотам инвентаря
    local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
    if item then -- если есть предмет
      for name = 1, #tails do -- пройти по таблице хвостов
        if item.name:gsub('%g+:', '') == tails[name] then -- проверить на совпадение
          robot.select(slot) -- выбрать слот
          robot.drop(0) -- выбросить к отходам
          empty = empty + 1 -- обновить счетчик
          break -- прервать цикл сравнения
        end
      end
    else
      empty = empty + 1 -- обновить счетчик
    end
  end

 

Далее следует проверить и выкинуть наверх предметы, которые будут мешать при крафте.

Подсчитанные пустые слоты отнимем от требуемого количества для крафта, пройдем по инвентарю уберем их.

  -- упаковка предметов в блоки --
  if crafting then -- если есть верстак
    -- перенос лишних предметов в буфер --
    if empty < 10 then -- если пустых слотов меньше 10
      empty = 10-empty -- увеличить количество пустых слотов для обратного отсчета
      for slot = 1, inventory do -- просканировать инвентарь
        if robot.count(slot) > 0 then -- если слот не пуст
          robot.select(slot) -- выбрать слот
          robot.drop(1) -- выбросить в буфер
          empty = empty - 1 -- обновить счетчик
        end
        if empty == 0 then -- если место освободилось
          break -- прервать цикл
        end
      end
    end

 

Предварительно создадим таблицу fragments, в которой будут храниться названия предметов, которые можно сложить в блоки.

Теперь создадим таблицу, в которой будут счетчики для каждого типа фрагментов.

Пройдем по инвентарю, получим информацию о слоте, сравним, прибавим - все как в первом цикле, можно было бы даже их объединить, но на предыдущем шаге мы выкинули какие-то предметы. Чтобы узнать какие именно - придется городить еще один цикл, оставим как есть.

    -- подсчет предметов доступных для упаковки --
    local available = {} -- создать таблицу счетчиков
    for slot = 1, inventory do -- пройти по слотам инвентаря
      local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
      if item then -- если есть предмет
        for n = 1, #fragments do -- пройти по списку названий фрагментов
          if item.name:gsub('%g+:', '') == fragments[n] then -- сравнить по имени
            if available[n] then -- если есть подобные фрагменты
              available[n] = available[n] + item.size -- обновить
            else -- иначе
              available[n] = item.size -- создать
            end
            break
          end
        end
      end
    end

 

Наконец-то можно крафтить. Хотя, нет. Надо расчистить слоты верстака, чтобы в него сложить рецепт.

Будем перебирать слоты от 1 до 9, но в роботе верстак занимает слоты с другими номерами, а именно 1 2 3 5 6 7 9 10 11, можно было бы составить условие от 1 до 11, с исключением целых по модулю 4. Сделаем проще - номера слотов занесем в таблицу "workbench", которая будет служить списком ссылок с системы 1-9 на 1-11. Вынесем ее подальше, чтобы она не создавалась при каждом запуске.

В цикле проверяем количество предметов в слоте, если оно не нулевое - ищем в инвентаре пустой слот, исключая слоты верстака.

Переносим предметы в найденный слот.

Если перенести не удалось - что-то попало в верстак после крафта. Забираем предметы из буфера и завершаем функцию, возвращая true, что будет сообщать о перегрузе и времени выдвигаться домой.

          for c_slot = 1, 9 do -- цикл чистки зоны верстака
            if robot.count(workbench[c_slot]) > 0 then -- если слот не пуст
              robot.select(workbench[c_slot]) -- выбрать слот верстака
              for slot = 4, inventory do -- обойти весь инвентарь, кроме рабочей зоны
                if robot.count(slot) == 0 and (slot == 4 or slot == 8 or slot > 11) then -- если есть свободный
                  robot.transferTo(slot) -- освободить слот
                  break -- выйти из цикла
                end
              end
              if robot.count() > 0 then -- проверить на перегрузку
                robot.suck(1) -- забрать из буфера
                return true -- остановить упаковку
              end
            end
          end

 

Верстак расчищен, пора заняться упаковкой.

Перебираем слоты инвентаря, исключая верстак, сравниваем названия со списком. При совпадении, делим содержимое на 9, заполняем верстак И крафтим блок.

          ------- основной цикл крафта -------
          for slot = 4, inventory do -- цикл поиска фрагментов
            local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
            if item and (slot == 4 or slot == 8 or slot > 11) then -- если есть предмет вне рабочей зоны
              if item.name:gsub('%g+:', '') == fragments[i] then -- сравнить по названию фрагмента
                robot.select(slot) -- при совпадении выбрать слот
                for n = 1, 9 do -- цикл заполнения рабочей зоны
                  robot.transferTo(workbench[n], item.size/9) -- разделить текущий стак на 9 частей и перенести в верстак
                end
                if robot.count(1) == 64 then -- сброс при заполнении верстака
                  break
                end
              end
            end
          end
          crafting.craft() -- создание блока

Можно заметить fragments, откуда i? Об этом позже.

 

После крафта могли остаться какие-то остатки, если не все слоты поделились на 9.

Проверяем содержимое в слотах, если предметов меньше 64 - перебираем слоты после текущего и сравниваем, при совпадении содержимого пробуем перенести. При опустошении текущего слота - прерываем перебор со сравнением.

          -- цикл сортировки остатков
          for A = 1, inventory do -- основной проход
            local size = robot.count(A) -- получить количество предметов
            if size > 0 and size < 64 then -- если слот не пуст и не полон
              robot.select(A) -- выбрать слот
              for B = A+1, inventory do -- проход сравнения
                if robot.compareTo(B) then -- если предметы одинаковые
                  robot.transferTo(B, 64-robot.count(B)) -- перенести до заполнения
                end
                if robot.count() == 0 then -- если слот освободился
                  break -- прервать сравнение
                end
              end
            end
          end

 

Последние три цикла заворачиваем в такую конструкцию:

    for i = 1, #fragments do -- перебор всех названий
      if available[i] then -- если в инвентаре такой есть
        for j = 1, math.ceil(available[i]/576) do -- разделить результат на стаки
          ...
        end
      end
    end

Первый цикл перебирает названия фрагментов.

Условный оператор проверяет наличие такого типа в инвентаре.

Внутренний цикл повторяет чистку, крафт и сортировку, если в результате будет больше стака блоков.

 

 

Новые используемые переменные:

local tails = {'cobblestone','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'}
local workbench = {1,2,3,5,6,7,9,10,11}
local fragments = {'redstone','coal','dye','diamond','emerald'}

local controller = add_component('inventory_controller')
local crafting = add_component('crafting')
local inventory = robot.inventorySize()

 

Полный текст функции, с более рациональным вызовом robot.count():

local function sorter() -- сортировка лута
  robot.swing(0) -- освободить место для мусора
  robot.swing(1) -- освободить место для буфера
  ------- сброс мусора -------
  local empty = 0 -- создать счетчик пустых слотов
  for slot = 1, inventory do -- пройти по слотам инвентаря
    local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
    if item then -- если есть предмет
      for name = 1, #tails do -- пройти по таблице хвостов
        if item.name:gsub('%g+:', '') == tails[name] then -- проверить на совпадение
          robot.select(slot) -- выбрать слот
          robot.drop(0) -- выбросить к отходам
          empty = empty + 1 -- обновить счетчик
          break -- прервать цикл сравнения
        end
      end
    else
      empty = empty + 1 -- обновить счетчик
    end
  end
  -- упаковка предметов в блоки --
  if crafting and empty < 12 then -- если есть верстак и переполнение
    -- перенос лишних предметов в буфер --
    if empty < 10 then -- если пустых слотов меньше 10
      empty = 10-empty -- увеличить количество пустых слотов для обратного отсчета
      for slot = 1, inventory do -- просканировать инвентарь
        if robot.count(slot) > 0 then -- если слот не пуст
          robot.select(slot) -- выбрать слот
          robot.drop(1) -- выбросить в буфер
          empty = empty - 1 -- обновить счетчик
        end
        if empty == 0 then -- если место освободилось
          break -- прервать цикл
        end
      end
    end
    -- подсчет предметов доступных для упаковки --
    local available = {} -- создать таблицу счетчиков
    for slot = 1, inventory do -- пройти по слотам инвентаря
      local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
      if item then -- если есть предмет
        for n = 1, #fragments do -- пройти по списку названий фрагментов
          if item.name:gsub('%g+:', '') == fragments[n] then -- сравнить по имени
            if available[n] then -- если есть подобные фрагменты
              available[n] = available[n] + item.size -- обновить
            else -- иначе
              available[n] = item.size -- создать
            end
            break
          end
        end
      end
    end
    ------- основной цикл крафта -------
    for i = 1, #fragments do -- перебор всех названий
      if available[i] then -- если в инвентаре такой есть
        for j = 1, math.ceil(available[i]/576) do -- разделить результат на стаки
          for c_slot = 1, 9 do -- цикл чистки зоны верстака
            if robot.count(workbench[c_slot]) > 0 then -- если слот не пуст
              for slot = 4, inventory do -- обойти весь инвентарь, кроме рабочей зоны
                if robot.count(slot) == 0 and (slot == 4 or slot == 8 or slot > 11) then -- если есть свободный
                  robot.select(workbench[c_slot]) -- выбрать слот верстака
                  robot.transferTo(slot) -- освободить слот
                  break -- выйти из цикла
                end
              end
              if robot.count() > 0 then -- проверить на перегрузку
                robot.suck(1) -- забрать из буфера
                return true -- остановить упаковку
              end
            end
          end
          ------- основной цикл крафта -------
          for slot = 4, inventory do -- цикл поиска фрагментов
            local item = controller.getStackInInternalSlot(slot) -- получить информацию о предмете
            if item and (slot == 4 or slot == 8 or slot > 11) then -- если есть предмет вне рабочей зоны
              if item.name:gsub('%g+:', '') == fragments[i] then -- сравнить по названию фрагмента
                robot.select(slot) -- при совпадении выбрать слот
                for n = 1, 9 do -- цикл заполнения рабочей зоны
                  robot.transferTo(workbench[n], item.size/9) -- разделить текущий стак на 9 частей и перенести в верстак
                end
                if robot.count(1) == 64 then -- сброс при заполнении верстака
                  break
                end
              end
            end
          end
          crafting.craft() -- создание блока
          -- цикл сортировки остатков
          for A = 1, inventory do -- основной проход
            local size = robot.count(A) -- получить количество предметов
            if size > 0 and size < 64 then -- если слот не пуст и не полон
              for B = A+1, inventory do -- проход сравнения
                if robot.compareTo(B) then -- если предметы одинаковые
                  robot.select(A) -- выбрать слот
                  robot.transferTo(B, 64-robot.count(B)) -- перенести до заполнения
                end
                if robot.count() == 0 then -- если слот освободился
                  break -- прервать сравнение
                end
              end
            end
          end
        end
      end
    end
  end
  robot.suck(1) --- забрать предметы из буфера
end

 

  • Нравится 3


0 комментариев


Рекомендуемые комментарии

Нет комментариев для отображения

Гость
Добавить комментарий...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...