eu_tomat
Модераторы-
Публикации
2 666 -
Зарегистрирован
-
Посещение
-
Победитель дней
331
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя eu_tomat
-
А в чём текущая проблема? Схема расставляется недостаточно правильно или недостаточно быстро?
-
Ваджра из Gravitation Suite? Робот с её помощью вроде бы рубит руду за три тика независимо от чар эффективности. Установка руды выполняется за восемь тиков. Всего требуется 11 тиков на полный цикл переработки руды. Получается, что скорость переработки руды в 20 блок/сек достигается с помощью 11 роботов. Кстати, а сколько роботов задействовал "афигенный програмист"? Для достижения скорости переработки 20 блок/сек при использовании иридиевого бура потребуется 13 роботов. Конечно же, без учёта времени презарядки инструмента. Я провёл эксперимент: В слот инструмента робота поместил полностью заряженный иридиевый бур. Над роботом установил сундук и поместил в него 48 стаков алмазной руды (3072 блока). Под роботом установил пустой алмазный сундук на 108 слотов. Слева от робота установил зарядное устройство. Запустил простой скрипт: robot.select(1) while robot.suckUp() do for i=1,64 do robot.place() robot.swing() end for slot=4,1,-1 do robot.select(slot) robot.dropDown() end end За 36 минут робот переработал все 48 стаков алмазной руды из верхнего сундука и поместил полученные алмазы в нижний сундук. Свободными оказались два последних его слота. Остаток заряда в буре: 54.2 из 300 kEU. Как можно ускорить этот процесс? Использование ваджры позволит сэкономить 5 минут на ускорении рубки, и, возможно несколько секунд на перезарядке инструмента, что не очень много на фоне 36 минут. Можно оптимизировать алгоритм очистки инвентаря робота, что позволит выиграть около 20 секунд, что тоже немного. Масштабировать схему на несколько роботов. В этом случае скорость возрастёт кратно. Возникает вопрос, как именно предполагается масштабировать переработку. Схема переработки руды будет зависеть в первую очередь от используемой системы хранения. Я вижу такие варианты: При наличии AE можно пополнять и освобождать сундуки МЭ-шинами или даже вообще обойтись без сундуков. Вручную раскидать руду по сундукам над роботами. При использовании системы хранения на сундуках и транспозерах главная сложность будет заключаться уже не в переработке руды, а в логистике. Но в условиях задачи про систему хранения ничего не сказано. А здесь вообще что-то непонятное: Что такое сервомеханизмы и поисковики?
-
Насколько очень? Какие имеются ресурсы для построения схемы? Сколько роботов допустимо задействовать в этой схеме? Насколько дорог инструмент для рубки руды в сравнении с роботами? Какова доступная для реализации схемы площадь или объём? Схема перерубки руды на двух роботах имеет смысл лишь в случаях использования очень дорогих или редких кирок. В противном случае предложенная схема оказывается неэффективной, и появляется смысл реализовать схему на одном роботе. Или на двух, но с одинаковой программой. Или даже на сотне или тысяче одинаковых роботов, если сервер справляется с нагрузкой, и другие игроки не возражают. За какое время требуется перерабатывать такое количество руды? Также возникает вопрос, зачем копить такое количество руды, и затем стоять AFK, если руду можно перерабатывать постепенно, по мере её накопления, параллельно занимаясь другими задачами? Или даже по мере добычи руды, поставив такую схему рядом с буровой установкой.
-
А вопрос-то в чём?
-
Ради чего? Если новая тема будет посвящена очередному этапу разработки, то нет, создавать новую тему не стоит. Если же в новая тема будет содержать описание готовой программы и ссылку на рабочий код, то это имеет смысл. Предлагаю пока что продолжить обсуждение в этой теме. А новую тему создать, когда уже появится что-то пригодное к использованию.
-
Теперь я предлагаю разобрать таблицу inventories и код, работающий с ней. Сейчас эта таблица строится при запуске программы таким образом: local function initInventories() for i = 0, 5, 1 do local name = transposer.getInventoryName(i) local size = transposer.getInventorySize(i) if name then table.insert(inventories, newInventory(i, name, size)) end end end Здесь я бы предпочёл избавился от вызова функции newInventory. Хотя быстродействие этого участка кода и не критично, но оно немного увеличится. А главное, упростится обслуживание кода спустя месяц-другой: не потребуется искать функцию newInventory, чтобы вспомнить детали её работы. Необходимые детали окажутся в месте непосредственного их использования: table.insert(inventories, { side = side, name = name, size = size, stacks = {} }) Есть и не столь очевидная оптимизация. Бегло изучив код, я предполагаю, что более эффективно себя покажет другой формат таблицы. И строить её следует так: local function initInventories() for side = 0, 5 do local name = transposer.getInventoryName(side) if name then inventories[side] = { name = name, size = transposer.getInventorySize(side), stacks = {} }) end end end Быстродействие этого участка кода увеличивается незначительно, но для сохранения работоспособности программы вслед за ним потребуется переписать и другие участки, новые варианты которых могут исполняться как более, так и менее эффективно. Для оценки общего изменения эффективности требуется более подробный анализ. В дальнейшем таблица inventories используется в следующих функциях: В функции drawInfo текущий код for i = 1, #inventories do local inventory = inventories[i] gpu.set(1, i + 9, inventory.side .. " : " .. inventory.size .. " : " .. inventory.name) end будет немного усложнён и замедлен: local i = 0 for side = 0, 5 do if inventories[side] then i = i+1 gpu.set(1, i + 9, side .. " : " .. inventories[side].size .. " : " .. inventories[side].name) end end Но содержащая его функция drawInfo вызывается один раз при запуске программы, а также используется в функции drawAdditional, которая вызывается лишь во время редактирования фильтров пользователем, что должно происходить редко. В функции getStacks текущий код for i = 1, #inventories do local inventory = inventories[i] inventory.stacks = transposer.getAllStacks(inventory.side) end также будет усложнён и замедлен: for side = 0, 5 do if inventories[side] then inventories[i].stacks = transposer.getAllStacks(inventory.side) end end Вызывается эта функция один раз при запуске программы, и далее каждый раз в главном цикле программы, то есть часто. Это уже неприятно и заставляет сомневаться в правильности смены формата таблицы inventories. В функции getInventoryBySide текущий код for i = 1, #inventories, 1 do local inventory = inventories[i] if inventory.side == side then return inventory end end будет сильно упрощён и ускорен: return inventory[side] Благодаря этому от вызова функции getInventoryBySide можно будет полностью отказаться. Количество вызовов функции getInventoryBySide в основном цикле равно удвоенному количеству фильтров. Даже если фильтр всего один, такая оптимизация уже позволит снизить общую нагрузку, создаваемую программой. По совокупному снижению нагрузки я считаю данную оптимизацию полезной. Также, если есть желание максимально повысить быстродействие программы, пожертвовав потреблением памяти, можно сформировать сразу две таблицы. Одну с номерами рабочих сторон транспозера для упрощения их перечисления, где это требуется, и вторую таблицу с ассоциативным доступом к нужной стороне транспозера без необходимости использовать перечисление.
-
Конкретно на этом участке быстродействие кода не критично, а поле для оптимизаций в программе пока ещё не исчерпано. Но пусть будет. Это зависит от того, что именно для нас хорошо. С точки зрения быстродействия лучше вообще не создавать и не вызывать функции. И локальные переменные внутри часто вызываемых функций тоже лучше не создавать. Но читать и дорабатывать такой код будет не просто. Хороший код всегда является результатом компромисса между быстродействием, потреблением памяти и простотой обслуживания кода. Баланс определяется условиями задачи. Поэтому говорить о качестве кода в отрыве от условий задачи бессмысленно. Да, смысл есть, это полезный приём, позволяющий упростить код. А долго ли... Зависит от выбора единицы измерения, из которых наиболее адекватной в большинстве случаев является процент времени, затрачиваемый на выполнение участка кода по отношению к содержащей его функции – либо непосредственно функции, содержащей этот код, либо вызывающими её функциями вплоть до всей программы целиком. Скорее всего, нет. Это надо проверять в каждом конкретном случае. В общем же это выглядит так: Обращение к локальным переменным требует меньше времени, чем к глобальным переменным или же полям таблицы. Поэтому локальные переменные позволяют увеличить быстродействие в большинстве случаев. Но локальные переменные требуют времени на их создание и уборку мусора. И если функция, содержащая локальную переменную, вызывается слишком часто, то эти накладные расходы могут превысить затраты на обращение к глобальной переменной или полю таблицы.
-
Сложно определить блок за одно сканирование. Несколько проходов сканирований смогут обеспечить лучший результат, но придётся потратить время – большее или меньшее в зависимости от выбранного алгоритма подавления шума. Функция analyze() выдаёт характеристики блоков, смежных роботу. Она не предназначена для сканирования на расстоянии.
-
Начну, с loadProperities, функции чтения конфигурации. В ней несколько раз встречаются строки вида string.byte(bytes, ...) и string.sub(bytes, ...). Я предлагаю использовать синтаксический сахар, предоставляемый Lua для более компактной записи: bytes:byte(...) и bytes:sub(...). На поведении программы это не отразится, но код станет светлее, что благоприятно скажется на его чтении. Там же встречается такая строчка: (enabled == 1 or true and false). В использованном контексте брать это выражение в скобки не обязательно, а с точки зрения замусоривания кода лишними символами – вредно. А кроме того, результатом выполнения выражения enabled == 1 уже является true или false, поэтому вся эта длинная запись приводит ещё и к бесполезному дублированию вычислений. С тем же успехом для булевой переменной var можно было бы написать длинное if var then return true else return false end вместо лаконичного return var Такой подход приводит к раздуванию кода на пустом месте. Поэтому, учитывая сказанное выше, строчку сокращаем до enabled == 1. Зато в функции saveProperities эта конструкция облегчит код: local enbd = 0 if filter.enabled then enbd = 1 end до local enbd = filter.enabled and 1 or 0 Да и к слову, зачем нужна переменная enbd, если её значение используется лишь один раз, и можно было сразу писать такой код: local enabled = string.char(filter.enabled and 1 or 0) local input_side = string.char(filter.input_side) ... Также я бы предпочёл избавиться от длинной последовательности string.char, осветлив код, заодно уменьшив количество вызовов функции char и количество переменных, заменив этот код local enabled = string.char(enbd) local input_side = string.char(filter.input_side) local output_side = string.char(filter.output_side) local input_slot = string.char(filter.input_slot) local output_slot = string.char(filter.output_slot) local name_length = string.char(#filter.name) local name = filter.name local metadata = string.char(filter.metadata) local count = string.char(filter.count) bytes = bytes .. enabled .. input_side .. output_side .. input_slot .. output_slot .. name_length .. name .. metadata .. count на более короткий и эффективный вариант: bytes = bytes .. string.char( enbd, filter.input_side, filter.output_side, filter.input_slot, filter.output_slot, #filter.name ) .. filter.name .. string.char( filter.metadata, filter.count) Такой код не только требует меньше действий, но и выглядит понятнее, на мой вкус. Есть ещё пара строк в этой функции, за которые цепляется глаз: for i = 1, #filters, 1 do local filter = filters[i] Их хочется заменить одной строкой: for i, filter in ipairs(filters) do Такой код легче читается. Быстродействие этого участка кода, скорее всего ухудшится, что вряд ли сыграет какую-либо роль конкретно в этом месте. Вот примерно так можно улучшить функции чтения и записи конфигурации. Для дальнейшего улучшения можно было бы сменить формат файла, но это улучшение будет относительным. Сейчас выбран двоичный формат хранения данных. Его преимущество в компактности хранения. Зато некомпактен код работы с файлом конфигурации. В данной программе я бы предпочёл хранить конфигурацию в виде сериализованной таблицы. Это сильно упростит код загрузки и сохранения конфигурации, позволяя не думать о деталях. Заодно файл можно будет просматривать и редактировать простыми текстовыми редакторами, что может оказаться даже более удобным, нежели редактор, встроенный в программу. Сам файл конфигурации, правда, увеличится в размерах. Но вряд ли его размер будет играть существенную роль. Предлагаю рассмотреть этот вариант, хотя и совершенно не настаиваю на нём. А если вообще отказаться от встроенного редактора, то я бы предпочёл загрузку конфигурации в виде Lua-кода. Примеры кода сейчас не предлагаю, потому как не уверен в их востребованности в этой теме.
-
Очень хорошо. Новый вариант на порядок интереснее первого. Он даёт больше шансов на то, что кто-то захочет использовать эту программу или ознакомиться с её кодом. Об этом лучше сказать в описании, причём где-то в самом его начале. Заголовок или название программы очень коротко сообщают о назначении программы. Суть же программы желательно раскрыть первыми двумя предложениями. А дальше можно переходить к деталям реализации. Да, обсуждение алгоритмов и кода является хорошим способом развития навыка программирования.
-
У меня двойственное чувство при чтении этой темы. Если я верно понял задумку автора, эта программа имеет гораздо больший потенциал, нежели простая сортировка. С тем же успехом программа может выполнять роль производственного конвейера. Скорее всего, она позволит выполнить полный цикл переработки руд в IC2, повесив на один транспозер измельчитель, рудопромывку, печку и центрифугу. С другой стороны, слишком короткое и смутное описание долго отталкивало меня от чтения кода. Но мне интересны подобные штуки на транспозерах, да и автор ждал критики: Я могу покритиковать, но сразу предупреждаю, что критика будет долгой и поэтапной. Потому что, на мой взгляд, этот код должен быть переписан процентов на 70. Если тебя интересует доработка кода, то предлагаю начать с описания, после чего можно будет приступить к алгоритму, а затем и коду. Предлагаю сразу прояснить следующие моменты: Что значит "сортировка"? Как она осуществляется? Эта сортировка позволяет красиво разложить предметы внутри инвентарей для удобства визуального восприятия игроком, или же позволяет определённым предметам оказаться в нужном инвентаре? Или и то и другое одновременно? В описании об этом не сказано ни слова. В этом месте описания внезапно появляются какие-то поля каких-то фильтров. Что это за фильтры? На что они влияют? Каково назначение полей? Предположим, выбран первый подходящий слот. Подходящий какому условию? На что влияет выбор слота? Откуда будут извлечены предметы? Куда? В какой инвентарь? В какой слот? Из описания это не ясно. Что такое целевой инвентарь? Что такое целевой слот? Каким образом они заданы? Что значит "плохо работает"? Это как? А как работает хорошо, если слот указан? Чем определяется плохость или хорошесть работы? В общем, для начала требуется прояснить, в чём заключается сортировка этой программой, и по каким правилам. Также в описании желательно привести какой-то пример правил сортировки, решающих какую-то несложную задачу вроде переплавки руды в печке. Если, конечно, это не мои фантазии о возможностях программы. Тогда и до критики кода дойдём. Другим форумчанам я предлагаю поучаствовать в критике критика и быть начеку, потому как предлагая свои правки, я зачастую жертвую читаемостью кода. Это для новичков нежелательно, про что я часто забываю.
-
Это для меня не очевидно. Если не видел ты, это не значит, что сорняков вообще нет. Я помню AgriCraft на 1.7.10, там и сорняки были, и культуры не переползали на жёрдочки. Видимо, на 1.12.2 другая механика. Вообще-то форум посвящён программированию, а чтобы читатели смогли оценить алгоритм, им требуется понимать соответствующую механику. И если программирование на Lua завсегдатаям форума в целом понятно, то детали механик модов требуется пояснять отдельно. Гайд по моду писать не требуется, но логика работы программы нуждается в описании. Не таком описании как "робот поворачивает направо, тыкает по жёрдочке и поворачивается к сундуку", а что-нибудь похожее на такое: Эта программа позволяет получить семена AgriCraft с максимальными параметрами. Я применил следующее решение: Робот берёт из сундука с материалами исходное семя, лопатку и два стака жёрдочек. Затем устанавливает одиночные жёрдочки на три грядки, на последнюю высаживает семя и возвращается к первой грядке, ожидая на ней урожая. Рано или поздно растение на последней жёрдочке вырастет и заселит среднюю жёрдочку, а затем и первую. Тем временем робот непрерывно пытается собрать урожай с первой грядки. Успешный сбор урожая сигнализирует о полном заселении грядок изначальной культурой. Получив урожай, робот уничтожает растение на средней грядке, сбрасывает полученную с грядки продукцию в сундук для продукции и устанавливает на освободившуюся грядку двойные жёрдочки для скрещивания. Далее робот непрерывно пытается лопаткой забрать растение со средней грядки. Успешный сбор сигнализирует об успешном скрещивании. Получив новое растение на лопатке, робот очищает все грядки, сбрасывает продукцию в сундук и возвращается на исходную позицию. Робот повторяет перечисленные выше действия, но теперь высаживая не семена, а растение с лопатки. Всего выполняется 25 скрещиваний. В большинстве случаев этого достаточно для получения семян с максимальными характеристиками 10/10/10. Примерное время работы составляет 15 минут при наличии 8 ускорителей роста из мода Mystical Agriculture под каждой грядкой. Без ускорителей весь процесс занимает 5 часов (указать нужное время). Завершив последнее скрещивание, робот высаживает растение с лопатки на жёрдочки, собирает с него семена и сбрасывает содержимое своего инвентаря в сундук с продукцией. Для успешной работы программы робот должен смотреть на сундук с материалами, а в сундуке должно лежать одно (не больше!) семя, лопатка и два стака жёрдочек точно в указанной последовательности. Проверено на версиях модов AgriCraft-2.12.0-1.12.0-a6.jar и OpenComputers-MC1.12.2-1.7.5.192.jar (указать правильные версии). Вот что-то примерно такое я ожидаю видеть в описании. Из этого описания читатели поймут, нужна ли им такая программа, и что от неё ожидать. Также это поможет читателям разобраться в назначении отдельных участков кода и предложить лучшие решения этой задачи. А ещё по картинке не понятно, на какой из сундуков должен смотреть робот в исходной позиции. Судя по коду, скриншот запечатлел конечную позицию робота. Или робот там ожидает успешного скрещивания. Попробуй угадай, куда ставить робота. Почитав код, предполагаю, что робот должен смотреть на правый сундук, левым боком касаясь зарядника. @imitator Поправь меня, если где-то я ошибся или был не точен. И будем считать этот пост описанием твоей программы.
-
@imitator Ага, немного проясняется механика AgriCraft. Но пока не всё для меня очевидно. И, думаю, тут на форуме многим требуется пояснение механики мода, чтобы оценить логику работы этого алгоритма. А в каком слоте было пусто? Или имеется в виду пустой совок? На старте используется только одна семечка? Растение в AgriCraft само расползается по жёрдочкам? Сорняки, насколько я помню, присутствуют в AgriCraft. На том сервере сорняки отключены, или просто за 15 минут они обычно не успевают появиться? При скрещивании культур в AgriCraft их параметры могут ухудшиться? Или скрещивание всегда даёт параметры не хуже исходных?
-
Обычное дело на серверах. Робот может по разным причинам отказаться от выполнения команд. Но, к счастью, большинство команд робота возвращают в программу статус их исполнения. Проверка статуса поможет роботу сохранить работоспособность, если что-то пойдёт не по плану. Как-то всё очень легко получается в AgriCraft. Жёрдочки из IC2 посложнее будут. Там сложнее добраться до максимальных характеристик, столь примитивный алгоритм там не прокатит. А кроме того в IC2 максимальные характеристики вредны, а оптимальные надо вычислять для конкретных условий выращивания. В общем, там есть, о чём подумать. А по поводу описания @hohserg верно предлагает. Желательно рассказать, что там делает робот. Что там с чем скрещивается, и в какой последовательности, какова цель скрещивания и условия достижения результата.
-
Если я верно понял код, то просто делается 25 попыток скрещиваний, результат складывается в сундук, а решение о дальнейшей селекции позже принимает игрок. Программа не имеет каких-либо проверок на корректность, все действия совершаются вслепую, поэтому работоспособность гарантируется лишь в каких-то стабильных и специфических условиях.
-
[OC] [Add-ons] Computronics! Полный обзор версии 1.5.5 [#3] (карточки)
eu_tomat прокомментировал Fingercomp запись в блоге в Fingercomp's Playground
Есть ещё одно интересное свойство карты самоуничтожения. Будучи вставленной в робота, она просто его уничтожает. А вставленная в компьютер, она кроме того взрывает окружающие блоки и наносит урон мобам. Также проверялось на 1.7.10. -
[OC] [Add-ons] Computronics! Полный обзор версии 1.5.5 [#3] (карточки)
eu_tomat прокомментировал Fingercomp запись в блоге в Fingercomp's Playground
Да, таймер тикает, пока карта самоуничтожения вставлена в компьютер, и сбрасывается при его включении. -
Вот именно. На скриншоте почему-то нет символа "c" в слове "drc". А должен быть. И с какой целью скриншот так замылен? Отдельные буквы угадываются с трудом.
- 52 ответа
-
- drone
- управление
-
(и ещё 1 )
Теги:
-
А ещё wget ругается на невозможность октрыть файл в режиме записи. Скорее всего, система загружена с дискеты в режиме только для чтения. Чтобы исправить эту ошибку, требуется установить систему на жёсткий диск командой install и загрузить её с жёсткого диска.
- 52 ответа
-
- 1
-
-
- drone
- управление
-
(и ещё 1 )
Теги:
-
Расскажи, как воспроизвести проблему: Какая версия Minecraft и OpenComputers? По какой ссылке скачана программа 3dprint? По какой ссылке скачана модель для печати?
-
Постоянное возвращение в операционную систему
eu_tomat ответил в вопрос Bogdikon в Помогите найти ошибку
В коде ещё одна ошибка: Этот цикл выполнит одну итерацию. Бесконечный цикл реализуется через until false или while true do. -
Постоянное возвращение в операционную систему
eu_tomat ответил в вопрос Bogdikon в Помогите найти ошибку
А что написал вместо return, и что именно сейчас не работает? -
@serafim Нормально. Теперь уже получился полноценный чат. Но почему-то, отправка сообщений закомментирована в коде.
-
Не надо дополнительную версию. Предлагая эту идею, я надеялся, что у нас схожее представление об удобстве. Мне нравятся простые в настройке изолированные системы с минимальным влиянием друг на друга. Для тебя же является нормой тесное соседство различных систем. Пусть так и остаётся. Согласен, чем-то приходится жертвовать. Код, написанный для EEPROM, пробуждает во мне оптимизатора. Но да, выигрыш там не существенен. Кстати, стек стеком, но переменная в Lua не удаляется сразу после её использования. Она удалится по завершении контекста, в котором была создана. Про сборщик мусора пока не говорим, промежуточные значения в любом случае где-то хранятся и как-то со временем удаляются.
- 7 ответов
-
- wireless
- opencomputers
-
(и ещё 1 )
Теги:
