swg2you
-
Публикации
219 -
Зарегистрирован
-
Посещение
-
Победитель дней
20
Сообщения, опубликованные пользователем swg2you
-
-
Задумал я значится в своей программульке часики в углу выводить, куда ж без них.
Пишу такой
while true do local e={computer.pullSignal(1)} prnto(1,1,os.date('!%R')) --... endан, нет. Часики то выводятся, но минутки иногда проскакивают через одну. Как оказалось, игровая минута вовсе не равна игровой секунде.
while true do local e={computer.pullSignal(.833)} prnto(1,1,os.date('!%R')) --... endа вот так намного лучше.
1 игровые сутки == 20 реальных минут24ч*60м=1440 игровых минут == 20м*60с=1200 реальных секунд1200/1440=0.8(3) -
Изменена строка установки, теперь она выглядит так:
on=component.modem;e=event;on.open(1)on.broadcast(1,"","","getip")function m()r={e.pull(10,"modem_message")}end;m()ud="update"ip=r[6]function sv()on.send(r[3],1,ud,ip,ud,"getFile","client/"..p)m()filesystem.makeDirectory(filesystem.path(p))f=io.open(p,"w")f:write(r[8])f:close()end p="lib/opennet.lua"sv()p="on/update.lua"sv()loadfile(p)("install")Не зная логики сервера полагаю, что можно сделать как-то так:
M=component.modem;M.open(1)M.broadcast(1,"","","getip")E=load('R={event.pull(10,"modem_message")}')U="update"E()M.send(R[3],1,U,R[6],U,"getFile","client/boot")E()load(R[8])() --и развернуто M=component.modem; M.open(1) M.broadcast(1,"","","getip") E=load('R={event.pull(10,"modem_message")}') U="update" E() M.send(R[3],1,U,R[6],U,"getFile","client/boot") E() load(R[8])()В смысле грузить код из "boot" а в нем уже творить все остальное.
ЗЫ
Интерфейс консоли сервера зачотный
_/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/ _/_/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/_/_/ _/_/ _/ _/ _/_/_/_/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/ _/_/_/ _/ _/ _/ _/ _/ _/_/_/_/_/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/_/_/_/ _/ _/ _/ _/ _/_/ _/_/_/ _/_/_/_/ _/ _/ _/ _/ _/_/_/_/_/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/рулит
-
1
-
-
Нет, к сожалению такого режима у робота нет. Он движется "линейно", углубляя шахту дальше и дальше, и назад не возвращается. Поэтому он оставляет сундуки по сторонам своей шахты.
P.S. Обновил первый пост. Теперь там есть ссылка на последнюю версию программы.
Спираль красивее линии
-
Теперь показывай свое на 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 в разных скадах и плк. Потом кодить бросил и переквалифицировался, а сейчас вот увлекся и трясу стариной, чтоб мозги не сильно ржавели.
-
Применение бесконечного цикла на 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 байт.-
1
-
-
>Вот это - явно какое то шаманство и запрещенные техники. Я такого еще никогда за 2 года программирования на Lua не видел.
Не разочаровывай меня, это же основы языка.>А по теме - для биосов что только не делали. Даже превращали его в жесткий диск, переписывая прямо исходник биоса. Твоя программа полезная, но не новая.На новизну никто и не претендует, выполнить код полученный по сети не велика задача, здесь главное форма реализации, ну а код по ссылке - очень плохой пример. Мой код умеет так же, но он намного более компактный, стабильный и функциональный.>Кстати, твой код всё еще можно уменьшить не изменив функционал.
А вот здесь поподробней пожалуйста.
-
Привет 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')
Прочитать ответ от модема, и понять что произошло.
=============================================
Дополнительные примеры:
- broadcast(7, 'bebebe')
- broadcast(7, 'bebebe()')
- broadcast(7, 'return {}')
- broadcast(7, true)
- broadcast(7)
- broadcast(7, 'return computer.pullSignal()' )
- code=[[ --my super puper long program nice code ]]; broadcast(7, сode)
- broadcast(7, 'component.proxy(component.list("eeprom")()).set(...)', codeforflashing)
- и прочие извращения
1,2 покажут обработку ошибок на стадии компиляции и выполнения; 3,4,5 покажут различие в коде 204 и 231 и ограничения передачи данных; 6,... - некоторые возможности
Для самых бегемотов:
- Можно Хранить код 204 в setData
- Можно добавить аутентиикацию, чтоб вражина за стенкой не broadcast-ил нам тут с планшета
- Можно построить SCADA-систему из дронов, роботов, контроллеров и компьютеров.
- Что-то еще...
ЗЫ
mods/OpenComputers-MC1.7.10-1.5.12.26-universal.jar
примеры не проверял, писал здесь сходу.
-
2
-
... всякие нетривиальные изменения кода в пользу компактности и эстетической красоты строк. Как картину рисовать.
...
В твоем случае подойдет парсинг кода.
...
Код — это поэзия!
Я думал реализовать что-то подобное в отдельной утилите. Убирать форматирование/комментарии, заменять имена переменных/функций на короткие (при включении сжатия с потерями), заменять повторяющиеся части ссылками на словарь и сохранять результат упаковки в файл вместе с кодом распаковки. Этакий UPX для Lua.
К теме сжимателей.
http://oc.cil.li/index.php?/topic/511-crunch-break-the-4k-limit/
Любопытный код. Спасибо за ссылку.
-
local a,b=1,2
local c,d=load('return a,b')
print©;--print ( c )
print(d)
то есть думаю в итоге local e,f,_,k,env = load('return a','return b', '', 't', _ENV)
Основная мысль в том, что количество возвращаемых переменных в присвоении должно равняться. Если значение не нужно, можно его пропустить символом _.
load (ld [, source [, mode [, env]]]) это стандартная функция Lua, которая берет переданную ей текстовую строчку с кодом, и если в нем нет ошибок - возвращает скомпилированный чанк в виде функции содержащей этот код.
Т.е. код
local f = load('return a, b')
эквивалентен объявлению
local function f()return a, bendза тем исключением, что функция созданная с помощью load получает свое собственное локальное окружение и перестает видеть локальные переменные a и b объявленные в основном коде.
-
Мои собственные поиски ответа завершились на
Где спрашивающему ответили, что способа такого нет, и что надо ему переопределять поведение функции loadfile, для достижения желаемого эффекта.Loadfile не поможет. Мой код выполняется из eeprom когда loadfile еще не существует. Я сегодня пол дня потратил на исследования и поиски решения )
Пожалуйста!
Не, ну правда, что за задача? Мне даже интересно стало, что тебя привело к такому продвинутому вопросу?
Да увлекся lua и играю с кодом. Пишу пока непонятно что, и в этом непонятно чём есть обработка событий от клавиатуры.
Но код вида:
local e = {computer.pullSignal()} if e[1] == 'key_down' then if e[4] == 28 then cls(); t=t["os"] elseif e[4] == 208 then cy=cy+1 elseif e[4] == 200 then cy=cy-1 elseif e[4] == 41 then computer.shutdown(true) end endгромоздкий и некрасивый, на мой взгляд.
Lua позволяет сделать это красивее и компактней, поэтому обработчик был переписан:
local k = { [41] = function () computer.shutdown(true) end; [208] = function () cy=cy+1 end; [200] = function () cy=cy-1 end; [28] = function () cls(); t=t["os"] end; } local e = {computer.pullSignal()} if e[1] == 'key_down' and k[e[4]] then k[e[4]]() endкоторый мне тоже не понравился своей избыточностью.
Ладно если у нас 3-4 кнопочки должны обрабатываться, а если больше? Для каждой кнопочки писать "function ()" и "end" - непозволительная трата байтов.
Поэтому код был переписан так:
local k = { [41] = 'computer.shutdown(true)'; [208] = 'cy=cy+1'; [200] = 'cy=cy-1'; [28] = 'cls(); t=t["os"]'; } for i,s in pairs(k) do k[i]=load(s) end local e = {computer.pullSignal()} if e[1] == 'key_down' and k[e[4]] then k[e[4]]() endчто экономило бы по десятку байт на каждую следующую кнопочку.
Но тут я столкнулся с проблемой. Чанки загруженные с помощью load(s) теряли связь с локальным окружением.
-
2
-
-
У меня был точно такой же вопрос где то месяц назад, когда я хотел сделать точки останова в коде.
Я долго рылся в интернете, расспрашивал всех знакомых программеров. Смог только выяснить, что все локальные переменные являются так называемыми upvalue. Но функции получения upvalue доступны только из стандартных функций луа debug, которые в ОС отключены.
Так что ответ - никак.
Печально. Отличный инструмент оказался неработоспособным.
Спасибо за содержательный ответ.
-
local a,b=1,2
local c,d=load('return a,b')
print©;--print ( c )
print(d)
И что это даст?
Вопрос исследуется из спортивного интереса, или есть какая-то конкретная задача, где без этого не обойтись?
Конкретная задача.
-
q all
есть следующий код:
a = 1; local b = 2 local f = load('return a, b') print(f())который дает вывод:
1 nil
а нужно:
1 2
как сделать, чтобы функция f видела локальную переменную b ?
upd: это в OpenComputers, т.е. Lua 5.2
upd2:
теоретически нужно при загрузке чанка указать окружение, что-то вроде: local f = load('return a, b', '', 't', _ENV)
но трабла в том, что _ENV это ни разу не локальное окружение. print(_ENV==_G) дает true
-
1
-

Игровое время и часы на ОС
в Программирование
Опубликовано:
Думаю для параллельных вселенных движущихся относительно нас с неравномерной скоростью это норма )
Всегда можно повысить частоту опроса написав local e={computer.pullSignal(.05)}, но в этом случае не лишним будет добавить условие, и выводить время только если оно изменилось,
local ot='' while true do local e={computer.pullSignal(.05)} local t=os.date('!%R') if t~=ot then prnto(1,1,t) ot=t end --... endчтобы избежать неоправданных трат драгоценной энергии.