eu_tomat
-
Публикации
2 666 -
Зарегистрирован
-
Посещение
-
Победитель дней
331
Сообщения, опубликованные пользователем eu_tomat
-
-
2 минуты назад, serafim сказал:судя по расчётам то без изменений
Если речь идёт о моих расчётах, то оптимально делать так:
18 часов назад, eu_tomat сказал:Вызвав robot.durability(), имеет смысл сразу сохранить остаток использования инструмента в переменную и декрементировать её при каждом успешном использовании инструмента. Но при снижении её значения ниже критического уровня не надо сразу бежать на базу, а следует перечитать robot.durability() ещё раз и уже после этого принимать решение.
То есть, вызывать robot.durability() следует как можно реже, самостоятельно довычисляя рабочее значение остатка прочности. Это позволит получить выигрыш во времени около 2-3%. И ездить на зарядку тоже следует как можно реже, не дробя работу на крупные куски. Если, конечно, смотреть с точки зрения оптимизации.
14 минуты назад, serafim сказал:robot.durability() возвращает дробное значение от 1-0 виде 0,950 , 100 - это округление к 95%
А что нам даст знание о целых процентах? Остаток прочности, выраженный в гарантированном количестве оставшихся использований, можно напрямую сравнивать с объёмом работы. А проценты какой смысл сравнивать? Это же относительная величина.
-
1 час назад, serafim сказал:Ну ок, пусть будет как есть
Как будет? Пусть скорость снижается, но упростится код?
1 час назад, serafim сказал:В итоге пришёл к такому коду, для проверки хватит ли выкопать линию
if r.durability() == nil or 100*r.durability() <= length*3+length then
Ну, хорошо. Если упрощаем код, тогда и robot.durability() можно вызывать два раза подряд, это уже не играет особой роли. Но почему константа 100 захардкожена? Разве она не должна зависеть от используемого инструмента?
-
4 часа назад, serafim сказал:Если подумать, то весь объём мне не требуется вычислять, достаточно знать сколько блоков в линии (х),
и хватит ли инструменту прочности чтоб эту линию выкопать
В этом случае резервирование прочности инструмента фискированным куском способствует не столько минимизации затрат времени, сколько упрощению кода. Но, например, в случае протяжённых челночных перемещений робота таки образом можно было бы экономить и время тоже.
На сравнительно коротких дистанциях для работа более важна способность корректного возврата ровно к той позиции, где он прервал свою работу. Предложенная же эвристика не способствует экономии времени, потому что затраты на проверку прочности инструмента крайне малы в сравнении со временем, затрачиваемым роботом на перемещение к заряднику.
Разберём несколько примеров. Для упрощения предположим, что роботу для рубки блоков не требуются перемещения, блоки каким-то образом сами появляются перед роботом. Но для зарядки инструмента роботу требуется переместиться на 10 шагов к заряднику и обратно. Пусть на рубку одного блока требуется 8 тиков. Столько же требуется для единичного перемещения. Также предположим, что инструмент заряжается мгновенно, и для его зарядки робот тратит время лишь на дорогу.
1) Остаток прочности инструмента: 1000/1000.
Очевидно, что в этом случае нет смысла перемещаться к заряднику, а можно смело рубить 1000 блоков, сразу после проверки реальной прочности инструмента один раз перед началом работы. Накладные расходы: 1/(8*1000) = 0.000125.
2) Остаток прочности инструмента: 100/1000.
Если робот сразу приступает к работе, то накладные расходы = 1/(8*100) = 0.00125
Если робот сначала идёт к заряднику, то накладные расходы = (1+20*8)/8*1000 = 0.020125
Видно, что к заряднику идти не выгодно, имеет смысл сначала израсходовать имеющуюся прочность инструмента.
3) Остаток прочности инструмента: 7/1000.
Если робот сразу приступает к работе, то накладные расходы = 1/(8*7) = 0.018
Если робот сначала идёт к заряднику, то накладные расходы = (1+20*8)/8*1000 = 0.020125
Аналогично: сначала имеет смысл потратить прочность инструмента на добычу блоков.
4) Остаток прочности инструмента: 6/1000.
Если робот сразу приступает к работе, то накладные расходы = 1/(8*6) = 0.0208
Если робот сначала идёт к заряднику, то накладные расходы = (1+20*8)/8*1000 = 0.020125
А уже в этом случае теряется смысл расходовать прочность инструмента до последнего, выгоднее сначала зарядиться.
А теперь другой пример: расстояние до зарядника = 40, остаток прочности 2/1000.
Если робот сначала идёт к заряднику, то накладные расходы = (1+80*8)/8*1000 = 0.080125
Если робот сразу приступает к работе, то накладные расходы = 1/(8*3) = 0.0625
В этом случае имеет смысл расходовать прочность инструмента практически до нуля.
Вывод: Для экономии времени на вызовах robot.durability() нет смысла дробить работу на крупные блоки. Запас в 48 блоков приведёт не к увеличению, а снижению скорости копки. Дополнительный смысл такого решения может появиться при длинных челночных проходах роботом или же для упрощения кода, чтобы не прерывать копку в произвольных точках карьера.
-
1
-
-
10 часов назад, serafim сказал:в гео-копалке @Doob использован интересный метод, работающий на тёмной магии
Магия тут вполне себе светлая.
@Doob находит скорость износа экспериментально, совершая несколько попыток применения инструмента, т.к. робот изнашивает инструмент не при каждом использовании, а с некоторой вероятностью, определённой в файле конфигурации OpenComputers. Метод медленный, но не требующий наличия контроллера инвентаря в роботе. Контроллер же инвентаря позволит выполнить эту операцию быстрее: W_R = 1/maxDamage.
Запоздалое, но важное дополнение к абзацу выше: Метод, использующий контроллер инвентаря, успешно работает только с обычными инструментами. Значение maxDamage для перезаряжаемого инструмента имеет другой смысл.
А здесь обратная операция: robot.durability()/W_R, остаток прочности инструмента переводится в остаточное количество использований инструмента. Реальное количество при стандартном конфиге примерно в 10 раз больше, но гарантированное количество именно такое.
Это количество сравнивается с манхэттенским расстоянием до исходной позиции робота. Именно такое количество блоков может потребоваться прорубить при возвращении. К этому добавляется запас в 64 блока. Скорее всего, это максимальное количество движений, которое может потребоваться для полной выработки слоя. Если я верно помню, эта копалка копает столбиками площадью 8x8=64 блока.
10 часов назад, serafim сказал:можно ещё немного ускорить копание убрав постоянную проверку инструмента
Да, именно так. Вызвав robot.durability(), имеет смысл сразу сохранить остаток использования инструмента в переменную и декрементировать её при каждом успешном использовании инструмента. Но при снижении её значения ниже критического уровня не надо сразу бежать на базу, а следует перечитать robot.durability() ещё раз и уже после этого принимать решение.
@Doob решил эту задачу иначе. Его программа уже знает, что слой может быть полностью выкопан до того, как возникнет необходимости вернуться на базу, и проверяет прочность инструмента после обработки очередного слоя. Такая частота проверки, скорее всего, избыточна, и robot.durability() можно вызывать реже.
-
1
-
-
28 минут назад, serafim сказал:я думаю можно поступить проще, если условие if r.detectDown() and not r.swingDown() then срабатывает,
проверяем его три раза, и тогда окончательно делаем вывод что это бедрок.
в случае бура 3х3 оно выполнится только один раз, если внизу бедрок, то все три.
Можно и так. Но тут свои сложности. Помню, у нас на серверах роботу было запрещено бить игрока. В этом случае такая проверка посчитает игрока за бедрок.
Кстати, есть и другие причины для срабатывания этого условия. Например, твёрдость инструмента недостаточна для добычи блока. Или там чей-то приват обнаружился. Или укреплённое стекло из Таумкрафта. Хорошо было бы предупреждать игрока о высоте, на которой был обнаружен этот "бедрок".
-
11 минуту назад, serafim сказал:Меня так-то и вариант с невозможностью сломать блок под роботом вполне устраивал
Обычная развилка: либо дописывать документацию, что с таким-то инструментом программа не работает, либо дописывать новый функционал. Добро пожаловать в разработку.
Кстати, если речь идёт о синем буре 3x3 из Gravitation Suite, то для него оптимален другой алгоритм копки. Поэтому придётся не только детектор бедрока, но и всю копалку переписывать. Эта копалка просто не может реализовать весь потенциал синего бура.
15 минут назад, serafim сказал:для копания видимо нет смысла проверять наличие блока
а вот двигаясь к сундуку и обратно, робот идёт по пустоте, предпочтительней будет именно двигаться
Да, адаптивность полезна. Тут вопрос лишь в том, готов ли разработчик усложнять алгоритм ради коротких эпизодов перемещения к сундуку. Кстати, синий бур в роботе разряжается довольно быстро, и перемещения к сундуку становятся не такими и редкими.
-
31 минуту назад, serafim сказал:Тут можно попробовать иной подход, после взмаха смотреть изменился ли инвентарь,
хотя бы просто ловить событие "inventory_changed"
В общем можно попробовать
Сигнал "inventory_changed" будет поступать только после заполнения очередного стака, то есть, в среднем при каждом 9/64 взмахе бура. Это ненадёжный метод. С другой стороны, и опрашивать robot.count() по всем слотам тоже не вариант.
Видимо, надо сначала оптимизировать эту проверку, проверяя только неполные слоты, а применять её только в случае, когда робот ушёл в шахту именно с этим видом бура. Обработка сигнала inventory_changed должна облегчить поиск неполных слотов.
-
18 минут назад, serafim сказал:1 если робот не может идти вперёд ( значит что-то ему мешает (блок,моб,игрок) ) - атакуй
2 если робот не может атаковать или разрушить блок (значит перед роботом пусто) - идём вперёд
Возможно верным решением будет смотреть если перед роботом что-то, а затем пробывать идти
Применительно к копалкам первое решение хуже второго. Третье решение обещает дать лучший результат, но не оправдывает надежд. Оно лучше первого, но также хуже второго.
- В случае, если маршрут робота пролегает в целом через пустые блоки, оптимален вариант "если не удалось осуществить движение, бей блок".
- Если пустые блоки на пути робота встречаются редко, оптимален вариант "сначала ударь блок перед роботом, затем двигайся".
- Вариант "сначала проверь блок, а затем бей или двигайся" уместен только на фермах опыта, где двигаться вообще не надо. Впрочем, возможно, даже там неуместен, я не проводил таких исследований.
При желании можно даже посчитать тот уровень заполненности пути робота блоками, выше которого выгодно будет использовать первый вариант, а ниже – второй. Если тема получит развитие, можно будет и посчитать точное значение. А пока для простоты я буду исходить из предположения, что пещеры довольно редки, и почти всегда на пути робота находится блок.
В случае, когда робот сначала пытается двигаться, а затем рубить блок в случае неудачи затраты времени примерно такие:
- 10 тиков на неудачную попытку движения.
- 6 тиков (предположим) на рубку блока.
- 8 тиков на успешную попытку движения.
В случае, если робот сначала бьёт, а затем двигается:
- 6 тиков на рубку блока
- 8 тиков на движение
Скорость продвижения увеличится в 24/14=1.71 раза. При сплошной копке "слой через два" ускорение не столь высоко, но всё равно ощутимо: в 1.38 раз. В случае, если перед роботом нет препятствий, и он выполняет неудачный взмах киркой до выполнения движения, произойдёт замедление в (1+8)/8 = 1.125 раза. Но при работе в шахте препятствие перед роботом чаще присутствует, нежели отсутствует.
Применив подобные расчёты для варианта с использованием detect(), ты обнаружишь, что его применение вредно. По крайней мере, в шахте без больших полостей.
-
1
-
@serafim, у меня возникли вопросы в связи с этим кусочком кода:
if r.forward() then xPos = xPos - 1 else r.swing() end
Ты пришёл к этому решению интуитивно, или подсмотрел его в других программах?
Это очень важный вопрос, т. к. касается не только твоей копалки, но и многих других. Подобное решение, будучи неоптимальным, встречается повсеместно. Тут сначала происходит попытка движения, а затем рубка блока, если попытка не удалась. Мне интересно понять, как мыслят программисты, применяющие такое решение. А их, похоже, большинство.
Идея поменять порядок операций движения робота и рубки блока кажется тебе контринтуитивной?
-
1
-
-
34 минуты назад, NEO сказал:проблема заключается в том что, количество озу может быть меньше размера файла.
Это поправимо:
file:seek( "set", blkSize*blkNum ) blkData = file:read( blkSize ) if blkData then array = blkData:byte( 1, blkSize ) end
-
1
-
1
-
-
10 минут назад, kaka888 сказал:Каким образом можно работать со строкой как с массивом байт?
Её же нельзя проиндексировать.
В голову приходит только создание массива символов этой строки с помощью цикла for и паттернов.Проиндексировать можно. Читать данные массива можно так:
content.byte(i,j)
С записью тоже можно что-нибудь придумать, но универсального решения не существует, т.к. Lua не позволяет модифицировать строки, а пересоздание длинных строк весьма накладно. Оптимальное же решение придётся искать под конкретную задачу.
-
1
-
-
Поразмыслив, я запоздало сообразил, что можно было пойти более коротким путём в своих рассуждениях. Когда звучит вопрос об оценке правильности, то первый встречный вопрос, который следует задать: а по каким правилам следует оценивать правильность. По сути, правильность – это соответствие определённому своду правил. Эти слова не случайно являются однокоренными.
Выражение "каждый прав по-своему" подразумевает, что каждый действует по своим правилам, не во всём совпадающими с правилами других. Мы следуем правилам не потому, что они абсолютно правильны, а потому что те помогают эффективнее достигать поставленных нами целей. При этом те же самые правила могут мешать достижению других целей.
Например, есть правило документировать свой код. Но при недостатке времени следует достигать минимально рабочего результата, иногда жертвуя документацией.
Или, например, студенты зачастую неразумно используют оператор goto, превращая свой код в невнятную свалку символов. Поэтому преподаватели вводят правило, запрещающее использование goto. И... часть студентов на всю жизнь вступает в секту противников оператора goto, избегая его применения даже там, где оно облегчает код.
Вот ещё живой пример из другой темы:
В 20.02.2020 в 03:38, Fingercomp сказал:local socket = component.internet.request(...)
Прошло уже 10 месяцев с момента публикации этого кода, но правильность именования переменной до сих пор никого не волновала. А почему? А потому что в том контексте это правило не играло особой роли, и название переменной не мешало участникам обсуждения понимать друг друга.
Вот такая получилась философско-филологическая тема. Не столько о программировании, сколько о логике и о смысле слов и действий. Применяйте правила там, где они уместны. А рассуждая о правильности, уточняйте контекст, который зачастую может содержать множество целей, иногда противоречащих друг другу.
-
12 часа назад, sherrie сказал:Прошу помощи, не знаю, куда рыть!
Сложный вопрос. У нас на форуме мало любителей визуального программирования, а мод ComputerCraftEdu многие даже не запускали. Знатоков Mac у нас тоже не много. Но я попробую дать какие-то общие рекомендации.
Во-первых я посоветую использовать обычный ComputerCraft и программировать на Lua. Всё-таки, визуальное программирование годится лишь для самых примитивных программ. Создавать чуть более сложные программы в визуальном редакторе становится очень затратно.
Если программирование на Lua категорически не устраивает, то я могу дать только один совет: привести ПО на проблемных компьютерах к тому же состоянию, что и на рабочем: версии операционной системы и пакетов, java. Если версии совпадают, то следует скопировать настройки. А для начала можно просто скопировать папку лаунчера и Майнкрафта с корректно работающим модом на проблемные компьютеры.
-
8 минут назад, NEO сказал:Если тебе не явен контекст, тут не мои полномочия, человек использует http protocol, который базируется на сокетах, человек в общем программирует под эвм, очевидно что сокет явно определенный.
Это лишь одна часть контекста, имеющая свою традицию именования переменных. Но это не весь контекст. Программист не должен ограничивать себя мелкими правилами, если они не позволяют ему осуществить задуманное. Поэтому первичен вопрос о целях, которые ставил перед собой программист при написании кода. И если особых целей не было, что выяснилось в последних постах автора вопроса, то смело применяем стандартные правила. Разве ты всегда чётко следуешь всем правилам?
18 минут назад, NEO сказал:Выходит тавтология, в response - хранится response
А как иначе? Ссылку на функцию, возвращающую счётчик, мы называем count. Тоже тавтология? Итератор, возвращающий ответ, можно назвать response. Как это название мешает пониманию кода? Кого оно вводит в заблуждение?
-
19 минут назад, kaka888 сказал:Проблема возникает такая, что другой человек, который читает этот кусок кода, неверно понимает что хранит и делает переменная.
Отлично! У нас есть критерий оценки правильности. Мы называем переменные так, чтобы их название было осмысленным и не противоречило коду. С этой точки зрения прав сетевой программист: название переменной вводит его в заблуждение. Жаль, что он не предложил альтернативу, но попробуем восполнить этот пробел.
17 минут назад, kaka888 сказал:Я вообще не знаю как правильно называть эту переменную, и даже не представляю, ну, мб только handler, хз.
Эту проблему тебе придётся решать каждый раз при написании кода. Названия переменных вроде handler, socket, interface, container и т.п. нежелательны в виду их излишней абстрактности. К тому же, в определённом контексте за этими названиями закреплены конкретные смыслы. Об этом уже упомянул @NEO. Чтобы правильно назвать переменную, надо задать себе вопрос, что именно она хранит. А для этого надо понять, какие значения ей присваиваются.
Что делает функция request? Документация говорит, что функция request осуществляет запрос. Вполне логичное название для функции.
Что возвращает функция request? Ответ на осуществлённый запрос. Значит, переменная хранит ответ.
Теперь осталось перевести слово "ответ" на английский язык. Эта задача не всегда проста из-за наличия в языках синонимов. Причём, синонимы почти всегда имеют альтернативные смыслы.
Для поиска наиболее точного перевода я рекомендую использовать гуглопереводчик, он показывает варианты перевода слова с дополнительными смыслами. Именно анализ дополнительных смыслов позволяет выбрать наиболее адекватный перевод.
Предлагаю кликнуть по ссылке, там есть варианты перевода слова "ответ". В поле формы можно вбить любое другое слово. В нашем случае предложено 8 вариантов перевода. Ориентируясь по дополнительным смыслам синонимов, я выбираю название "response". Возможно, меня поправят другие форумчане, лучше меня владеющие языком.
-
1 час назад, NEO сказал:Других назначений у сокета нет, остальное абстрактная философия и отсебятина или непонимание основ сетевого программирования.
Вопрос был не о назначении сетевых сокетов, а о правильности названия переменной. Без конкретики вопрос о правильности абстрактен. И ответ на него также будет абстрактным до тех пор, пока не появится конкретика.
У тебя есть взгляд на вопрос в контексте сетевого программирования. Предлагаю дополнить его ответами на конкретные вопросы:
- Какое название переменной ты считаешь правильным в данном контексте, и почему?
- Какая проблема возникает, если эту переменную назвать "socket"?
-
8 часов назад, kaka888 сказал:Всё-таки как правильнее будет назвать эту переменную?
Вне контекста вопрос о правильности некорректен. А контекст всё ещё не ясен. Поэтому все ответы на подобный вопрос окажутся мнениями, которые можно будет оспорить. Но ты же хочешь не спора, а какого-то устойчивого и однозначного решения?
8 часов назад, kaka888 сказал:Другое название он не предлагал.
Есть такое правило: критикуешь – предлагай альтернативу. Альтернатива даёт возможность сравнения. И даже если критерии правильности изначально были непонятны, они начинают проясняться во время сравнения и обсуждения альтернативных вариантов.
Здесь есть небольшой намёк на предмет спора:
8 часов назад, kaka888 сказал:Тому знакомому я объяснял свою проблему, связанную с запросами. Я дал ему этот кусок кода, но он подумал, что это не GET-запрос, а какие-то "сокеты". И он мне сказал, что он сам делал не через сокеты, а через get-запрос. Из этого я сделал вывод: либо я херово назвал переменную "socket", либо мой знакомый херово
понимает значение слова "socket", а я всё назвал корректно.
Знакомый, скорее всего, использует слово "socket" в узком смысле этого слова, как его обычно понимают программисты, работающие с сетевыми запросами. И если ты хочешь, чтобы такие программисты не спотыкались, читая твой код, то да, название переменной было выбрано неудачно. Именно неудачно, о правильности пока не говорим.
Буквально слово "socket" означает разъём. Это очень абстрактный смысл, позволяющий применять это слово к любому программному интерфейсу, если очень хочется.
На чьей стороне правда, сказать сложно.
- Ты прав, потому что не преследовал каких-то особых целей. Если нет целей, то нельзя определить и критерии истинности. Код работает? Значит, он правильный.
- Твой знакомый прав, потому что мыслит в определённом, привычном ему контексте. Он различает нюансы терминов, и в этом контексте название "socket" вводит его в заблуждение.
- Ты не прав, потом что ищешь правильность, не сформулировав критерии правильности.
- Твой знакомый не прав, потому что не предложил альтернативу.
Вернёмся к поиску критериев правильности. А их можно определить только исходя из целей.
Какой цели ты хочешь достичь, задавая вопрос о правильности использования термина "socket"? Предположим, ты получил ответ. Как ты его применишь? Какую проблему снимет новое решение?-
1
-
Вне контекста вопрос о правильности не имеет смысла. Поэтому именно с выяснения контекста и начнём.
Изначально вопрос был задан в разделе вопросов по Lua. И с точки зрения синтаксиса Lua ничто не мешает назвать переменную именно таким образом. Но, подозреваю, этот вопрос не про Lua. Поэтому пусть пока этот вопрос побудет в разделе общих вопросов. Может быть, это философский вопрос или филологический. Как знать...
1 час назад, kaka888 сказал:Недавно я столкнулся с проблемой, что более опытный в программировании человек не понял мою идею из-за неправильного (а может и правильного) названия моей переменной "socket"
В чём заключалась твоя идея? Почему, на твой взгляд, именно это название переменной лучше всего отражает идею? Как понял эту идею другой человек? Какую он предлагает альтернативу?
-
23 минуты назад, AQUA сказал:Как отслеживать нажатия и положения мышки, как сделано в MineOS и в редакторе OpenOS?
Для работы с мышью используются сигналы touch, drag, drop и scroll.
Почитать о сигналах можно на русском и английском языках.
-
1
-
-
3 минуты назад, serafim сказал:Происходит это при работе карьера, но не всегда.
То есть, это какой-то трудновоспроизводимый глюк? Это проверялось в сигнле или на сервере? Другие игроки могли внести изменения в BIOS или библиотеки?
-
Только что, serafim сказал:не известно, но кнопок никто не нажимает, но событие происходит
Можешь скинуть пример кода для демонстрации этого эффекта?
-
2 минуты назад, serafim сказал:Событие "key_down" также временами срабатывает без нажатия кнопок, приходится дополнительно его проверять.
А при каких условиях оно генерируется кроме, собственно, нажатия кнопок?
-
1
-
-
В 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.
-
Ого! Да тут кроме основной программы целая коллекция вспомогательных! Использовать их совершенно необязательно, но при использовании копалки любая из них может пригодиться.
-
2
-

quarry карьер
в Роботы
Опубликовано:
Не совсем так. Робот также снижает прочность кирки на единицу, но с шансом 0.1, т.е., в среднем один раз из 10. Таким образом, робот железной киркой может добыть не 251 блок, а в среднем 2510 блоков. Но это в среднем. В каждом конкретном случае может быть больше, а может быть меньше в зависимости от выпадения шанса.
Да. Причём, можно исхитриться и выполнять замер не отдельной процедурой, а прямо во время работы. И так, наверное, даже более правильно.
И да, ты прав, это значение примерное. С точки зрения идеальной математики оно должно быть взаимно обратным значению максимальной прочности. Но погрешности вещественных типов приводят к расхождению, если максимальная прочность большая. Я уже не помню, насколько большим было это расхождение, но точно помню, что оно не не корректировалось округлением до ближайшего целого. Поэтому правильным способом будет непрерывное уточнение значения в процессе использования инструмента. Конечно же, если есть желание получить максимально точное значение максимальной прочности инструмента.
Но на практике, я думаю, это не играет особой роли. Когда прочность инструмента высока, расхождение в единицу прочности не будет фатальным. А по мере износа инструмента точность определения остаточной прочности будет увеличиваться.
Кстати, с синим буром в режиме 3x3 опять будет сложность: он теряет заряд пропорционально количеству срубленных блоков, которое не всегда одинаково и зависит от конфигурации встреченных полостей.