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

Doob

Гуру
  • Публикации

    1 089
  • Зарегистрирован

  • Посещение

  • Победитель дней

    141

Все публикации пользователя Doob

  1. Doob

    Дубокоп

    Да, надо бы посмотреть какая плотность у тех блоков. Может оказаться, что булыжники имеют плотность руды, а руда плотность камня, тогда ничего не поделать, роботов с камерой пока не завезли.
  2. Было бы интересно сократить вызов методов компонентов, а то они слишком много места занимают. Недавно возникла идея сделать своеобразный конвейер байткода, правда пока кроме вызовов функций ничего не придумал. Зато алгоритм хеширования вроде-бы годный. Вот общая идея: Есть один токен для записи аргументов и один для вызова. Интерпретатор идет по байткоду и если встречает токен записи, то записывает следующие токены в таблицу аргументов, когда встречает токен вызова, находит по его хешу функцию, и передает ей аргументы. Выхлоп функции передается в переменную с таким же хешем. А вот алгоритм хеширования: Берется длина строки, отсекается до 4 бита. Четные байты сдвигаются на 2 бита влево, нечетные на 7, и ксорятся в фиксированную 10 битную последовательность. Первый бит последнего символа сдвигается на оставшийся свободный и все это объединяется. Получается хеш на 15 бит. x = 0 for i = 1, #str do b = str:sub(i, i):byte() & 63 if i % 2 == 0 then x = x ~ b << 2 else x = x ~ b << 7 end end result = (#str & 15) | x | ((str:sub(-1, -1):byte() & 1) << 14) Наверно, можно было это сделать как-то умней, но лень анализировать статистику распределения битов в названиях. Проверил на названиях основных компонентов и их методов, коллизий не обнаружил.
  3. С реализацией беда, прям кошмар-ужас-ужас. Наивные люди полагают, что FORTH это язык, но в действительности это идея интерпретатора. Такая себе сферическая в вакууме идея и ничего больше. Ну и стек еще, но это просто традиция. Сначала пытался все реализовать как деды завещали, но при помощи Lua. Споткнулся на оптимизации. FORTH по идее работает настолько близко к железу, что для него даже ассемблер не нужен, достаточно написать транслятор, а остальное делается самим Фортом (сверху приправляется ассемблерным языком, написанным на Форте, но это по желанию). Lua в качестве ассемблера не годится, слишком высокоуровневый. Есть фортоподобные поделия, реализованные на языках высокого уровня, но для знакомого с традиционными реализациями, они работают крайне странно и необычно. По факту там только игры со стеком. В моем понимании, Форт-программист имеет доступ ко всей системе. Это значит, что форт-система может модифицировать сама себя, есть доступ к входным и выходным данным, к стекам и всей памяти. В связи с этим, я начал делать прослойку между Lua и FORTH в виде процессора виртуальной машины. Немного увлекшись реализовал эмулятор DCPU-16. Но для DCPU-16 уже есть FORTH, да и прослойка получается слишком жирная. Изначальная попытка написать FORTH на Lua у меня сильно конфликтовала с желанием все оптимизировать. Дошло до того, что слова Форта, которые должны работать шитым кодом транслировались в Lua-код, код загружался как обычные функции, а на них ссылаются слова. Я решил, что это мрак какой-то и забросил. Но добавить Форт в опенкомпы все-таки очень хочется. Начал изучать наследников и вообще все фортоподобные языки (даже зачерпнул немного стековой эзотерики). Их уже больше сотни, а если учитывать реализации под конкретные архитектуры, то их несколько сотен наберется. Помимо основной идеи голого интерпретатора есть еще много всего интересного и полезного, но никаких определенных тенденций нет, полный хаос. Добрался до стековых процессоров, в основном они не очень логичные, даже сомнительные, но для реализации на FPGA вполне годятся. И вот тут мне очень понравился процессор J1, он подкупает своей простотой и емкостью инструкций (хотя первая версия очень избыточна и не особо продуманна, есть возможность расширить набор инструкций, что мне очень пригодится). Автор его использует довольно странно, вместо традиционной форт-системы он сделал так, что форт-слова определяются как макросы ассемблера. От форта там название и синтаксис, но на самом деле только ассемблер и макросы, ловко спрятанные под синтаксисом транслятора. Я же решил использовать архитектуру J1 в более традиционной манере, быстро набросал ядро, ассемблер, потом на ассемблере разработаю Форт-транслятор. Для работы с прерываниями надо будет прокинуть ввод-вывод в память, чтобы можно было работать с любыми устройствами опенкомпов. Само-собой надо расширить набор инструкций для превращения сигналов в прерывания, доступа к большему объему памяти и большему количеству операций. Но это еще не все. Понимание недостаточной оптимальности и избыточности заставляет создать еще один вариант, более быстрый и эффективный. Это будет компиляция интересных идей наследников Форта при высокоуровневой реализации, вроде Cat или Joy. Заодно выкинуть весь легаси-мусор, который даже в стандарты засунули. Получается два Форта: Традиционный, совместимый, на виртуальном процессоре J1. Мунспик. Быстрый, удобный, максимально приближенный к реалиям опенкомпов. Совсем не похожий на древний Форт83.
  4. @Odl Через VPN надобно смотреть.
  5. Doob

    Упаковщик прошивок

    Ок, сделано. Я думал, что давно уже процессоры по дефолту работают на 5.3.
  6. Doob

    Упаковщик прошивок

    Добавил алгоритм LZSS. Используется код распаковщика от @BrightYC Жмет намного хуже, но зато не требует карту данных.
  7. Да, действительно, эффект будет тот же. Вот распределение результатов для руды и камня. Дополнил тему.
  8. В моде OpenComputers есть интересное устройство, которое позволяет определить плотность блока на расстоянии. Но вот беда, данные он выдает довольно шумные и чем больше расстояние, тем больше шума. Чтобы определить подлинную плотность блока, можно просканировать его несколько раз, а результат усреднить. Шум, мешающий сканированию, имеет вероятностную природу. И после нескольких сканирований можно статистически найти, какая вероятней всего плотность у блока. За один тик мы можем просканировать 64 блока. Чтобы проанализировать всю доступную область (65 x 65 x 64) сотней итераций, нам понадобится 422500 тиков, что равно 21125 секунд или 352 минуты, то есть без малого 6 часов. Но сколько раз надо сканировать? Сто? Тысячу? Нам открыто тайное знание и есть точный ответ. Один. Всего за одно сканирование мы можем найти руду среди любых других блоков. Если хочется абсолютной уверенности, придется сделать пару магических пассов и просканировать повторно. Начнем с теории. Для начала откроем код мода и найдем функцию geolyzer.scan, она располагается [здесь] src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala и называется onGeolyzerScan() Просмотрев код, мы можем понять, что функция принимает параметры, по этим параметрам сканирует блоки в мире. Делает разные проверки вроде world.blockExists(x, y, z) && !world.isAirBlock(x, y, z), чтобы убедится, что блок есть. Потом получает информацию о блоке по координатам, делает еще несколько проверок (опять проверить, что блок все-таки есть block != null, проверяет дополнительные параметры: includeReplaceable, isFluid(block), block.isReplaceable(world, blockPos.x, blockPos.y, blockPos.z)) Потом происходит измерение расстояния до блока. И в конце берется плотность, смешивается с шумом и расстоянием. Результат добавляется к таблице блоков и отправляется игроку. Вроде-бы ничего необычного. Шум, расстояние, плотность. Нам и так известна зависимость силы шума от расстояния. И вот тут начинается волшебство. Рассмотрим поподробнее код вычисления итоговой плотности блока. e.data(index) = e.data(index) * distance * Settings.get.geolyzerNoise + block.getBlockHardness(world, x, y, z) Коротко можно это записать в виде формулы: R = G * D * N + H G - это сгенерированный шум. D - расстояние до блока. N - множитель шума из конфига (стандартно - 2). H - настоящая плотность. R - результат работы геосканера. Если мы попробуем в качестве эксперимента отнять от результата предполагаемую плотность, то ничего нового не узнаем. Если обратим все операции с известными значениями, то получим только шум. А можем ли мы так же разобрать формулу шума? Давайте попробуем. Несколькими строками выше [ссылка]. Можно наблюдать получение массива случайных байт. val noise = new Array[Byte](e.data.length) world.rand.nextBytes(noise) Далее следует нормализация значений. noise.map(_ / 128f / 33f).copyToArray(e.data) Хм. Так-так-так. Если мы это все обьеденим с предыдущей формулой, то получится что-то вроде такого: R = G(RANDOM_BYTE / 128 / 33) * D * N + H И что это нам дает? А то, что исходное псевдослучайное число имеет жесткую дискретность. ГПСЧ дает случайные числа типа byte, а это только 256 значений (-128, +127). Нам известны все значения, кроме H и RANDOM_BYTE, что нам это дает? Мы можем предположить значение H и обратить всю формулу. (R - H) / D / N * 128 * 33 Для стандартного конфига можно сократить до: 2112 * (R - H) / D А теперь тайное знание для тех, кто не понял самостоятельно. Мы взяли желаемую плотность блока (например 3 для руды). Подставили вместо H. Получили случайное значение. Можем легко определить, угадали ли плотность или нет. Из-за дискретности случайных значений генератора, распределение вероятностей для блоков с разной плотностью не одинаковое. Перейдем к практике. Вот код простого скрипта, который в заданном радиусе ищет блоки с нужной плотностью. Результат выводится на голопроектор. local sqrt = math.sqrt local component = require('component') local geolyzer = component.geolyzer local hologram = component.hologram local function distance(x, y, z) return sqrt(x^2 + y^2 + z^2) end local function magic(R, H, D) return 2112 * (R - H) / D % 1 end local function visualize(hardness, elevation, size) hologram.clear() hologram.setScale(9) local blocks, result for x = -size, size do for z = -size, size do blocks = geolyzer.scan(x, z, elevation, 1, 1, 32) for i_y = 1, 32 do result = magic(blocks[i_y], hardness, distance(x, i_y+elevation-1, z)) if blocks[i_y] ~= 0 and (result > 0.9998 or result < 0.00005) then hologram.set(x+24, i_y, z+24, true) end end end end end local hrd, ele, siz = table.unpack({...}) hrd = hrd or 3 ele = ele or -32 siz = siz or 16 visualize(hrd, ele, siz) А вот результат: При сканировании заметны артефакты. Когда разные плотности близки на целочисленных расстояниях, позникают коллизии. Это можно частично компенсировать, если есть блок кандидат на ошибку. На любом расстоянии можно рассчитать абсолютный минимальный и максимальный уровень шума. С расстоянием, у близких плотностей пересечение значений увеличивается, но если плотность блока не в области пересечений, то можно точно определить к какой области он относится. Пересечение плотностей руды (3) и камня (1.5), точками обозначены три сканирования блока руды. Результаты обратного вычисления для разных плотностей хорошо это демонстрируют. Для компенсации артефактов надо ввести дополнительное условие: полученный RANDOM_BYTE должен быть в диапазоне -128:127. Вот финальный скрипт и результат. local sqrt = math.sqrt local component = require('component') local geolyzer = component.geolyzer local hologram = component.hologram local function distance(x, y, z) return sqrt(x^2 + y^2 + z^2) end local function magic(R, H, D) return 2112 * (R - H) / D end local function visualize(hardness, elevation, size) hologram.clear() hologram.setScale(9) local blocks, result for x = -size, size do for z = -size, size do blocks = geolyzer.scan(x, z, elevation, 1, 1, 32) for i_y = 1, 32 do result = magic(blocks[i_y], hardness, distance(x, i_y+elevation-1, z)) if blocks[i_y] ~= 0 and result > -128 and result < 127 and (result%1 > 0.9998 or result%1 < 0.0002) then hologram.set(x+24, i_y, z+24, true) end end end end end local hrd, ele, siz = table.unpack({...}) hrd = hrd or 3 ele = ele or -32 siz = siz or 16 visualize(hrd, ele, siz) Для более точного определения плотности можно сделать два сканирования. Одно сместить относительно другого так, чтобы расстояния с артефактами не совпадали. Чтобы не выполнять тяжелую операцию sqrt, можно создать словарь, где [x^2 + y^2 + z^2] = sqrt(x^2 + y^2 + z^2), всего понадобится 1742 уникальных значений. P.S. Пост является компиляцией знаний из [этой] темы. Собрал, чтобы перевести и опубликовать на официальном форуме. Автор идеи хакнуть геосканер - @eu_tomat
  9. Выглядит излишне усложненно. С внешней БД таких проблем бы не было, но и это лишнее. Хранение пустых слотов тут не самая большая проблема, там ведь производится много лишних вычислений, чтобы добыть предмет. Стоит хорошо проработать структуру данных, тогда не будет никаких утечек памяти.
  10. Работает, но адаптер не может открыть сундук под собой, тут это обсуждали. Изначально я так и хотел. Но придется считать или хранить пути для всех сундуков, от каждого к каждому. Чтобы избавиться от древовидной структуры надо придумать, как обходить кольца при поиске пути. Самое простое - не использовать двойные сундуки, но хотелось бы с ними. Если с этим разобраться, то все сундуки будут иметь один ранг и можно будет перемещать предметы в любом направлении. Собственно, идея была не только хранить предметы, но еще использовать хранилище как трубы. Можно подключить к системе любое устройство, назначить ему подпрограмму и по команде кидать в него предметы. Например, подключить печку: ставим печку к транспозеру, в программе находим ее по метке, назначаем входы и выходы, потом будет достаточно указать какой ресурс и в каком количестве на какой слот подать, а система будет распределять готовые ресурсы.
  11. Doob

    Упаковщик прошивок

    Сделал тесты потребления памяти. Тест1: ожидание высвобождения памяти и вывод результата. Тест2: вывод потребляемой памяти без сборки мусора, в качестве нагрузки - несжимаемый комментарий. Тест3: тоже, но со сборкой мусора. Для высвобождения памяти можно использовать такой код for i = 0, 9 do computer.pullSignal(2) end Но тут нужны сигналы, для микроконтроллеров такое не всегда подходит. Если программа работает с сигналами, то память высвободится в процессе работы. Для пробного вывода потребления памяти можно делать так. error('Memory used: ' .. computer.totalMemory()-computer.freeMemory(), 0) Тесты показывают, что можно даже на одной памяти первого уровня (192 KiB) спокойно запускать очень сложные программы.
  12. Многие разрабатывают компьютеризированные хранилища, но мало кто публикует. Захотелось мне свое доработать и опубликовать... и я его не нашел. Либо затер сохранение, либо я его писал в каком-то кастомном клиенте, который удалил. В общем, печаль-беда. Предлагаю коллективно разработать умное хранилище на транспозерах, в которое, можно загружать/выгружать предметы, не заморачиваясь с проектированием и стройкой. Вот примерная архитектура моей системы, которую восстановил по памяти. К серверу подключена сеть из транспозеров и сундуков. При первом запуске, системе надо определить и сохранить свою топологию. Для этого, пользователь выбирает сундук, через который будет происходить ввод-вывод предметов, закидывает в него предмет, который будет играть роль метки при сканировании хранилища. Запускает сканирование в терминале. Система проверяет все транспозеры и находит метку. Сундук помечается как корневой и начинается сканирование. При сканировании, система выбирает еще не помеченный сундук и перемещает туда метку. Сундук помечается и путь к нему от корня записывается в базу данных. При повторном прохождении предмета через сундук в направлении от корня, путь перезаписывается, чтобы избежать конфликта в петлях. Представление данных: Адреса транспозеров записываются в список, позиция в этом списке используется во всех операциях с транспозерами. транспозеры = { [1] = uuid_1, [2] = uuid_2, [3] = uuid_3, ... } Имена предметов хранятся в двойном словаре, это позволяет не хранить в базе полное имя предмета, а только ссылку. Полное имя выглядит так: мод:имя_предмета:мета. предметы = { [1] = идентификатор_1, [идентификатор_1] = 1, [2] = идентификатор_2, [идентификатор_2] = 2, [3] = идентификатор_3, [идентификатор_3] = 3, ... } Для каждого сундука хранятся ссылки на смежные транспозеры, это позволяет перемещать предметы в любом направлении и очень быстро обновлять информацию о содержимом, даже если кто-то залез в хранилище руками. Под нулевым индексом хранится путь от корня. сундуки = { [1] = { [0] = {транспозер_1, транспозер_4, транспозер_10, ...}, транспозер_1 = сторона_1, транспозер_2 = сторона_2, транспозер_3 = сторона_3, ... }, ... } В основной базе данных хранится информация о расположении предметов, идентификатор сундука указывает на таблицу предметов, идентификатор предмета это ссылка на словарь, он указывает на таблицу слотов сундука, в которых лежит данный предмет. база_данных = { сундук_1 = { предмет_1 = { [слот1] = количество, [слот2] = количество, [слот3] = количество, ... }, ... }, ... } Счетчик это вспомогательная таблица для визуализации в терминале и транспортировки предметов. Ссылки на предметы служат указателями на таблицу, в которой первым элементом хранится суммарное количество этого предмета в системе, а дальше следуют ссылки на сундуки, которые содержат этот предмет. (У меня эта таблица была разделена на две, но зачем не могу вспомнить) счетчик = { предмет_1 = {суммарное_количество, сундук_1, сундук_2, ...}, предмет_2 = {суммарное_количество, сундук_1, сундук_2, ...}, предмет_3 = {суммарное_количество, сундук_1, сундук_2, ...}, ... } Первый слот во всех сундуках (кроме корневого) всегда свободен, это транспортировочный слот, по которому перемещаются предметы. Алгоритм импорта предмета очень прост, система находит свободный или неполный слот, берет путь из таблицы сундуков и перекачивает предмет, командуя транспозерам записанное направление, обновляет базу данных. Для экспорта ищется предмет, если он есть в ненулевом количестве, то выбираются сундуки и слоты с требуемым суммарным количеством и по очереди в корень переносятся предметы (в обратном направлении) и обновляется база. Для принудительного обновления информации, системе достаточно просканировать сундуки и записать хранящиеся в них предметы. А вот при добавлении транспозеров или сундуков, необходимо производить ту же операцию, что и при первом запуске. База данных получается полностью реляционная, с неполной связью. Ничего лишнего, кроме ссылок не хранится, в памяти сложных операций с таблицами не производится. Последний раз тестировал больше полугода назад, кажется использовал креативную шину, так что транспозеров было больше нормы, никаких проблем с памятью не наблюдалось.
  13. Иногда надо уместить программу на EEPROM, но она никак не хочет туда влезать. Есть решение - карта данных любого уровня, может упаковывать и распаковывать программу, а код распаковки не занимает много места. Благодаря алгоритму Deflate теперь есть где развернуться. Я наконец-то смог запрессовать свою копалку, даже без оптимизации кода, и еще свободное место осталось. Требования: Data-card любого уровня. Интернет карта для установки программы. Установка: pastebin run KThbTuZr или wget https://raw.githubusercontent.com/zgyr/bpacker/master/installer.lua && installer && rm installer.lua или oppm register OpenPrograms/zgyr-Programs oppm install bpacker Использование: bpacker [опции] <имя файла> Опции: -q тихий режим, не показываются статусные сообщения -m минификация кода перед упаковкой (работает не всегда) -l использовать алгоритм lzss (Data card не требуется) -h справка Программа сожмет указанный файл и запишет на EEPROM. Код должен быть адаптирован для работы без OpenOS. TODO: Сделать упаковщик немного умнее. (сейчас код распаковки захардкожен, занимает лишние байты и может не работать в очень редких случаях) Улучшить минификатор. (он лучший среди Lua-минификаторов, но иногда ломает код) Ссылки: Github программы. Github минификатора.
  14. Doob

    quarry карьер

    Зачем так сложно? Есть же излюбленный программистами способ - деление на два. Берем предрассчитанную прочность кирки, когда счетчик насчитает половину использований, вызовем проверку robot.durability(), следующий раз вызовем через оставшуюся половину, и т. д.
  15. Самостоятельная система. Можно было бы сделать, чтобы она грузилась Lua BIOS, как обычная ось. Если уместить ядро на EEPROM, то там будет только базовый функционал, клавиатура и дисплей. Дополнительные блоки слов, текстовый редактор и драйвера надо будет поставлять отдельно.
  16. В процессе. Скоро будет на что посмотреть. Долго курил маны и спецификации, чтобы выяснить одну вещь - каждый пишет Форт так, как хочет. Сейчас набиваю базовые команды, потом сращиваю ядро с опенкомпом. Затем надо тесты написать, или выдрать откуда-нибудь. Как будет основной функционал, можно будет думать над интерфейсами к устройствам. Прокинуть древовидное API через память или имитацию прерываний - тот еще квест.
  17. Если бы все так уныло размышляли, как товарищ NEO, не было бы ни NES эмуляторов, ни JVM с майнкрафтом. Вообще, вряд-ли что-то бы было. Сидели б на жердочках и хлебали пиво лаптями.
  18. Не, проблема была с сохранением. Файл workspace.nbt был пустой. Потом дошло, что надо запустить из консоли без аргументов, просто java -jar ocelot.jar. Тогда все работает нормально.
  19. Эм. Сам предлагал, а теперь смысл ищешь. Вот у нас есть CHIP-8, можно много готовых игр на него добыть. Хотя, это такой себе процессор и игры там соответствующие. Вроде-бы был Z80, (не, это в ComputerCraft было и вроде не работает) там игр и программ уже готовых просто бездна. Хотя, в основном все на васике, поэтому тормозить будет жутко. А Forth я предложил из-за его простоты во всем. Например, надо написать какую-нибудь копалку/сортировку, чтобы она влезла на EEPROM. Lua код вкорячить туда очень больно, хвосты из "end end end end ...." дают ощущение, что это Lisp переросток. Хотя, я подозреваю, что интерпретатор форта тоже не годится, надо его запихивать в процессор или делать движок луа-макросов в целях сокращения пространства. Но просто ради фана интересно сделать в опенкомпах экосистему на другом языке.
  20. Ну дык. Помочь надо, чувак в одиночку мод делает. Процессор есть, если набор команд обычный, то можно С компилятор собрать, а там уже и на Луну можно собираться.
  21. Да, RetroComputers довольно точно перенес компьютерный функционал из RP2. И Forth там больше на себя похож. Еще есть мод MagnetiCraft, и там тоже есть компы, и роботы есть. Компьютер работает на виртуальном MIPS процессоре, для этих компов уже есть системы на ассемблере, BASIC, Lisp и Forth.
  22. А вот тут самое интересное, компы в RedPower это виртуальный процессор 6502, а уже на ассемблере к этому процессору был реализован Forth. Так что не нам говорить о нагрузке. Там еще кто-то писал ось на этом ассемблере, чтобы тики редстоуна не пропускались.
  23. Многие, кто играл в майн с древних времен, помнят, что был такой замечательный мод RedPower2. Помимо всяких крутых механизмов там были компьютеры, работающие на forth-системе. Функционал, правда не богатый, можно было только мигать цветными кабелями. Мод развития не получил, автор пропал. Потом был мод NedoComputers, но он тоже не долго прожил и особого распространения не получил. Есть идея, написать виртуальную машину для OpenComputers. Язык Forth невероятно примитивен, синтаксис простой и лаконичный, базовая система легко уместится на EEPROM. Но есть пара вопросов в реализации. Так как придется писать интерпретатор/компилятор на языке высокого уровня, надо чем-то пожертвовать или отойти от стандарта. Язык плотно работает со стеком. Есть стек данных и стек возвратов (второй пока не трогаем). Адресация 16 бит, следовательно, диапазон памяти = 64КБ. Отсюда имеем первую проблему, придется дробить float64 и имитировать 16 битные числа. Можно не дробить, памяти у нас более чем достаточно. Хотя, в более новых стандартах, реализована работа с 32 и 64 битными числами, написанная на самом Форте. Можно это обыграть, используя стандартный функционал Lua. Еще из-за особенностей выравнивания памяти, у чисел с плавающей точкой отдельный стек и отдельная адресация. Это можно тоже игнорировать и запихнуть float'ы в стек данных (а может и нельзя, тут пока не понятно). Вообще, все это описывается самим Фортом, но имея уже готовый интерфейс к математическому сопроцессору, было бы глупо писать всякие sqrt/sin/tanh жонглированием на стеке. Еще стандарт ANS94 требует много лишнего, вроде доступа к ассемблеру, своеобразной работы с железом и мусорных функций. Поэтому, лучше видится стандарт FORTH-83, он описывает язык очень обобщенно. Только немного расширить его до реалий опенкомпов. Ссылки: стандарт 83 года FORTH-83, слова стандарт 94 года ANS94, слова краткое введение в синтаксис
  24. Программка проста, но мне лень. Были тут на форуме пара лаунчеров, но функционал немного другой. Может кто и напишет. А вот транспозеры могут забирать ресы из инвентаря игрока без всяких сундуков.
  25. Любая статическая схема с таким количеством топлива не эффективна. Динамическая схема из четырех счетверенных, с полным переотражением имеет эффективность 7. В процессе работы энергия скачет между 560 и 140 EU/t.
×
×
  • Создать...