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

Доработка программы для переработки руды

Рекомендуемые сообщения

32 минуты назад, serafim сказал:

Синхронизировать двух роботов на одну задачу оказалось не так просто как думалось, перепробовал пол сотни вариантов пока получилось хоть что-то не сильно лагучее

 

Два робота совместно ставят и рубят один и тот же блок получая ускорение

А в чём заключается преимущество именно такой схемы параллельной работы? Какой смысл размещать независимых роботов так, чтобы они имели общий блок для переработки руды, если проще сделать эти блоки отдельными для каждого робота? Это позволило бы вообще не задумываться о синхронизации роботов

 

Мне было понятно, когда один робот рубил руду, а второй робот её устанавливал. Это позволяло повысить эффективность использования дорогого инструмента. Развивая эту идею, я использовал третьего и даже четвертого робота: три робота устанавливали руду в один общий блок, а четвёртый рубил руду в этом блоке.

 

Но что даёт этот трюк с общим блоком в схеме на двух независимых роботах, когда каждый из них рубит своим инструментом?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
9 минут назад, eu_tomat сказал:

А в чём заключается преимущество именно такой схемы параллельной работы?

Идея в том чтоб не заморачиваться с ПО, роботы сами будут ставить или рубить руду в зависимости от того кто раньше успеет

9 минут назад, eu_tomat сказал:

три робота устанавливали руду в один общий блок, а четвёртый рубил руду в этом блоке.

Такой способ тоже хорош и экономный в плане инструмента и зарядчика

9 минут назад, eu_tomat сказал:

что даёт этот трюк с общим блоком в схеме на двух независимых роботах, когда каждый из них рубит своим инструментом?

Тут прироста увы нет, в основном влияет только время установки блока

Изменено пользователем serafim

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@serafim Что-то я запутался.

 

36 минут назад, serafim сказал:

Идея в том чтоб не заморачиваться с ПО, роботы сами будут ставить или рубить руду в зависимости от того кто раньше успеет

Это понятно. Но если вдобавок к этому мы разместим роботов так, чтобы каждый из них рубил в своём блоке, то о синхронизации вообще не надо будет думать. Каков смысл общего блока для совместной работы двух роботов, если у каждого есть свой инструмент для рубки?

 

40 минут назад, serafim сказал:

Такой способ тоже хорош и экономный в плане инструмента и зарядчика

Какой способ хорош? Мой с тремя установщиками и одним рубщиком? Или тот, который предложил ты с двумя роботами?

 

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
22 минуты назад, eu_tomat сказал:

Каков смысл общего блока для совместной работы двух роботов, если у каждого есть свой инструмент для рубки?

это тайна покрытая мраком, а вообще надежда на рассинхрон вычислений сервера с клиентом позволяющий моментально сносить блоки

22 минуты назад, eu_tomat сказал:

Какой способ хорош? Мой с тремя установщиками и одним рубщиком?

Твой, но увы тут ПО писать особо не о чем

Изменено пользователем serafim

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@serafim Ну, ясно. Нет особого смысла направлять роботов в один блок, если речь не идёт об экономии на дорогом инструменте.

 

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

 

При таких условиях для меня это совершенно неинтересная задача с точки зрения кодинга. Но благодаря примитивности эти двух программ я считаю их хорошими примерами для оптимизации. Если я и перепишу эти две программы, то это будет в формате блога с раскрытием темы оптимизации.

 

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

 

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

 

Какой из вариантов работы над этим заказом тебе наиболее интересен?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
17 часов назад, eu_tomat сказал:

мы можем совместно работать над новым вариантом ... В этом случае мы с тобой сможем раскрыть тему оптимизации последовательно, пост за постом.

идея интересная

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, serafim сказал:

идея интересная

Начнём с установщика блоков:

Скрытый текст

local sides = require "sides"
local robot = require "robot"
local component = require "component"
local active_slot = 1
size=robot.inventorySize()
local function Text()
    os.execute("cls")
    print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame")
    print("Доработал-atomzerg")
end
 
Text()
 
 
while true do
robot.select(active_slot)
if robot.count(active_slot) == 0 then
    active_slot = active_slot + 1 end
  if robot.select(active_slot) ==size then
   active_slot = 1 end
if robot.place() == false then active_slot = active_slot + 1 end
if active_slot == size then active_slot = 1 end
robot.place()
end

 

Предварительный, грубый анализ:

  • Программа в основном расходует время на выполнение бесконечного цикла.
  • Внутри бесконечного цикла безусловно выполняются следующие операции:
  • Два раза выполняется robot.select, затрачивая 0.05 сек на вызов.
  • Один раз robot.place, затрачивая 0.4 сек на вызов
  • Один раз robot.count, на вызов тратится примерно 5E-5 сек времени.

Успешные вызовы robot.place приближают игрока к цели, нет смысла уменьшать количество этих вызовов, но есть смысл подготовить робота таким образом, чтобы каждый вызов был успешным, т.к. выполнение неудачного вызова требует 0.05 сек времени.

 

Программа проверяет успешность операции кодом:  if robot.place() == false, но из этого делается неверный вывод, будто бы закончились предметы в слоте. Это не верно. Такое условие сообщает о том, что не удалось установить блок в мир: скорее всего, есть какая-то помеха. Для проверки наличия предмета в слоте могло бы подойти условие if robot.place() == nil, но эту проверку можно гораздо быстрее осуществить с помощью robot.count(). В случае же, если не удалось установить блок, имеющийся в слоте робота, требуется просто подождать, пока освободится пространство в координатах установки.

 

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

 

Вызовы robot.select() приближают игрока к цели только в том случае, если текущий слот инвентаря опустел. И при достаточно быстром заполнении инвентаря робота блоками руды требуется не более 1/64 этой операции на одну итерации цикла. Минимизируя количество вызовов этой операции удастся сэкономить 0.05*2 - 0.05/64 секунд на одну итерации цикла. Относительно времени, затраченного на основную операцию, экономия составит 19.84%.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Для информации, чтобы читателям было понятно, что здесь происходит: @serafim выложил свои варианты программ, но пока решил притормозить, чтобы не участвовать в создании лагодромов. Его позиция понятна, темы автора заказа вызывают противоречивые чувства.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

Начнём пожалуй с самого начала, для оптимизации программы разберём предложенный код поэтапно

Скрытый текст

local sides = require "sides"
local robot = require "robot"
local component = require "component"
local active_slot = 1
size=robot.inventorySize()
local function Text()
    os.execute("cls")
    print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame")
    print("Доработал-atomzerg")
end
 
Text()
 
 
while true do
robot.select(active_slot)
if robot.count(active_slot) == 0 then
    active_slot = active_slot + 1 end
  if robot.select(active_slot) ==size then
   active_slot = 1 end
if robot.place() == false then active_slot = active_slot + 1 end
if active_slot == size then active_slot = 1 end
robot.place()
end

 

1 local sides = require "sides"

библиотека sides на 1й строке - этот интерфейс предоставляет таблицу названий, для работы со сторонами блоков

в формате:  Низ (bottom): 0 , Верх (top): 1 , Тыл (back): 2 , Перед (front): 3 , Право (right): 4 , Лево (left): 5

пример для работы с контроллером красного камня: 

1 local component = require("component")
2 local sides = require("sides")
3 local rs = component.redstone
4 rs.setOutput(sides.left,15)

здесь использован rs.setOutput(sides.left,15) на 4й строке (включить сигнал с лева, с силой сигнала 15),

без библиотеки sides пришлось бы указать сторону в формате rs.setOutput(5,15)

  • Вот только в коде эта библиотека не используется, вызывать её не требуется
3 local component = require "component"

библиотека component на 3й строке - этот интерфейс используется для доступа и взаимодействия компьютера с компонентами

тот же пример для работы с контроллером красного камня:

1 local component = require("component")
2 local rs = component.redstone

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

2 local rs = component.redstone
  • Вот только ни какие взаимодействия с компонентами в коде не происходят,  вызывать её не требуется
5 size=robot.inventorySize()

глобальная переменная size на 5й строке вызывается один раз при запуске программы

и принимает значение последнего слота в инвентаре робота,

который при одном улучшении инвентаря равен 16 ячейкам

  • желательно назначать переменные локально
5 local size = robot.inventorySize()
  • чтобы она не вносила изменения в другие программы за пределами данного кода
6 local function Text()
7    os.execute("cls")
8    print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame")
9    print("Доработал-atomzerg")
10 end
 
12 Text()
  • функция Text() вызывается только один раз на строке 12, её можно упростить
7 os.execute("cls")
8 print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame")
9 print("Доработал-atomzerg")
  • также вопрос а требуется ли она вообще, достаточно указать что за программа сейчас работает
print("работает установщик блоков")

теперь касательно основного тела программы:

16 robot.select(active_slot)
17 if robot.count(active_slot) == 0 then
18    active_slot = active_slot + 1 end
19  if robot.select(active_slot) ==size then
20   active_slot = 1 end
21 if robot.place() == false then active_slot = active_slot + 1 end
22 if active_slot == size then active_slot = 1 end
23 robot.place()
  • текущий алгоритм работы:

строка 16  выбирается активный слот инвентаря робота из переменной active_slot , при первом запуске она равна 1

строка 17  проверяется значение слота (в данном случае 1) и если он пустой то

строка 18  к глобальной переменной active_slot плюсуется 1

строка 19  если выбран последний слот инвентаря робота то

строка 20  переменная active_slot меняет значение на 1

строка 21  если робот не смог поставить блок то к активному слоту плюсуется 1

строка 22  если переменная active_slot равна последнему слоту робота то переменная active_slot меняет значение на 1

строка 23  робот ставит блок без проверок успешно или нет

  • Вывод: в текущем алгоритме творится каша

использован не оптимальный метод выбора заполненного слота назначая переменную active_slot

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

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

поставил его раньше, в итоге будет постоянно перебирается инвентарь тратя время в пустую

 

отдельно хотелось бы обратить внимание на форматирование кода, читать его затруднительно

общепринято использовать для lua два пробела, да это не обязательно но сильно улучшает восприятия написанного кода

второе - это как написаны логические элементы, тут не выделены начало и конец а также выполняемые условия

каждое условие проверяется отдельно, хотя логичное было бы остановится на том которое соответствует требованию

 

вот так должен был выглядеть код при соблюдении общепринятых норм

while true do
  robot.select(active_slot)
  if robot.count(active_slot) == 0 then
    active_slot = active_slot + 1 
  elseif robot.select(active_slot) == size then
    active_slot = 1 
  elseif robot.place() == false then 
    active_slot = active_slot + 1 
  elseif active_slot == size then 
    active_slot = 1 
  end
  robot.place()
end
  • Использовать кучу условий и метод счётчика для выбора заполненного слота в инвентаре робота не эффективно

правильнее применить цикл перебора инвентаря пропуская пустые слоты

и при нахождении полного слота выбрать его, остановив дальнейший перебор

for slot = 1, inv do
  if r.count(slot) > 0 then 
    r.select(slot)
    break
  end
end

вместо кучи условий с переменной active_slot можно использовать только одно условие, (если выбранный слот пуст)

if r.count() == 0 then

также если инвентарь робота пустой, то не логично перебирать его до посинения,

правильнее остановить поиск, пока в инвентаре не появится новые блоки,

и при добавлении новых блоков, сразу его выбрать

if slot == inv then
  local e, slot = event.pull("inventory_changed")   
  r.select(slot)
end

проверять поставил ли робот блок нет необходимости

if robot.place() == false then 

особенно если использованы несколько установщиков блоков, программа будет простаивать

r.place()

Собственно готовый код занимает всего 21 строку, осталось его только собрать до кучи

 

Но я этого делать не буду, и вот почему:

Эта программа при лагающем сервере вызывает рассинхрон при быстрой смене блока,

устанавливая и разрушая его сервер выдаёт финты типа моментального разрушения или дюпа

 

Подобные действия не способствуют популезации мода OpenComputers

Рекомендую проголосовать за удалении этой темы как потенциально нежелательной

Изменено пользователем serafim

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, serafim сказал:

Рекомендую проголосовать за удалении этой темы как потенциально нежелательной

Рекомендую заархивировать ее как пример потенциально нежелательной

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@serafim Хороший анализ плохого кода, я согласен почти с каждым утверждением. Но в удалении этой темы я не вижу смысла. В ней разобраны альтернативные варианты решения поставленной задачи, более экономно расходующие ресурсы сервера.

 

Обсуждение проблемы лагодромов я считаю полезным. Большинство игроков создаёт лагодромы ненамеренно, т.к. попросту не знает, как писать программы правильно, как минимизировать нагрузку на сервер. Таким игрокам будет полезна информация о том, как решить задачу правильно. А тот, кто вредит серверу целенаправленно, готов использовать для этого любые другие моды, а не только OC. И останавливает такого игрока только одно средство — бан.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
14 минуты назад, eu_tomat сказал:

Под этим предлогом можно было бы удалить многие темы нашего форума

может и так, тогда предлагаю отправить данную тему в корзину

там можно будет её смотреть, но нельзя редактировать

либо добавить на сайт новую ветку лагодромы рядом с корзиной, закрытую от редакции

Изменено пользователем serafim

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 14.12.2020 в 16:31, serafim сказал:

также если инвентарь робота пустой, то не логично перебирать его до посинения,

правильнее остановить поиск, пока в инвентаре не появится новые блоки,

и при добавлении новых блоков, сразу его выбрать


if slot == inv then
  local e, slot = event.pull("inventory_changed")   
  r.select(slot)
end

 

Тут ещё не помешает проверка на наличие предмета в слоте, т.к. по завершении обработки 64 блоков руды очередь гарантированно забьётся событиями извлечения предмета из слота, из-за чего с большим шансом слоты, на которые указали сигналы, могут оказаться пустыми.

 

Кстати, очень странно, что событие inventory_changed вообще генерируется при установке блока. Причём, аж 4 раза . Не должно быть ни того, ни другого. Оно должно вызваться один раз при исчерпании стака, как при выбрасывании предметов по одной штуке. Проверялось для OpenComputers-MC1.7.10-1.7.5.1290-universal.jar.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, eu_tomat сказал:

очень странно, что событие inventory_changed вообще генерируется при установке блока.

Событие "key_down" также временами срабатывает без нажатия кнопок, приходится дополнительно его проверять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 минуты назад, serafim сказал:

Событие "key_down" также временами срабатывает без нажатия кнопок, приходится дополнительно его проверять.

А при каких условиях оно генерируется кроме, собственно, нажатия кнопок?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, eu_tomat сказал:

А при каких условиях оно генерируется кроме, собственно, нажатия кнопок?

не известно, но кнопок никто не нажимает, но событие происходит

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, serafim сказал:

не известно, но кнопок никто не нажимает, но событие происходит

Можешь скинуть пример кода для демонстрации этого эффекта?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, eu_tomat сказал:

Можешь скинуть пример кода для демонстрации этого эффекта?

Происходит это при работе карьера, но не всегда.

В ранних версиях использовал код такого вида:

Скрытый текст

local e = {require("event").pull("key_down")}
if e[4] == 49 then
  print("программа завершена")
  os.exit()
elseif e[1] == "key_down" then
  print("нажата кнопка")
end

 

Робот возвращался к старту, и по событию key_down должен был продолжить копать,

но в итоге он приезжал и сразу ехал обратно

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 минуты назад, serafim сказал:

Происходит это при работе карьера, но не всегда.

То есть, это какой-то трудновоспроизводимый глюк? Это проверялось в сигнле или на сервере? Другие игроки могли внести изменения в BIOS или библиотеки?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, eu_tomat сказал:

это какой-то трудновоспроизводимый глюк? Это проверялось в сигнле или на сервере?

по видимому глюк

в сингле

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

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

Гость
Ответить в тему...

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

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

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

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

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


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