Zer0Galaxy
Гуру-
Публикации
1 220 -
Зарегистрирован
-
Посещение
-
Победитель дней
189
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя Zer0Galaxy
-
- Я умею читать чужие мысли! - А я умею читать чужие регулярные выражения! - Ты победил Люди, которые программируют приложения, связанные с обменом по сети rednet или сохранением на диск, часто сталкиваются с необходимостью преобразования массива данных различных типов в строку и последующим его восстановлением. Под массивом я подразумеваю не отдельно взятую таблицу, а несколько переменных, которые нужно упаковать в одну строку. Самый простой но не самый лучший способ решить эту задачу - поместить все необходимые данные в таблицу и воспользоваться функциями serialize, unserialize из библиотеки textutilse. О недостатках такого способа я уже когда-то говорил и сегодня повторяться не буду. А расскажу о том, как эту проблему решаю я. Предположим нам необходимо упаковать в одну строку значения нескольких переменных (x, y, z). Причем строка должна содержать не только значения переменных, но и информацию о том, что это за переменные. Думаю с упаковкой ни у кого больших проблем не возникнет. Сделать это можно, к примеру, так: s='x='..x..' y='..y..' z='..z В результате мы получим строку, которая содержит имена наших переменных и их значения, отделенные от имен знаками равенства. 'x=10 y=11 z=12' Вроде просто. Но как из этой строки извлечь заложенную в нее информацию, а именно имена и значения? Конечно, можно написать большой и сложный алгоритм посимвольного разбора строки. К счастью, вся скучная работа уже сделана за нас и поставленную задачу мы можем выполнить буквально в одно действие. Я говорю о функциях match и gmatch из библиотеки string. Назначение этих функций - поиск шаблона в строке. К примеру, в строке s, которую я привел выше, я хочу найти подстроку 'y=11'. Для этого я вызываю функцию s:match('y=11') которая и вернет мне искомую подстроку, если она там есть. Параметр 'y=11' будем называть шаблоном. Если шаблон в строке не найден, функция вернет nil. Правда здорово?
-
Если роутер С накрылся, до роутера D вообще ничего не дойдет
-
Предположим, мы имеем вот такую сеть Как видим, возможны два маршрута от роутера 1 к роутеру 3. Вес одного из них равен 2, а другого - 3. Естественно выбран будет наиболее короткий маршрут с наименьшим весом. Но что случится если второй роутер выйдет из строя? Прежний маршрут станет недоступным и на какое то время связь прервется. Но к счастью есть старение маршрута. И через пять минут, когда он не обновится, его вес станет равным трем. А еще через пять и вовсе четырем. Вот тут то и стрельнет длинный маршрут, который продолжает обновляться.
-
Теперь по поводу адресации. Адресация в реализованной сети трехуровневая. Это значит, что ip-адрес, возвращаемый функцией getIP, складывается из трех составляющих. Вот пример адреса, который может вернуть getIP white.snow.33 где: white - имя сегмента сети, snow - имя роутера, 33 - id компьютера. Что такое сегмент? Для уменьшения размеров таблиц маршрутизации вся сеть делится на сегменты. Роутер хранит маршруты не ко всем роутерам сети, а к сегментам и к роутерам в своем сегменте. Пример: предположим в сети сотня роутеров. Без сегментации каждому роутеру пришлось бы хранить сто маршрутов. Если сеть разбить на десять сегментов, в таблице маршрутизации каждого роутера будет девять маршрутов на соседние сегменты и десять маршрутов на роутеры своего сегмента. И того - 19. На данный момент реализован только один сегмент - белый. Но планируется еще как минимум шесть. А на счет помощи. Основные технические вопросы касающиеся доставки пакетов решены. Необходимо дальнейшее развитие сети. Наполнение web-серверов, создание электронной почты, чатов и т.д. Можешь подумать как перевести всё это дело на OpenComputers. И конечно актуальным является вопрос русификации.
-
Сеть работает следующим образом. Имеется ряд роутеров, на данный момент семь штук. Каждый роутер имеет статическую таблицу маршрутизации, которая хранится в файле на диске роутера. Обычно она содержит только собственный ip-адрес роутера, но могут быть и исключения. После запуска роутеры начинают с определенным периодом (сейчас 5 минут) обмениваться своими маршрутами. Маршруты, полученные от другого роутера, сохраняются в ОЗУ. Каждый маршрут в таблице имеет параметр, который я называю "вес". Статические маршруты (загруженные из файла) имеют нулевой вес. Динамические - увеличивают свой вес на 1 при каждой передаче от роутера к роутеру. Т.е. если маршрут получен от соседнего роутера он будет иметь вес равный 1, если через одного то - 2. И т.д. Прежде чем добавить динамический маршрут, роутер сравнивает его вес с уже имеющимся в своей таблице и сохраняет маршрут с наименьшим весом. Это сделано для того, что бы хранить в таблице только самые короткие маршруты. Кроме того, маршруты подвержены старению. Если маршрут в течении периода не обновился, его вес увеличивается на единицу. Таким образом появляется шанс у более длинного, но более надежного маршрута. Благодаря этому сеть, хоть и не сразу, но восстанавливается в случае отключения одного из роутеров.
-
Предлагаю потестировать WEB-сервер, созданный на базе Craftnet. Для доступа к серверу вам понадобится уже упоминавшаяся библиотека функций (pastebin get FJqsDgZP ip) и конечно же браузер (pastebin get Gn6ki1TH browser). Браузер нужно запускать на цветном компьютере, оснащенном беспроводным модемом. После запуска браузера кликаем на белую строку ввода адреса и вводим адрес пока единственного сайта (white.poem). [ATTACH]118[/ATTACH] Если всё сделано правильно, вы сможете ознакомиться с несколькими шедеврами мировой поэзии.
-
На сервере 164 успешно прошла тестирование глобальная сеть Craftnet. Если вы знаете и используете API rednet, вас должна заинтересовать возможность связать между собой компьютеры, находящиеся на расстоянии гораздо дальше чем 64 блока. Что для этого нужно? Два или более компьютеров, оборудованных беспроводными модемами и находящихся в зоне покрытия Craftnet. Расстояние между ними значения не имеет. На данный момент зона покрытия имеет радиус порядка 600 блоков с центром в районе спауна. Как этим пользоваться? На каждый компьютер загружаем пакет функций для работы с Craftnet http://pastebin.com/FJqsDgZP Функций всего четыре. Вот они: open() - инициализирует беспроводной модем. В отличии от стандартного rednet.open, не требует указывать сторону, на которой расположен модем. Возвращает true в случае удачной инициализации getIP() - регистрирует компьютер в сети. Возвращает строку с адресом. Этот адрес понадобится другому компьютеру, если он захочет нам что то передать. Функции open и getIP достаточно вызвать один раз. send(ip, mess) - передает сообщение mess компьютеру с адресом ip. Аналог функции rednet.send, только адрес не число, а строка, полученная функцией getIP. receive([timeout]) - переводит компьютер в режим приема сообщений. Аналог функции rednet.receive. Необязательный параметр timeout, как и раньше, задает максимальное время ожидания. Возвращает 1) принятое сообщение 2) ip отправителя 3) ip получателя. Выражаю признательность игроку Neo за идеи, высказанные при обсуждении структуры сети. Rednet: предел - 64 блока; Craftnet: бесконечность - не предел.
-
В прошлый раз мы научились создавать объекты в lua и вызывать их методы. Нами был создан класс ClassA (хорошо, не класс, а объект-прототип), имеющий одно поле (Name) и два метода (Metod1, Metod2). Были созданы два экземпляра объектов и вызваны их методы. Сегодня мы попытаемся создать наследника от ClassA, добавим ему еще одно поле, унаследуем один из методов без изменений, а второй переопределим. Так же как и класс-родитель, наследник изначально представляет собой пустую таблицу: ClassB={} ClassB.__index=ClassB setmetatable(ClassB,ClassA)После выполнения setmetatable, ClassB внешне будет представлять собой точную копию ClassA, т. е. унаследует все его методы.Изменения начнем с конструктора function ClassB:new(_Name,_Size) local obj=ClassA:new(_Name) obj.Size=_Size setmetatable(obj,self) print('Constructor ClassB for '..obj.Name) return obj endКаковы отличия в конструкторах родителя и наследника? Как видим, для создания объекта наследник использует конструктор родителя, а не создает объект «с нуля». Это конечно не обязательно, но такова классика. Другое отличие — новое поле, которое будет хранить воображаемый размер нашего объекта.Переходим к методам. Metod1, как и договаривались оставляем нетронутым, а вот Metod2 переопределим. function ClassB:Metod2() ClassA.Metod2(self) --inherited print('Metod2 of ClassB for '..self.Name..'. Size is '..self.Size) endТут я показал как из метода объекта-наследника вызвать метод объекта-родителя. Но это тоже при необходимости.Вот собственно и всё. Помимо ранее созданных объектов ClassA, создаем еще два экземпляра нового объекта objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end for i = 3,4 do objects[i] = ClassB:new('Object#'..i, i*i) endИ посмотрим что получилось for i=1,4 do objects[i]:Metod1() objects[i]:Metod2() endУ меня получилось вот что:[ATTACH]116[/ATTACH] Обращаю внимание, что для объектов 3 и 4 конструктор и Metod2 выполняются дважды — сначала от ClassA, затем от ClassB. Мы рассмотрели такие особенности ООП как наследование и полиморфизм. А вот как реализовать на lua сокрытие данных объекта от доступа извне (по моему, это называется инкапсуляцией) я пока не знаю. Если знаете — пишите. Для тех кто все таки решил попробовать себя в объектно-ориентированном программировании, напоминаю — следите за пунктуацией. Имя поля отделяем точкой, имя метода — двоеточием. Это важно.
-
В данной статье я хотел бы показать, как можно применять объектно-ориентированный подход при программировании на lua. Если Вы ранее не сталкивались с ООП в других языках, статья вряд ли станет Вам полезной ибо не предназначена для обучения объектно-ориентированному мышлению, а лишь приводит пример реализации объектов. Lua не относится к объектно-ориентированным языкам, поскольку не содержит стандартных механизмов создания и использования объектов. Но lua-таблица является настолько гибким инструментом, что позволяет реализовать практически любую структуру, присущую другим языкам. В том числе и объекты. Прежде чем создавать экземпляры объекта, необходимо описать соответствующий ему класс. ClassA={} ClassA.__index=ClassAПо большому счету, называть это классом нельзя, поскольку класс — это абстракция, служащая шаблоном для создания объекта. Сдесь же мы имеем дело с вполне реальной таблицей. Поэтому ClassA будем называть объектом-прототипом.Как видите, я не описал никаких полей объекта-прототипа т. к. в отличии от таких языков как Delphi и C++, поля таблицы в lua можно описывать когда угодно, а не только при создании таблицы. Поля будем прописывать в конструкторе класса при создании экземпляра объекта. Единственное поле __index содержит указатель на сам класс. Это нужно будет для правильной работы оператора self. Создадим конструктор: function ClassA:new(_Name) local obj={Name = _Name} setmetatable(obj,self) print('Constructor ClassA for '..obj.Name) return obj endЧто делает конструктор?Строка 1. Создает экземпляр теперь уже объекта, описывает поля объекта и присваивает полям начальные значения. Строка 2. Переопределяет метатаблицу вновь созданного объекта, в результате чего объект получает доступ к методам класса. Методов пока нет, но они будут описаны позже. Строка 3. Это необязательная строка. Я ее сюда вставил для демонстрации работы конструктора. Строка 4. Возвращает созданный объект. Теперь создадим парочку методов: function ClassA:Metod1() print('Metod1 of ClassA for '..self.Name) end function ClassA:Metod2() print('Metod2 of ClassA for '..self.Name) endЗачем два? В дальнейшем один из них будет наследован, а другой перекрыт методом наследника. И так, мы создали объект-прототип. Пора создавать экземпляры объекта. Экземпляры будем хранить в таблице objects. Для создания экземпляра вызываем конструктор objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end Смотрим что получилось for i=1,2 do objects[i]:Metod1() objects[i]:Metod2() end Вот программа в полном сборе. ClassA={} ClassA.__index=ClassA function ClassA:new(_Name) local obj={Name = _Name} setmetatable(obj,self) print('Constructor ClassA for '..obj.Name) return obj end function ClassA:Metod1() print('Metod1 of ClassA for '..self.Name) end function ClassA:Metod2() print('Metod2 of ClassA for '..self.Name) end objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end for i=1,2 do objects[i]:Metod1() objects[i]:Metod2() end Если все сделано правильно, после запуска программы Вы должны наблюдать вот такие сообщения: [ATTACH]115[/ATTACH] В следующий раз я расскажу о наследовании методов объекта и их полиморфизме.
-
Это что, реальная статистика? Интересно, откуда оно берет данные? Неужели подавляющее большинство форумчан старше 45? И где 1,2% женщин? Что-то я ни одной не видел. Что такое глубина просмотра?
-
Вот, как то так: local user={} -- Описываем класс user user.__index=user -- это обязательно -- Это метод класса function user:register(login0, password0) self.login = login0 self.password = password0 end -- Это конструктор класса function user:new() local obj={login = '', password = ''} -- создаем новый объект setmetatable(obj,self) -- наделяем его свойствами класса return obj -- возвращаем полученный объект end users={} --тут будем хранить элементы класса for i = 1,5 do -- для создания элемента класса вызываем конструктор users[i] = user:new() -- можно было бы совместить new и register ... print('<'..users[i].login..'>') -- print что бы было видно, что прога работает. -- вызываем метод вновь созданного объекта users[i]:register('login' .. i,'password' .. i) end -- смотрим что получилось for i=1,5 do print(users[i].login,' ',users[i].password) end
-
У тебя будет создан массив users с пятью элементами, каждый из которых является указателем на один и тот же объект user.Попробуй как нибудь вот так function NewUser() local obj={login = '', password = ''} return obj end for i = 1,5 do users[i] = NewUser() -- чувствую вот тут бред уже пишу... print(users[i].login) -- print что бы было видно, что прога работает. end А чтобы такая конструкция работала users[i]:register('login' .. tostring(i),'password' .. tostring(i))нужно метатаблицу переопределять. Вспомню как это делать - выложу.Да, и объявлять локальной переменную цикла не обязательно. Она и так будет локальной
-
На сколько я понял, алгоритм А* предполагает, что карта черепахе известна. Если черепаха сама ее строила, тогда понятно. А если нет, тогда как?
-
Так это же готовая прога построения лабиринта для войны роботов Алекса. Я что то подобное писал, но не такое многофункциональное. Вот только пользоваться флопинетом при наличии реднета это не серьезно. Могу помочь, если есть трудности. И еще. Как на счет следующих вопросов? 1. построения одного объекта сразу несколькими черепахами 2. сканирование готового объекта для сохранения в память Оформление видео - десять из десяти
-
Я полагал, что когда черепаха "умирает", то она умирает и куда то подниматься уже некому. Другое дело, сможет ли она издать предсмертный писк, что бы ее сородичи узнали и пошли мстить?
-
Такая проблема: пытаюсь присоединить монитор к системнику и просто вываливаюсь из майкрафта, без всяких сообщений. Тоже происходит при попытке зайти в терминал робота. Мод качал с официального сайта
-
Никуда не пропадал. В РК регулярно бываю
-
Вопрос: ресурсы, которыми ведется торговля, будут садминены или добыты игровыми средствами? А по поводу цен, по моему, цены должны определяться не столько редкостью и полезностью сколько спросом и предложением. Например, если все сдают уголь и берут алмазы, цена на уголь должна падать, а на алмазы расти. Может даже автоматически. Иначе, если не будет отрицательной обратной связи, можем получить финансовый перекос. Начальные же цены действительно нужно установить исходя из соображений нужности и сложности добычи. Эх, нет у меня экономического образования...
-
Semoro, что тебе известно о русификации СС? Если много, давай тему создадим.
-
Для начала нужно поселиться на сервере недалеко друг от друга и создать небольшую сеть из 3-4 роутеров. По мере необходимости наращивать.К сожалению, я не смогу в ближайшее время появляться на игровом сервере и буду участвовать только из оффлайна. Часто бываю в РК, все вопросы можно туда. Вот ПО роутера, которое должно запускаться из стартапа http://pastebin.com/5T0suSif Таблица маршрутизации - статическая. Ее нужно поместить в файл rtable в корне диска. Пример таблицы first self second 8 third 9 fourth 9Первая колонка - имя подсети, вторая - id по которому будет переправляться пакет на данную подсеть. Если во второй колонке self - значит это собственное имя роутера.Набор функций для хоста http://pastebin.com/FJqsDgZP У Neo есть задумка динамической маршрутизации, но я пока не видел достаточно эффективной реализации.
-
О структуре ip-адреса и таблицах маршрутизации в сети rednet (окончание) Чтобы все сказанное мной выше не казалось безжизненной теорией приведу пример работающих функций, которые могут помочь в нахождении роутером пути для передачи пакета. Первая из них loadTable(filename) предназначена для загрузки таблицы маршрутизации из файла. function loadTable(filename) local rTable={} local file=fs.open(filename,'r') if not file then error('Can not open file '..filename) end local line=file.readLine() while line do local path,id=line:match('^%s-([_%w%.]+)%s+(%d+)') if path then id=tonumber(id) local t=rTable for k in path:gmatch('([_%w]+)%.') do write(k..'.') if not t[k] then t[k]={} elseif type(t[k])=='number' then t[k]={[0]=t[k]} end t=t[k] end local k=path:match('([_%w]+)$') t[k]=id print(k,'=',id) end line=file.readLine() end file.close() return rTable endВ качестве параметра функция принимает строку, содержащую путь к файлу. Возвращает таблицу, в которой данные из файла упакованы в виде удобном для использования. Вызывается один раз в начале работы ПО роутера. Вторая функция trace(t,path) function trace(t,ip) ip=ip..'.' for k in ip:gmatch('([_%w]+)%.') do if not t[k] then return tonumber(k) end if type(t[k])=='table' then t=t[k] else return t[k] end end return t[0] endпринимает два параметра: t — таблица, полученная после вызова функции loadTable; ip – строка, содержащая ip-адрес хоста-приемника. Возвращает функция число — id компьютера (хоста или следующего роутера) на который следует передать пакет. Привожу скриншот работы этих функций для таблицы маршрутизации со следующим содержимым: A.first 7 A.first.self 7 A.first.v_pupkin 13 A.second 8 A.third 9 A.fourth 9 B 8 C 9
-
О структуре ip-адреса и таблицах маршрутизации в сети rednet (продолжение) А теперь предположим, что наши соседи из другой деревни построили сеть аналогичную нашей. И мы связали эти две сети в одну при помощи цепочки повторителей. На рисунке изображены все имеющиеся в наличии роутеры и только два из всех возможных хостов. Наша деревня отмечена буквой А, соседняя — буквой В. Как теперь должна должна выглядеть таблица маршрутизации роутера first, чтобы пакет, предназначенный для деревни В был направлен в нужном направлении? Как я говорил выше, роутер должен знать пути ко всем остальным роутерам сети. Значит ли это, что в таблице должны быть прописаны пути к роутерам 15, 16, 17 и 18 для каждого в отдельности? Но ведь они все лежат в одном направлении и есть смысл выделить их в одну группу — группу В. А роутеры first, second, third и fourth соответственно в группу А. Таким образом ip-адрес теперь будет состоять из трех составляющих: адрес группы, адрес роутера и адрес хоста. Такая сеть будет трехуровневой. Привожу пример таблицы маршрутизации роутера first: A.first.self 10 – Это что бы отличать свои хосты от чужих A.first.v_pupkin 13 – Уже извеcтный нам хост Васи Пупкина A.second 8 – Пакеты на роутер second A.third 9 – Пакеты на роутер third A.fourth 9 – Пакеты на роутер fourth шлем через роутер third B 8 – Пакеты для роутеров группы В шлем через роутер second Разбор адреса производится в следующем порядке. Анализируется первая составляющая ip-адреса. Если это В — отправляем пакет на id 8. Если нет, анализируем вторую составляющую. Если это second, third или fourth — отправляем пакет на соответствующий id. Если нет, анализируем третью составляющую. Если третья составляющая прописана в таблице — отправляем пакет на соответствующий id. Если нет, интерпритируем третью составляющую как число и отправляем пакет на этот id. Если составляющая адреса не обнаружена в таблице, то такой пакет считается ошибочным и игнорируется. В принципе, таким же образом можно построить четырех- и более уровневую сеть. Но я думаю, мы пока ограничимся тремя уровнями. Если не двумя. Окончание следует.
-
А ты попробуй письменно. Может еще кому интересно будет. Я вон уже сколько букв написал
-
О структуре ip-адреса и таблицах маршрутизации в сети rednet (продолжение) И всё бы хорошо, но область покрываемая одним роутером ограничена радиусом 64. Если нам нужно покрыть бОльшую область, одним роутером не обойтись. И те роутеры, которыми мы накрыли требуемую область должны быть связаны между собой На рисунке изображены четыре роутера (я их назвал first, second, third и fourth). К некоторым из них подключены хосты. Как теперь пакету от хоста 11 добраться до хоста, скажем, 14? Прямой связи роутера first с хостом 14 нет. Значит пакет нужно направить на один из роутеров 8 или 9. Прописываем таблицу маршрутизации v_pupkin 13 – Уже известный нам хост Васи Пупкина 14 9 – Пакеты на 14-й хост шлем через роутер third Но хостов, подключенных к роутерам second, third и fourth может быть очень много да и добавляться они могут слишком часто. Неужели их всех нужно руками прописывать в таблицу маршрутизации? Давайте пересмотрим структуру ip-адреса. Пусть теперь этот адрес состоит из двух составляющих: адреса роутера, к которому подключен хост и адреса самого хоста разделенных точкой. Пример fourth.14 Теперь роутеру first не нужно помнить адреса всех хостов сети. Нужно лишь знать пути к роутерам. Вот так выглядит новая таблица маршрутизации. First.self 10 – Это что бы отличать свои хосты от чужих First.v_pupkin 13 – Уже известный нам хост Васи Пупкина second 8 – Пакеты на роутер second third 9 – Пакеты на роутер third fourth 9 – Пакеты на роутер fourth шлем через роутер third Разумеется, похожие таблицы должны быть составлены и для остальных роутеров сети. Такую сеть будем называть двухуровневой. Каковы недостатки такой сети? При добавлении нового роутера (хоть это бывает и не часто) приходится корректировать таблицы маршрутизации всех остальных роутеров. Так же при отключении одного из ранее работавших роутеров будет наблюдаться потеря пакетов, проходящих через него. Как бороться с этими проблеммами? Мне видится динамическое построение таблиц маршрутизации с периодическим обновлением. Возможно со временем нам удастся решить и эту задачу. Продолжение следует...
-
Ребята, давайте не будем спорить о том кто что знает о маршрутизации. Дело в том, что маршрутизация в реальном мире и в мире майнкрафта это две большие разницы. И не нужно переносить свои знания из реала в майн. Давайте лучше подумаем как такую маршрутизацию сделать, во-первых, работоспособной, во-вторых, максимально эффективной. Способ, предложенный Neo, действительно работает в сети из двух роутеров, но над эффективностью нужно еще поработать. Предлагаю для размышления такой способ маршрутизации. Предположим, наша сеть состоит всего из одного роутера и нескольких хостов. Пакет, направляемый хостом-передатчиком в сторону роутера должен содержать адрес хоста-приемника. Роутер извлекает этот адрес и переправляет пакет далее в нужном направлении. Какой должна быть структура ip-адреса в такой сети, если забыть на минутку о реальных ip-адресах? Первое, что приходит в голову, это должно быть одно единственное число, по возможности совпадающее с id хоста. Такую сеть будем называть одноуровневой. Нужна ли в одноуровневой сети таблица маршрутизации? Мне кажется, что нет, поскольку всю необходимую информацию о дальнейшем пути пакета роутер может извлечь из самого пакета. Ну разве что какой либо из пользователей не захочет иметь в качестве адреса число, а захочет иметь строку. Скажем Вася Пупкин, владелец хоста с id 13, ненавидит число 13. Он может обратиться к администратору роутера и тот пропишет вот такую таблицу маршрутизации: v_pupkin 13 Теперь все пакеты с адресом получателя "v_pupkin" будут перенаправляться на id 13. Остальные же пакеты, с числовыми адресами получателей, будут обрабатываться роутером как и прежде. Продолжение следует...
