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

Doob

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

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

  • Посещение

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

    141

Сообщения, опубликованные пользователем Doob


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


  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)

    Наверно, можно было это сделать как-то умней, но лень анализировать статистику распределения битов в названиях. Проверил на названиях основных компонентов и их методов, коллизий не обнаружил.

    • Спасибо 1

  3. С реализацией беда, прям кошмар-ужас-ужас.

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

     

    Сначала пытался все реализовать как деды завещали, но при помощи Lua. Споткнулся на оптимизации. FORTH по идее работает настолько близко к железу, что для него даже ассемблер не нужен, достаточно написать транслятор, а остальное делается самим Фортом (сверху приправляется ассемблерным языком, написанным на Форте, но это по желанию).

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

    В моем понимании, Форт-программист имеет доступ ко всей системе. Это значит, что форт-система может модифицировать сама себя, есть доступ к входным и выходным данным, к стекам и всей памяти.

     

    В связи с этим, я начал делать прослойку между Lua и FORTH в виде процессора виртуальной машины. Немного увлекшись реализовал эмулятор DCPU-16. Но для DCPU-16 уже есть FORTH, да и прослойка получается слишком жирная.

    Изначальная попытка написать FORTH на Lua у меня сильно конфликтовала с желанием все оптимизировать. Дошло до того, что слова Форта, которые должны работать шитым кодом транслировались в Lua-код, код загружался как обычные функции, а на них ссылаются слова. Я решил, что это мрак какой-то и забросил.

     

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

     

    Добрался до стековых процессоров, в основном они не очень логичные, даже сомнительные, но для реализации на FPGA вполне годятся.

    И вот тут мне очень понравился процессор J1, он подкупает своей простотой и емкостью инструкций (хотя первая версия очень избыточна и не особо продуманна, есть возможность расширить набор инструкций, что мне очень пригодится). Автор его использует довольно странно, вместо традиционной форт-системы он сделал так, что форт-слова определяются как макросы ассемблера. От форта там название и синтаксис, но на самом деле только ассемблер и макросы, ловко спрятанные под синтаксисом транслятора.

     

    Я же решил использовать архитектуру J1 в более традиционной манере, быстро набросал ядро, ассемблер, потом на ассемблере разработаю Форт-транслятор. Для работы с прерываниями надо будет прокинуть ввод-вывод в память, чтобы можно было работать с любыми устройствами опенкомпов. Само-собой надо расширить набор инструкций для превращения сигналов в прерывания, доступа к большему объему памяти и большему количеству операций.

     

    Но это еще не все. Понимание недостаточной оптимальности и избыточности заставляет создать еще один вариант, более быстрый и эффективный. Это будет компиляция интересных идей наследников Форта при высокоуровневой реализации, вроде Cat или Joy. Заодно выкинуть весь легаси-мусор, который даже в стандарты засунули.

    Получается два Форта:

    1.  Традиционный, совместимый, на виртуальном процессоре J1.
    2.  Мунспик. Быстрый, удобный, максимально приближенный к реалиям опенкомпов. Совсем не похожий на древний Форт83.
    • Одобряю 2
    • Спасибо 1

  4. Выглядит излишне усложненно. С внешней БД таких проблем бы не было, но и это лишнее.

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

    Стоит хорошо проработать структуру данных, тогда не будет никаких утечек памяти.


  5. 20 минут назад, Mihis сказал:

    А разве апгрейд "Контроллер инвентаря" не работает с адаптером?

    Работает, но адаптер не может открыть сундук под собой, тут это обсуждали.

     

    1 час назад, NEO сказал:

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

    Изначально я так и хотел. Но придется считать или хранить пути для всех сундуков, от каждого к каждому.

     

    Чтобы избавиться от древовидной структуры надо придумать, как обходить кольца при поиске пути. Самое простое - не использовать двойные сундуки, но хотелось бы с ними.

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

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

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


  6. Сделал тесты потребления памяти.

     

    Тест1: ожидание высвобождения памяти и вывод результата.

    ZH8sACj.png

     

    Тест2: вывод потребляемой памяти без сборки мусора, в качестве нагрузки - несжимаемый комментарий.

    XL3YnUv.png

     

    Тест3: тоже, но со сборкой мусора.

    kQrvD6V.png

     

    Для высвобождения памяти можно использовать такой код

    for i = 0, 9 do
      computer.pullSignal(2)
    end

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

     

    Для пробного вывода потребления памяти можно делать так.

    error('Memory used: ' .. computer.totalMemory()-computer.freeMemory(), 0)

     

    Тесты показывают, что можно даже на одной памяти первого уровня (192 KiB) спокойно запускать очень сложные программы.


  7. Многие разрабатывают компьютеризированные хранилища, но мало кто публикует.

    Захотелось мне свое доработать и опубликовать... и я его не нашел. Либо затер сохранение, либо я его писал в каком-то кастомном клиенте, который удалил. В общем, печаль-беда.

     

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

     

    Вот примерная архитектура моей системы, которую восстановил по памяти.

    К серверу подключена сеть из транспозеров и сундуков.

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

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

    Запускает сканирование в терминале. Система проверяет все транспозеры и находит метку. Сундук помечается как корневой и начинается сканирование.

    При сканировании, система выбирает еще не помеченный сундук и перемещает туда метку. Сундук помечается и путь к нему от корня записывается в базу данных.

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

     

    Представление данных:

    Адреса транспозеров записываются в список, позиция в этом списке используется во всех операциях с транспозерами.

    транспозеры = {
      [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, ...},
      ...
    }

     

    Первый слот во всех сундуках (кроме корневого) всегда свободен, это транспортировочный слот, по которому перемещаются предметы.

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

    Для экспорта ищется предмет, если он есть в ненулевом количестве, то выбираются сундуки и слоты с требуемым суммарным количеством и по очереди в корень переносятся предметы (в обратном направлении) и обновляется база.

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

     

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

    • Нравится 2

  8. Иногда надо уместить программу на 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 минификатора.

    • Нравится 9

  9.  

    В 29.12.2020 в 04:58, eu_tomat сказал:

    В следующий раз мы используем кирку 204 раз, затем 184 раза, затем 166 и т.д. Чем ниже остаток прочности, тем чаще выполняется его проверка

    Зачем так сложно? Есть же излюбленный программистами способ - деление на два.

    Берем предрассчитанную прочность кирки, когда счетчик насчитает половину использований, вызовем проверку robot.durability(), следующий раз вызовем через оставшуюся половину, и т. д.


  10. Самостоятельная система. Можно было бы сделать, чтобы она грузилась Lua BIOS, как обычная ось.

    Если уместить ядро на EEPROM, то там будет только базовый функционал, клавиатура и дисплей. Дополнительные блоки слов, текстовый редактор и драйвера надо будет поставлять отдельно.

    • Спасибо 1

  11. В процессе. Скоро будет на что посмотреть.

    Долго курил маны и спецификации, чтобы выяснить одну вещь - каждый пишет Форт так, как хочет.

    Сейчас набиваю базовые команды, потом сращиваю ядро с опенкомпом. Затем надо тесты написать, или выдрать откуда-нибудь.

     

    Как будет основной функционал, можно будет думать над интерфейсами к устройствам. Прокинуть древовидное API через память или имитацию прерываний - тот еще квест.

    • Спасибо 1

  12. 58 минут назад, NEO сказал:

    только смысл с этого?

    Эм. Сам предлагал, а теперь смысл ищешь.

     

     

    Вот у нас есть CHIP-8, можно много готовых игр на него добыть. Хотя, это такой себе процессор и игры там соответствующие.

    Вроде-бы был Z80, (не, это в ComputerCraft было и вроде не работает) там игр и программ уже готовых просто бездна. Хотя, в основном все на васике, поэтому тормозить будет жутко.

     

    А Forth я предложил из-за его простоты во всем. Например, надо написать какую-нибудь копалку/сортировку, чтобы она влезла на EEPROM. Lua код вкорячить туда очень больно, хвосты из "end end end end ...." дают ощущение, что это Lisp переросток.

    Хотя, я подозреваю, что интерпретатор форта тоже не годится, надо его запихивать в процессор или делать движок луа-макросов в целях сокращения пространства.

    Но просто ради фана интересно сделать в опенкомпах экосистему на другом языке.

    • Спасибо 1

  13. Да, RetroComputers довольно точно перенес компьютерный функционал из RP2. И Forth там больше на себя похож.

    Еще есть мод MagnetiCraft, и там тоже есть компы, и роботы есть. Компьютер работает на виртуальном MIPS процессоре, для этих компов уже есть системы на ассемблере, BASIC, Lisp и Forth.

    • Спасибо 1

  14. 7 минут назад, eu_tomat сказал:

    При большом желании на Lua можно написать и ассемблер

    А вот тут самое интересное, компы в RedPower это виртуальный процессор 6502, а уже на ассемблере к этому процессору был реализован Forth. Так что не нам говорить о нагрузке. Там еще кто-то писал ось на этом ассемблере, чтобы тики редстоуна не пропускались.

    • Спасибо 1

  15. Многие, кто играл в майн с древних времен, помнят, что был такой замечательный мод RedPower2.

    Помимо всяких крутых механизмов там были компьютеры, работающие на forth-системе. Функционал, правда не богатый, можно было только мигать цветными кабелями.

    th?id=OIP.xecuMIN5y089wRRAfU2RpgHaEK%26p

    Мод развития не получил, автор пропал.

    Потом был мод NedoComputers, но он тоже не долго прожил и особого распространения не получил.

     

    Есть идея, написать виртуальную машину для OpenComputers. Язык Forth невероятно примитивен, синтаксис простой и лаконичный, базовая система легко уместится на EEPROM.

    Но есть пара вопросов в реализации. Так как придется писать интерпретатор/компилятор на языке высокого уровня, надо чем-то пожертвовать или отойти от стандарта.

    Язык плотно работает со стеком. Есть стек данных и стек возвратов (второй пока не трогаем). Адресация 16 бит, следовательно, диапазон памяти = 64КБ. Отсюда имеем первую проблему, придется дробить float64 и имитировать 16 битные числа.

    Можно не дробить, памяти у нас более чем достаточно. Хотя, в более новых стандартах, реализована работа с 32 и 64 битными числами, написанная на самом Форте. Можно это обыграть, используя стандартный функционал Lua. Еще из-за особенностей выравнивания памяти, у чисел с плавающей точкой отдельный стек и отдельная адресация. Это можно тоже игнорировать и запихнуть float'ы в стек данных (а может и нельзя, тут пока не понятно).

    Вообще, все это описывается самим Фортом, но имея уже готовый интерфейс к математическому сопроцессору, было бы глупо писать всякие sqrt/sin/tanh жонглированием на стеке.

    Еще стандарт ANS94 требует много лишнего, вроде доступа к ассемблеру, своеобразной работы с железом и мусорных функций. Поэтому, лучше видится стандарт FORTH-83, он описывает язык очень обобщенно. Только немного расширить его до реалий опенкомпов.

     

    Ссылки:

        стандарт 83 года FORTH-83, слова

        стандарт 94 года ANS94, слова

        краткое введение в синтаксис

        

    • Нравится 3
    • Спасибо 1
    • В шоке 1

  16. Программка проста, но мне лень. Были тут на форуме пара лаунчеров, но функционал немного другой. Может кто и напишет.

     

    А вот транспозеры могут забирать ресы из инвентаря игрока без всяких сундуков.

    • Одобряю 1

  17. Любая статическая схема с таким количеством топлива не эффективна.

    Динамическая схема из четырех счетверенных, с полным переотражением имеет эффективность 7. В процессе работы энергия скачет между 560 и 140 EU/t.

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