Перейти к публикации
Форум - ComputerCraft
swg2you

bios-net для централизованного управления сетью контроллеров/дронов/роботов/компьютеров

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

Привет all. (после публикации заметил ошибку в названии темы и тегах, код для OpenComputers а не для ComputerCraft, я их постоянно путаю)

 

код 204 байта:

_=component;m=_.proxy(_.list('modem')())m.open(7)u=table.unpack::r::e={computer.pullSignal()}if e[1]=='modem_message'then;_={load(e[6])}if _[1]then;_={pcall(_[1],u(e,7))}end;m.send(e[3],7,u(_));end;goto r

или код 231 байт:

::r::pcall(load("_=component;m=_.proxy(_.list('modem')())m.open(7)u=table.unpack::r::e={computer.pullSignal()}if e[1]=='modem_message'then;_={load(e[6])}if _[1]then;_={pcall(_[1],u(e,7))}end;m.send(e[3],7,u(_));end;goto r"));goto r

Записать в EEPROM любого устройства имеющего сетевую карту, и включить устройство.

 

На отдельном компьютере выполняющем роль сервера выполнить код примера:

modem.open(7)
modem.broadcast(7, "return 'Hello ',  _VERSION,  ...", true, 42, 'bebebe')

Прочитать ответ от модема, и понять что произошло.

=============================================

Дополнительные примеры:

  1. broadcast(7, 'bebebe')
  2. broadcast(7, 'bebebe()')
  3. broadcast(7, 'return {}') 
  4. broadcast(7, true)
  5. broadcast(7)
  6. broadcast(7, 'return computer.pullSignal()' )
  7. code=[[ --my super puper long program nice code ]]; broadcast(7, сode)
  8. broadcast(7, 'component.proxy(component.list("eeprom")()).set(...)', codeforflashing)
  9. и прочие извращения

1,2 покажут обработку ошибок на стадии компиляции и выполнения; 3,4,5 покажут различие в коде 204 и 231 и ограничения передачи данных; 6,... - некоторые возможности

 

Для самых бегемотов:

  1. Можно Хранить код 204 в setData
  2. Можно добавить аутентиикацию, чтоб вражина за стенкой не broadcast-ил нам тут с планшета
  3. Можно построить SCADA-систему из дронов, роботов, контроллеров и компьютеров.
  4. Что-то еще...

ЗЫ

mods/OpenComputers-MC1.7.10-1.5.12.26-universal.jar

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

Изменено пользователем swg2you
  • Like 2

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


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

 

 

::
Вот это - явно какое то шаманство и запрещенные техники. Я такого еще никогда за 2 года программирования на Lua не видел.

 

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

Твоя программа полезная, но не новая.

 

Кстати, твой код всё еще можно уменьшить не изменив функционал.

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


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

>Вот это - явно какое то шаманство и запрещенные техники. Я такого еще никогда за 2 года программирования на Lua не видел.

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

 

>Кстати, твой код всё еще можно уменьшить не изменив функционал.

А вот здесь поподробней пожалуйста.

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

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


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

>Кстати, твой код всё еще можно уменьшить не изменив функционал.

А вот здесь поподробней пожалуйста.

 

Например, 157 байт

m=component.proxy(component.list('modem')()) m.open(42) while true do e,_,_,_,_,cmd=computer.pullSignal() if e=='modem_message' then pcall(load(cmd)) end end
Изменено пользователем Doob

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


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

>Вот это - явно какое то шаманство и запрещенные техники. Я такого еще никогда за 2 года программирования на Lua не видел.

Не разочаровывай меня, это же основы языка.

А в самом деле, не сочти за труд, объясни что это за операторы :: и goto. Я, конечно догадываюсь, что это определение метки и переход по метке, но в Луа с таким сталкиваюсь впервые.

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


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

А в самом деле, не сочти за труд, объясни что это за операторы :: и goto. Я, конечно догадываюсь, что это определение метки и переход по метке, но в Луа с таким сталкиваюсь впервые.

На английском, но с примерами есть тут:

http://lua-users.org/wiki/GotoStatement

 

 

 

>>здесь главное форма реализации,

>>Мой код умеет так же, но он намного более компактный

Можно вопрос - а зачем? Зачем тебе такой компактный код? В биосе 4к места, почему бы им не воспользоваться?

 

 

 

>>А вот здесь поподробней пожалуйста.

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

 

  • Твой код написан хорошо, и абсолютно без изменения функционала удалось сжать его всего на 4-10 символов.
  • С небольшими изменениями, которые не отразятся на условиях работы программы при 90% случаев, можно сжать 230 вариант примерно до 150 байт

    В принципе можно остановиться на этом варианте, но я пошел дальше.

  • Если отказаться от входных параметров, которые не нужны, так как их можно реализовать в клиентской программе, можно сжать первый вариант до 130 байт
  • Если добавить еще небольших условностей, типа без проверки на сигнал модема, можно сжать код до 107 байт
  • Если отказаться от отсылки сообщений об ошибках обратно, которые можно и так определить первым сообщением, код получается 92 байта
Изменено пользователем Krutoy
  • Like 1

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


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

 

На английском, но с примерами есть тут:

http://lua-users.org/wiki/GotoStatement

 

Первый же пример выдал

bios:338: [string "test"]:7: '=' expected

Нет в Minecraft-Lua безусловных переходов, похоже. (тестировалось под КК)

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


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

goto есть зло сущее, отродье BASIC'овское, не используйте его, да не проклятыми за баги будете.

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


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

goto есть зло сущее, отродье BASIC'овское, не используйте его, да не проклятыми за баги будете.

Это предубеждение. Хочу заметить, что goto было добавлено в версию 5.2 совсем не давно, и значит, никак не является архаизмом.

И между прочим, это может быть очень удобно, например, из за отсутствия в луа оператора continue.

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


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

Первый же пример выдал

bios:338: [string "test"]:7: '=' expected

Нет в Minecraft-Lua безусловных переходов, похоже. (тестировалось под КК)

 

В OpenComputers все работает

Вызов функции это тоже безусловный переход

 

 

На английском, но с примерами есть тут:

http://lua-users.org/wiki/GotoStatement

 

 

 

>>здесь главное форма реализации,

>>Мой код умеет так же, но он намного более компактный

Можно вопрос - а зачем? Зачем тебе такой компактный код? В биосе 4к места, почему бы им не воспользоваться?

 

 

 

>>А вот здесь поподробней пожалуйста.

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

 

  • Твой код написан хорошо, и абсолютно без изменения функционала удалось сжать его всего на 4-10 символов.
  • С небольшими изменениями, которые не отразятся на условиях работы программы при 90% случаев, можно сжать 230 вариант примерно до 150 байт

    В принципе можно остановиться на этом варианте, но я пошел дальше.

  • Если отказаться от входных параметров, которые не нужны, так как их можно реализовать в клиентской программе, можно сжать первый вариант до 130 байт
  • Если добавить еще небольших условностей, типа без проверки на сигнал модема, можно сжать код до 107 байт
  • Если отказаться от отсылки сообщений об ошибках обратно, которые можно и так определить первым сообщением, код получается 92 байта

 

 

Да ты маг, у меня только 108, что сжать еще, не знаю))

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

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


Ссылка на сообщение
Поделиться на других сайтах
 
Применение бесконечного цикла на goto позволяет сэкономить 5-6 байт, сравните длины:
::L::a={}goto L
while a={}true do end
repeat a={}until nil

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

---
Размер не важен, если кроме этого кода в EEPROM больше ничего не нужно. Но если вы будете писать, к примеру, дрона с серьезной логикой, или операционную систему работающую из чипа, или интеллектуальный загрузчик с встроенным файловым менеджером, просмотром окружения и доступных устройств, то в 4к вам будет тесновато, и блок, добавляющий возможность выполнения присланного по сети кода, удаленной перепрошивки и прочего - должен быть как можно меньше.
 
На самом деле, это просто получение удовольствие от стремления к идеалу. Спортивный интерес, если угодно. 
---
>без изменения функционала удалось сжать его всего на 4-10 символов.
>Если отказаться от отсылки сообщений об ошибках обратно, которые можно и так определить первым сообщением, код получается 92 байта
Моя хотеть созерцать эту красоту.
 
upd:
Хотя нет! Моя хотеть достичь этой красоты самостоятельно.
 
upd2:
Нет предела совершенству.
Если поставить задачу: в бесконечном цикле, не проверяя на сигнал модема, не обрабатывая ошибок, выполнять полученный по сети код то можно уместиться в 90 байт.
Изменено пользователем swg2you
  • Like 1

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


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

 

 

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

Вот мой код в 92 байта (добавлены переходы строки для читабельности):

_=component
_.proxy(_.list'od'()).open(7)
::r::
pcall(load(({computer.pullSignal()})[6]))
goto r

А так же код с возвращением ошибки и с проверкой имени сигнала. Обрати внимание как я проверяю название сигнала:

-- # Проверка сигнала
_=component m=_.proxy(_.list'od'())m.open(7)::r::a,_,c,_,_,f=computer.pullSignal()_=a:find"mo"and m.send(c,7,pcall(load(f)))goto r

-- # Возврат ошибки
_=component m=_.proxy(_.list'od'())m.open(7)::r::m.send(c,7,pcall(load(({computer.pullSignal()})[6]))goto r

Но тут появилась идея что в принципе, если инициализировать контроллер\дрон первым сообщением, можно сократить до 75 байт:

_=component _.proxy(_.list'od'()).open(7)load(({computer.pullSignal()})[6])

Теперь показывай свое на 90

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


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

Предлагаю добавить swg2you в белый список, как проявившего серьезный интерес к программированию на Луа.

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


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

Предлагаю добавить swg2you в белый список, как проявившего серьезный интерес к программированию на Луа.

Моя интуиция подсказывает что swg2you интерес к Lua уже давно проявил. Похоже он где то еще вне майна Луа выучил.

Это так?

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


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

Теперь показывай свое на 90

Ва-а! Я даже не думал что так ({}) можно обратиться к элементу таблицы.
В своем, я перенес метку в другое место, что сэкономило один байт на разделителе, и выбросил pcall.
--код 90 байт:
--C=component::R::C.proxy(C.list('od')()).open(7)E={computer.pullSignal()}load(E[6])()goto R


--он же развернутый:
C=component
::R::
C.proxy(C.list('od')()).open(7)
E={computer.pullSignal()}
load(E[6])()
goto R

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

 
>Обрати внимание как я проверяю название сигнала: _=a:find"mo"and m.send()
красота в чистом виде, такие конструкции меня всегда приводят в восторг
 
 >если инициализировать контроллер\дрон первым сообщением
Выбросить цикл и не проверять "правильность" события можно, но я пошел по другому пути.
===
Код для EEPROM в 94 байта полностью сохраняющий функционал:
--код 94 байта:
C=component::R::C.proxy(C.list('od')()).open(7)E={computer.pullSignal()}load(E[9]or'')()goto R

--он же в развернутом виде, с комментариями:
C=component

::R:: 
--метка в этом месте экономит 1 байт, т.к. служит одновременно разделителем соседних участков

C.proxy(C.list('od')()).open(7) 
--а то что мы будем открывать уже открытый порт - не является исключением и вполне допустимо

E={computer.pullSignal()} 
--параметры события будем сохранять поскольку мы будем их использовать в загружаемом коде

load(E[9]or'')()
--Если у нас возникло событие вернувшее 9-й параметр, то это наше событие, иначе выполняем пустоту ''

--Стандартные события возвращают не больше 6-ти параметров, а если говорить о сетевых, то
--маловероятно, что кто-то будет делать broadcast с таким количеством параметров. 
--broadcast(port, mess1, mess2, mess3, mess4) <--такое маловероятно, но если встретится,
--то ничто нам не помешает, пожертвовав одним байтом сдвинуть позицию еще дальше.
--Поэтому "правильность" события будем кодировать позиционным методом. 

goto R

Теперь у нас есть сверх-компактный код хранимый в EEPROM, и нам осталось обеспечить обработку ошибочных ситуаций. Поскольку даже самая простая планка ОЗУ имеет в 48 раз больший объем чем EEPROM (192к против 4к), то вполне логичным шагом будет перенос обработки исключений в оперативную память.

 
Напишем конверт обеспечивающий безопасную компиляцию/выполнение кода пользователя и возврат результата или сообщения об ошибке:
U = table.unpack

R = {load(E[10])}
--10-й параметр события загружаем как код пользователя
--конечно, можно заключать код пользователя в конверт простой конкатенцией строк, но такая методика 
--порождает "проблему кавычек" и может приводить к ошибкам, поэтому конверт отдельно, код отдельно

if R[1] then 
  R = { pcall( R[1], U(E, 11) ) } --
end
--если компиляция успешна пробуем выполнить чанк передав ему все оставшиеся параметры

C.proxy(C.list('od')()).send(E[3], 7, U(R))
--и возвращаем отправителю результаты или ошибку если при компиляции/выполнении возникли проблемы

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

 
Длиннокод с длиннокомментариями:
local wrap="U=table.unpack;R={load(E[10])}if R[1]then;R={pcall(R[1],U(E,11))}end;C.proxy(C.list('od')()).send(E[3],7,U(R))"
--конверт объявляем снаружи, мало ли где еще пригодится

function enetRun(addr, code, ...)
  local result=false  
  if type(code)=='string' then
  --load() в eeprom должен получать только строки  
    if addr then
      --приемник должен генерировать событие вида 
      --E=={'modem_message', rAddr, sAddr, port, dist, nil, nil, nil, wrap, code, ...}
      --    ^1               2      3      4     5     6    7    8    9     10    11
      --поэтому посылаем конверт, код и параметры начиная с 9-й позиции события
      result=modem.send(addr, 7, nil, nil, nil, wrap, code, ...)
      --                         ^6   7    8    9     10    11
    else
      --если адрес получателя не задан, то отправляем всем желающим
      result=modem.broadcast(7, nil, nil, nil, wrap, code, ...)
    end
  end
  --и возвращаем true если получилось отправить
  return result
end

--теперь попробуем что-то поотправлять:
enetRun(nil, 123) --это не пропустит наша функция

enetRun(nil, 'computer.beep(440)')
--это просто выполнится в удаленном устройстве, пискнет там нотой Ля и вернет: true
--теперь мы сможем организовывать концерты контроллеров и дронов с солистом роботом

enetRun(nil, 'return 123+...', 4)
--это выполнится  и вернет нам: true, 127

enetRun(nil, 'q')
--это отправится, но наш конверт вернет нам: nil, "и текст ошибки компиляции"

enetRun(nil, 'q()')
--это тоже отправится, но конверт вернет нам: false, "текст ошибки выполнения"

--теперь мы можем удаленно выполнять свои хелловорлды
enetRun(nil, 'return "Hello world"')

--передавая им строковые, числовые, nil-ы или булевы параметры
enetRun(nil, 'return ...', 'Hi', nil, true)

--но даже не пытайтесь передать больше 3-х параметров: 
--enetRun(nil, 'return ...', 1, 2, 3, 4) - на это modem.send будет ругаться: false packet has too many parts
--мы ведь передаем 3 nil-а, конверт и код, это уже 5, а modem.send, по видимому, умеет не больше восьми

--также не пытайтесь передавать другие типы данных: таблицы, потоки,  и т.п.
--enetRun(nil, 'return ...', {}) - modem.send обругает вас: false unsupported data type

--возврат "неправильных" данных вызывающий ошибку на стороне удаленного устройства оставим на совести пользователей  
--enetRun(nil, 'return {}') - треш, краш и халт в modem.send удаленного устройства
--но, если очень захочется, то send конверта можно заключить в pcall, чтобы красиво обработать и это исключение

--осталось получить все что нам прислали наши контродроботы
repeat
  local e={computer.pullSignal()}; 
  e[2]=tostring(e[2]):sub(1,3)  --обрезав адреса до 3-х символов
  e[3]=tostring(e[3]):sub(1,3)  
  prn(table.unpack(e))
until e[1]=='key_up' 
--и выйти по аникею пропищав напоследок Си
computer.beep(329.6)

--напомню, что enetRun(addr, '') будет обращаться к конкретному устройству
--а enetRun(nil, '') позволить опросить все доступные, чтобы выбрать любимчика

--ах, да, prn() это моя собственная функция вывода, у меня нет OpenOS, пишите там print
--и не забывайте вначале получить экземпляр модема и открыть 7-й порт, чтобы видеть ответы

На этом пока всё, спасибо всем отписавшимся, и отдельное спасибо Krutoy за повышение планки и наталкивание на идеи.

 

ЗЫ

Интуиция подводит. С Lua я играю всего пару недель и исключительно через СС OC, хотя кодер довольно опытный, однопроходные дизассемблеры для зилоговских процессоров еще в начале 90-х писал. Потом были бейсики с паскалями, потом LD, FBD, SFC и паскалеподобный ST в разных скадах и плк. Потом кодить бросил и переквалифицировался, а сейчас вот увлекся и трясу стариной, чтоб мозги не сильно ржавели.

 

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


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

 

 

ЗЫ Интуиция подводит. С Lua я играю всего пару недель и исключительно через СС OC, хотя кодер довольно опытный, однопроходные дизассемблеры для зилоговских процессоров еще в начале 90-х писал. Потом были бейсики с паскалями, потом LD, FBD, SFC и паскалеподобный ST в разных скадах и плк. Потом кодить бросил и переквалифицировался, а сейчас вот увлекся и трясу стариной, чтоб мозги не сильно ржавели.
Я так и знал - что то тут не чисто  :)

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

 

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

http://computercraft.ru/topic/675-opennetoc-prodolzhenie/page-6?do=findComment&comment=10751

Хотя конечно, там тоже строка не ограничивается, чем она будет короче - люди будут меньше пугаться.

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


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

Создайте аккаунт или войдите в него для комментирования

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

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас

×