Jump to content

Автоматизация выведения пчелок


Recommended Posts

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

Даже не буду описывать свой путь к финальному варианту, так как он был на столько длинный, что половину я уже забыл, так что приступим сразу к делу!

1. Что нужно для схемы:

Спойлер

Сам компьютер собирается из следующих компонентов:

  • системный блок 3-го уровня
  • видеокарта 3-го уровня
  • центральный процессор 2-го уровня
  • память 2-го уровня (2 штуки)
  • жесткий диск 2-го уровня
  • EEPROM (Lua BIOS)
  • дискета OpenOS
  • клавиатура
  • монитор 3-го уровня (лучше всего 6 штук)

Из обязательного тут только видеокарта 3-го уровня, соответственно и системник. Остальное можете использовать 1-го уровня или как-либо экспериментировать со сборкой. Оперативки лучше не жалейте, так как программа использует рекурсию, а на сложных пчел потребуется много оперативной памяти.

Про установку операционной системы и настройку  Lua BIOS я уже неоднократно писал в прошлых гайдах, ниже будет ссылка.

Для сборки остальной системы нам потребуется:

  • несколько кабелей
  • транспозер
  • 2 обычных сундука
  • алмазный или дракониевый сундук (чем больше будет места, тем лучше)
  • любые предметные трубы (я использую из EnderIO)
  • пасека

Подводим энергию к компьютеру и собираем все приблизительно так

Screenshot_2.png.7c368485f62ac3ccf2afd54c012fafb2.png

Screenshot_3.thumb.png.1a37bf4521ef0e4d49bd9ed474a9904f.png

Тут у нас 3 сундука: хранилище, ввод в пасеку, вывод из пасеки. Все это дело контролируется транспозером, благодаря чему все работает. В хранилище (алмазный сундук) сложите всех ваших пчел.

На этом внешняя часть схемы готова.

2. Программная часть

Спойлер

Программа состоит из двух частей: главная программа и список всех пчел с инструкцией их вывода. 

Главная программа:

Спойлер
local component = require("component")
local sides = require("sides")
local transposer = component.transposer
local filesystem = require("filesystem")
local shell = require("shell")
local term = require("term")
local event = require("event")
local currentDir = shell.getWorkingDirectory()
local beeTreePath = filesystem.concat(currentDir, "bees.lua")
local bee_tree = dofile(beeTreePath)

--===========ВАЖНО==================
--бывают случаи, когда программа находит двух трутней или двух принцесс, из-за чего ломается

local bee_storage_side = sides.west -- сторона, на которой находится сундук с пчелами
local breeding_side = sides.north   -- сторона, на которой находится сундук для вывода пчел
local new_bee_side = sides.east     -- сторона, на которой находится сундук с новыми пчелами
--==================================

local TIME_SLEEP = 20
local bee_storage_size = transposer.getInventorySize(bee_storage_side)
local bee_storage = {
    ["drone"] = {},
    ["princess"] = {}
}

function scanBeeStorage() --функция сканирования хранилища с пчелами
    local function bee_find(name_hight, name_low, bee_name)
        bee_name = bee_name:gsub(name_hight, "")
        if not bee_storage[name_low][bee_name] then
            bee_storage[name_low][bee_name] = 0
        end
        bee_storage[name_low][bee_name] = bee_storage[name_low][bee_name] + 1
    end

    bee_storage["drone"] = {}
    bee_storage["princess"] = {}

    for slot = 1, bee_storage_size do
        local stack = transposer.getStackInSlot(bee_storage_side, slot)
        if stack then
            local bee_name = stack.label

            if bee_name:find("Drone") then
                bee_find(" Drone", "drone", bee_name)
            elseif bee_name:find("Princess") then
                bee_find(" Princess", "princess", bee_name)
            end
        end
    end
end

function targetBeeExists(target_bee) -- функция проверки на наличие целевой пчелы
    if bee_storage["drone"][target_bee] and bee_storage["drone"][target_bee] > 0 then
        return true
    end
    if bee_storage["princess"][target_bee] and bee_storage["princess"][target_bee] > 0 then
        return true
    end
    return false
end

function findBeePair(target_bee) --функция поиска пары пчел для разведения
    print("Поиск пары для выведения:", target_bee)
    if not bee_tree[target_bee] then
        print("Нет информации о выведении:", target_bee)
        return nil, nil
    end

    for parent1, _ in pairs(bee_tree[target_bee]) do
        for parent2, _ in pairs(bee_tree[target_bee]) do

            if parent1 ~= parent2 then              
                print("Проверяем наличие пчел:", parent1, parent2)
                if bee_storage["drone"][parent1] and bee_storage["princess"][parent2] then
                    print("Пара найдена:", parent1, parent2)
                    return parent1, parent2

                elseif bee_storage["drone"][parent2] and bee_storage["princess"][parent1] then
                    print("Пара найдена:", parent2, parent1)
                    return parent2, parent1
                end
            end
        end
    end
    print("Не найдена пара для вывода:", target_bee)
    return nil, nil
end

function moveBeesForBreeding(parent1, parent2) --функция переноса пары пчел для разведения
    local function move_bee_from_slot(parent, slot, type_bee1)
        transposer.transferItem(bee_storage_side, breeding_side, 1, slot)
        bee_storage[type_bee1][parent] = bee_storage[type_bee1][parent] - 1
        if bee_storage[type_bee1][parent] == 0 then
            bee_storage[type_bee1][parent] = nil
        end
    end

    print("Перенос пчел в пасеку:", parent1, parent2)
    local drone_moved = false
    local princess_moved = false

    for slot = 1, bee_storage_size do
        if drone_moved and princess_moved then break end

        local stack = transposer.getStackInSlot(bee_storage_side, slot)
        if stack then
            local bee_name = stack.label

            if bee_name == parent1 .. " Drone" and not drone_moved then
                print("Переносим ", bee_name, "из слота", slot)
                move_bee_from_slot(parent1, slot, "drone")
                drone_moved = true

            elseif bee_name == parent2 .. " Princess" and not princess_moved then
                print("Переносим", bee_name, "из слота", slot)
                move_bee_from_slot(parent2, slot, "princess")
                princess_moved = true
            end

        end
    end
end

function collectNewBees() -- функция перемещения новых пчел в хранилище
    print("Собираем новых пчел")
    
    for slot = 1, transposer.getInventorySize(new_bee_side) do
        local stack = transposer.getStackInSlot(new_bee_side, slot)
        if stack then
            local bee_name = stack.label
            if bee_name:find("Drone") then
                local name = bee_name:gsub(" Drone", "")
                if not bee_storage["drone"][name] then
                    bee_storage["drone"][name] = 0
                end
                bee_storage["drone"][name] = bee_storage["drone"][name] + 1
            elseif bee_name:find("Princess") then
                local name = bee_name:gsub(" Princess", "")
                if not bee_storage["princess"][name] then
                    bee_storage["princess"][name] = 0
                end
                bee_storage["princess"][name] = bee_storage["princess"][name] + 1
            end
            transposer.transferItem(new_bee_side, bee_storage_side, 1, slot)
        end
    end
end

function breedUntilTarget(target_bee) --рекурсивная функция поиска нужной пчелы
    while true do
        scanBeeStorage()
        if targetBeeExists(target_bee) then
            print("Целевая пчела найдена:", target_bee)
            return true
        end

        local parent1, parent2 = findBeePair(target_bee)
        if parent1 and parent2 then
            moveBeesForBreeding(parent1, parent2)
  
            repeat
                local stack = transposer.getSlotStackSize(new_bee_side, 1)
                os.sleep(TIME_SLEEP)
            until stack > 0

            collectNewBees()
        else
            print("Невозможно найти комбинацию для вывода этой пчелы, попытка обхода")

            local success = false
            for parent1, _ in pairs(bee_tree[target_bee]) do
                for parent2, _ in pairs(bee_tree[target_bee]) do
                    if parent1 ~= parent2 then
                        if not targetBeeExists(parent1) or not targetBeeExists(parent2) then
                            if breedUntilTarget(parent1) and breedUntilTarget(parent2) then
                                success = true
                                break
                            end
                        end
                    end
                end
                if success then break end
            end

            if not success then
                print("Error: Все попытки обхода провалились.")
                return false
            end
        end
    end
end

function main()  
    local success = breedUntilTarget(target_bee)
    if not success then
        print("Не удалось вывести целевую пчелу:", target_bee)
    else
        print("Целевая пчела успешно выведена:", target_bee)
    end
end

local function displayMenu()
    local bee_list = {}
    for bee, _ in pairs(bee_tree) do
        table.insert(bee_list, bee)
    end

    local screen_height = 50
    local items_per_page = screen_height - 2
    local current_page = 1
    local total_pages = math.ceil(#bee_list / items_per_page)

    while true do
        term.clear()
        print("Выберите целевую пчелу (Страница " .. current_page .. " из " .. total_pages .. "):")

        local start_index = (current_page - 1) * items_per_page + 1
        local end_index = math.min(current_page * items_per_page, #bee_list)

        for i = start_index, end_index do
            print(string.format("%d. %s", i, bee_list[i]))
        end

        print("Введите номер пчелы, 'n' для следующей страницы, 'p' для предыдущей страницы:")

        local input = io.read()
        if input == "n" and current_page < total_pages then
            current_page = current_page + 1
        elseif input == "p" and current_page > 1 then
            current_page = current_page - 1
        else
            local choice = tonumber(input)
            if choice and choice >= 1 and choice <= #bee_list then
                target_bee = bee_list[choice]
                print("Вы выбрали: " .. target_bee)
                main()
                return
            end
        end
    end

end

displayMenu()

Словарь пчел:

Спойлер
local bee_tree = {
    ["Common"] = { ["Forest"] = true, ["Meadows"] = true },
    ["Cultivated"] = { ["Common"] = true, ["Meadows"] = true },
    ["Noble"] = { ["Common"] = true, ["Cultivated"] = true },
    ["Majestic"] = { ["Noble"] = true, ["Cultivated"] = true },
    ["Imperial"] = { ["Majestic"] = true, ["Noble"] = true },
    ["Diligent"] = { ["Common"] = true, ["Cultivated"] = true },
    ["Unweary"] = { ["Diligent"] = true, ["Cultivated"] = true },
    ["Industrious"] = { ["Unweary"] = true, ["Diligent"] = true },
    ["Steadfast"] = { ["Forest"] = true, ["Common"] = true },
    ["Stalwart"] = { ["Steadfast"] = true, ["Cultivated"] = true },
    ["Valiant"] = { ["Stalwart"] = true, ["Diligent"] = true },
    ["Tropical"] = { ["Forest"] = true, ["Common"] = true },
    ["Exotic"] = { ["Tropical"] = true, ["Eldritch"] = true },
    ["Monastic"] = { ["Cultivated"] = true, ["Common"] = true },
    ["Secluded"] = { ["Monastic"] = true, ["Forest"] = true },
    ["Hermit"] = { ["Secluded"] = true, ["Monastic"] = true },
    ["Austere"] = { ["Hermit"] = true, ["Secluded"] = true },
    ["Frugal"] = { ["Austere"] = true, ["Hermit"] = true },
    ["Miserly"] = { ["Frugal"] = true, ["Austere"] = true },
    ["Sinister"] = { ["Common"] = true, ["Forest"] = true },
    ["Fiendish"] = { ["Sinister"] = true, ["Cultivated"] = true },
    ["Demonic"] = { ["Fiendish"] = true, ["Sinister"] = true },
    ["Attuned"] = { ["Sinister"] = true, ["Demonic"] = true },
    ["Infernal"] = { ["Attuned"] = true, ["Demonic"] = true },
    ["Ender"] = { ["Exotic"] = true, ["Esoteric"] = true },
    ["Eldritch"] = { ["Monastic"] = true, ["Sinister"] = true },
    ["Spectral"] = { ["Ethereal"] = true, ["Ender"] = true },
    ["Invisible"] = { ["Spectral"] = true, ["Ethereal"] = true },
    ["Spatial"] = { ["Invisible"] = true, ["Spectral"] = true },
    ["Abominable"] = { ["Infernal"] = true, ["Demonic"] = true },
    ["Ghastly"] = { ["Abominable"] = true, ["Spooky"] = true },
    ["Spooky"] = { ["Ghastly"] = true, ["Sinister"] = true },
    ["Skulking"] = { ["Spooky"] = true, ["Infernal"] = true },
    ["Draconic"] = { ["Eldritch"] = true, ["Dragon"] = true },
    ["Dragon"] = { ["Eldritch"] = true, ["Tropical"] = true },
    ["Wyvern"] = { ["Dragon"] = true, ["Draconic"] = true },
    ["Enchanted"] = { ["Arcane"] = true, ["Eldritch"] = true },
    ["Witching"] = { ["Arcane"] = true, ["Esoteric"] = true },
    ["Sorcerous"] = { ["Witching"] = true, ["Arcane"] = true },
    ["Transmuting"] = { ["Sorcerous"] = true, ["Witching"] = true },
    ["Mystical"] = { ["Cultivated"] = true, ["Common"] = true },
    ["Arcane"] = { ["Mystical"] = true, ["Unusual"] = true },
    ["Ethereal"] = { ["Arcane"] = true, ["Mystical"] = true },
    ["Esoteric"] = { ["Ethereal"] = true, ["Arcane"] = true },
    ["Unusual"] = { ["Cultivated"] = true, ["Common"] = true },
    ["Wheaten"] = { ["Common"] = true, ["Cultivated"] = true },
    ["Farmed"] = { ["Wheaten"] = true, ["Diligent"] = true },
    ["Miry"] = { ["Water"] = true, ["Tropical"] = true },
    ["Boggy"] = { ["Miry"] = true, ["Tropical"] = true },
    ["Marshy"] = { ["Boggy"] = true, ["Miry"] = true },
    ["Water"] = { ["Marshy"] = true, ["Tropical"] = true },
    ["Ocean"] = { ["Water"] = true, ["Cultivated"] = true },
    ["Wet"] = { ["Water"] = true, ["Common"] = true },
    ["Soggy"] = { ["Wet"] = true, ["Boggy"] = true },
    ["Dank"] = { ["Soggy"] = true, ["Wet"] = true },
    ["Rocky"] = { ["Common"] = true, ["Forest"] = true },
    ["Stony"] = { ["Rocky"] = true, ["Common"] = true },
    ["Pupae"] = { ["Cultivated"] = true, ["Common"] = true },
    ["Larvae"] = { ["Pupae"] = true, ["Common"] = true },
    ["Pupa"] = { ["Larvae"] = true, ["Pupae"] = true },
    ["Silky"] = { ["Pupa"] = true, ["Cultivated"] = true },
    ["Stringy"] = { ["Silky"] = true, ["Pupa"] = true },
    ["Woven"] = { ["Stringy"] = true, ["Silky"] = true },
    ["Furry"] = { ["Woven"] = true, ["Stringy"] = true },
    ["Fluffy"] = { ["Furry"] = true, ["Woven"] = true },
    ["Plush"] = { ["Fluffy"] = true, ["Furry"] = true },
    ["Hirsute"] = { ["Plush"] = true, ["Fluffy"] = true },
    ["Feathery"] = { ["Hirsute"] = true, ["Plush"] = true },
    ["Shaggy"] = { ["Feathery"] = true, ["Hirsute"] = true },
    ["Rugged"] = { ["Shaggy"] = true, ["Feathery"] = true },
    ["Jagged"] = { ["Rugged"] = true, ["Shaggy"] = true },
    ["Fierce"] = { ["Jagged"] = true, ["Rugged"] = true },
    ["Savage"] = { ["Fierce"] = true, ["Jagged"] = true },
    ["Ferocious"] = { ["Savage"] = true, ["Fierce"] = true },
    ["Wild"] = { ["Ferocious"] = true, ["Savage"] = true },
    ["Untamed"] = { ["Wild"] = true, ["Ferocious"] = true },
    ["Barbaric"] = { ["Untamed"] = true, ["Wild"] = true },
    ["Primitive"] = { ["Barbaric"] = true, ["Untamed"] = true },
    ["Primeval"] = { ["Primitive"] = true, ["Barbaric"] = true },
    ["Ancient"] = { ["Primeval"] = true, ["Primitive"] = true },
    ["Primal"] = { ["Ancient"] = true, ["Primeval"] = true },
    ["Mythic"] = { ["Primal"] = true, ["Ancient"] = true },
    ["Legendary"] = { ["Mythic"] = true, ["Primal"] = true },
    ["Fabled"] = { ["Legendary"] = true, ["Mythic"] = true },
    ["Mythical"] = { ["Fabled"] = true, ["Legendary"] = true },
    ["Fable"] = { ["Mythical"] = true, ["Fabled"] = true },
    ["Story"] = { ["Fable"] = true, ["Mythical"] = true },
    ["Tale"] = { ["Story"] = true, ["Fable"] = true},
    ["Saga"] = { ["Tale"] = true, ["Story"] = true },
    ["Epic"] = { ["Saga"] = true, ["Tale"] = true },
    ["Heroic"] = { ["Epic"] = true, ["Saga"] = true },
    ["Legend"] = { ["Heroic"] = true, ["Epic"] = true },
    ["Chronicle"] = { ["Legend"] = true, ["Heroic"] = true },
    ["Annals"] = { ["Chronicle"] = true, ["Legend"] = true },
    ["Records"] = { ["Annals"] = true, ["Chronicle"] = true },
    ["Archives"] = { ["Records"] = true, ["Annals"] = true },
    ["Library"] = { ["Archives"] = true, ["Records"] = true },
    ["Collection"] = { ["Library"] = true, ["Archives"] = true },
    ["Hoard"] = { ["Collection"] = true, ["Library"] = true },
    ["Treasure"] = { ["Hoard"] = true, ["Collection"] = true },
    ["Riches"] = { ["Treasure"] = true, ["Hoard"] = true },
    ["Fortune"] = { ["Riches"] = true, ["Treasure"] = true },
    ["Wealth"] = { ["Fortune"] = true, ["Riches"] = true },
    ["Prosperity"] = { ["Wealth"] = true, ["Fortune"] = true },
    ["Abundance"] = { ["Prosperity"] = true, ["Wealth"] = true },
    ["Plenty"] = { ["Abundance"] = true, ["Prosperity"] = true },
    ["Bounty"] = { ["Plenty"] = true, ["Abundance"] = true },
    ["Gift"] = { ["Bounty"] = true, ["Plenty"] = true },
    ["Present"] = { ["Gift"] = true, ["Bounty"] = true },
    ["Prize"] = { ["Present"] = true, ["Gift"] = true },
    ["Award"] = { ["Prize"] = true, ["Present"] = true },
    ["Medal"] = { ["Award"] = true, ["Prize"] = true },
    ["Badge"] = { ["Shield"] = true, ["Crest"] = true },
    ["Emblem"] = { ["Badge"] = true, ["Shield"] = true },
    ["Symbol"] = { ["Emblem"] = true, ["Badge"] = true },
    ["Sign"] = { ["Symbol"] = true, ["Emblem"] = true },
    ["Mark"] = { ["Sign"] = true, ["Symbol"] = true },
    ["Seal"] = { ["Mark"] = true, ["Sign"] = true },
    ["Stamp"] = { ["Seal"] = true, ["Mark"] = true },
    ["Print"] = { ["Stamp"] = true, ["Seal"] = true },
    ["Imprint"] = { ["Print"] = true, ["Stamp"] = true },
    ["Insignia"] = { ["Imprint"] = true, ["Print"] = true },
    ["Crest"] = { ["Insignia"] = true, ["Imprint"] = true },
    ["Shield"] = { ["Crest"] = true, ["Insignia"] = true },
}

return bee_tree

Для начала нужно создать файл "bees.lua" и в него вставить словарь пчел (второй код). После используем Ctrl + S для сохранения и Ctrl + W для выхода из редактора кода. Обязательно писать именно с .lua.

edit bees.lua

После чего создаем файл с любым названием (в моем случае - main) и вставляем код главной программы. Тут не обязательно дописывать .lua.

edit main

Теперь запускаем программу (просто в консоли пишем main) и идем дальше.

3.Управление программой

Спойлер

После запуска программы, на мониторе выведется первые 48 пчел. Если написать "n", отобразятся следующие 48 пчел, если "p", прошлые 48. Чтоб выбрать пчелу для выведения, нужно написать номер целевой пчелы.

Программа начнет рекурсивно искать нужную пару пчел, пока не найдет кратчайший путь выведения. Например, у сундуке есть знатная, развитая и обычная пчела, а нам нужна имперская. Сначала программа ищет комбинацию из знатной и величавой пчелы. Знатная найдена, величавая нет. Теперь программа работает над выводом величавой программы и так же ищет нужную пару. Таким образом программа будет искать, пока не найдет любую пару для выведения. Таким образом, если программа дойдет до самой первой комбинации и не найдет для нее пару, будет ошибка. 

image.thumb.png.b573e4734e2da36ef9d52b2d866a5051.png

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

image.png.e44ba5270e4e5fa7950d26d981b3f12f.png

Небольшой недочет схемы в том, что она может работать только с одной пасекой одновременно.

Главный недочет программы - словарь пчел написан полностью на английском, но у большинства игроков интерфейс русский. Чтоб программа работала, нужно или держать интерфейс на английском или переписать словарь на русские названия пчел. Возможно, когда-нибудь я перепишу словарь на русский, но не сегодня)

Если вы все сделаете правильно, у вас будет самый простой способ вывода имперской пчелы (проще - только купить). Надеюсь, мои мучения вам помогут, пишите ваши вопросы и предложения в комментариях, постараюсь ответить как можно скорее! 

  • Like 1
Link to comment
Share on other sites

  • 5 months later...

нужно проверить будет ли русификатор подхватывать программное название пчёл и автоматом переводить их на нужный язык

пример как видит мод пчёлы 
for.bees.species.austere=Суровая
for.bees.species.avenging=Мстящая
for.bees.species.boggy=Болотистая
for.bees.species.common=Обычная
for.bees.species.cultivated=Развитая
for.bees.species.darkened=Тёмная
for.bees.species.demonic=Одержимая
for.bees.species.diligent=Прилежная
for.bees.species.edenic=Райская
for.bees.species.ended=Драконья
for.bees.species.exotic=Редкая
for.bees.species.fiendish=Жестокая
 

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...