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

По сути, программа представляет из себя эдакий автокад для чертежа карт рельсовых путей. Поддерживается векторная и растровая графика, логические связи и интеллектуальные скоростные режимы набора, значительно ускоряющие рутинные операции. Все, что есть на карте, представляет собой объект со своими уникальными характеристиками и поведением. Естественно реализовано копирование объектов, масштабирование/перемещение/вращение, откат изменений, создание дистрибутивов карт и прочая стандартная хренотень. Так же пока еще в стадии разработки возможность поиска маршрутов и нахождение коллизий с другими маршрутами (чтобы поезда не врезались друг в друга).
Конечно, рассказывать, как сделать такой софт я не буду по нескольким причинам:
1)Это долго – тут не статью, тут книгу писать можно (кстати хорошая идея
)
2)Это сложно. Да-да, это действительно чуть посложнее, чем написать хэлловорлд.
3)Это опасно для моего здоровья. Так как софт и права на него принадлежат фирме, мне могут открутить яйца, если я выложи в инет исходники
. Конкуренты не дремлют, и если раньше на одну большую карту уходило где-то неделя, то с этой прогой максимум один день.
Так а к чему же эта статья спросишь ты? А статья о той проблеме, с которой я столкнулся при написании программы. Как я уже говорил, тут есть скоростной интеллектуальный режим набора рельсовых цепей и рельсовых стрелок, суть его сводится к тому, чтобы сразу соединять объекты в правильные положения в зависимости от того, какие объекты соединяют и для какой цели. Например между двумя горизонтальными РЦ должен быть обязательно стык, а при соединении стрелок и некоторых РЦ они должны преобразовываться в единую гальванически связанную цепь. Все это конечно можно закодить жестко прямо в коде, что я поначалу и сделал. Но потом я начал сталкиваться с тем что таких правил соединения становится много и они могут изменятся. Хотя у меня к тому моменту было всего около десятка этих самых правил, но код уже напоминал чудо-юдо состоящее из нагроможденных и вложенных if’ов. А правил с каждым днем становилось все больше, и я решил поменять стратегию решения возникшей трудности.
Прочитав в одной книге про системы, основанные на правилах (экспертные системы), я решил написать свое ядро для обработки таких правил и свой язык, чтобы эти самые правила записывать (да-да, опять таки это будет интерпретатор). На данный момент у меня есть версия 0.1, более менее стабильная и с ней уже можно работать. Вот о том, как внедрить ее в свои продукты и пойдет речь.
Как подключить?
Для того, чтобы подключить движок к .net программе нужно будет добавить ссылку на dll.

Затем объявляем главную переменную для работы:
Теперь инициализируем ее нашими скриптами (которые мы позже напишем):
Как видишь переменную типа RulespaceManager самому нельзя создать, ее можно получить только пропарсив файл со скриптами.
Кратко рассмотрим что же нам дает этот класс:
1)
Добавляет новый факт в общую память фактов. Твоя программа добавляет факты в память, а мой движок уже на основе правил решает, что ему делать с этими фактами.
2)
Очищает всю память фактов. Не рекомендуется просто так использовать, лучше очистку проводить в скриптах.
3)
Удалить один факт, если он там есть.
4)
Получить конкретный факт и его значение.
5)
Наверное, самая важная функция. После добавления или удаления фактов вызываем этот метод, он запускает анализатор фактов и выполняет нужные правила.
6)
Событие, подписавшись на которое мы сможем получать уведомления и данные из движка.
Вот я вот тут все говорю – факты, факты, а что же такое у нас факт? Факт это объект содержащий имя факта и его значение. Все в текстовом варианте. Хотя как потом ты увидишь, там можно хранить все, и текст и числа. Вот, к примеру, чтобы добавить новый факт в память и выполнить проверку нужно написать вот это:
В последнем методе мы указали true для того чтобы использовать для проверки еще и правило по умолчанию (default rule), о котором чуть позже.
И последнее, о чем нужно знать при взаимодействии с вашим кодом, это класс CallBackVariable. Этот класс служит для взаимодействия между переменными вашего кода и переменными из скриптов. Создать новую переменную этого типа можно вот таким образом:
Первый параметр – это имя переменной в скриптах, в нашем случае это var_offsetX. Важно запомнить, что все переменные в скриптах начинаются с префикса «var_»!
Это нужно для того чтобы различать, где имена фактов, где значения, а где переменные. Так, второй параметр означает текущее значение переменной, так как тип значения object, то сюда можно записывать и строки и числа. Следующий параметр – это перечисления типа значения, это может быть цифровой (Numeric) или текстовый (String). И последний параметр – ссылка на объект типа RulespaceManager.
Так же класс CallBackVariable содержит методы для преведения значения к типам double, int, string и float.
Скрипты – как много в этом звуке…
Быстренько рассмотрев взаимодействие с кодом твоей программы, мы приступим к изучению языка составления правил. Он очень прост, и тем, кто знает какой либо современный язык программирования – выучить его не составит труда.
Первое что надо усвоить – это пространство правил (rulespace). Оно служит для объединения правил по области их действия, например, правила отвечающие за расчет физики, или правила для рисования. Любое правило должно принадлежать какому-либо пространству правил. В принципе пространство правил - аналог пространства имен (namespace) в C# или C++.
Вот так мы объявили пространство правил ConnectLogic, которое, судя по названию, занимается логикой соединений. Все что находится между { и } будет принадлежать этому пространству правил. Далее ты заметил строку «stack 100», это значит, что установить глубину вложенных проверок до 100 уровней, чтобы ненароком не улететь в бесконечную рекурсию, которая правда бывает в большинстве случаев из-за неправильно составленных правил.
Идем дальше, костяк системы – правила. Идеология такова – все должно состоять из правил. Правила должны состоять из условий (фактов) и действий, которые будут выполнены, если правило выиграет (да-да, именно выиграет, привыкайте к этому термину, дальше объясню, почему именно так).
Вот пример простого правила с моей системы:
Здесь идет объявление правила Обычное_Соединение_ГоризонтальнойРЦ_с_горизонтальнойРЦ. Как видите идет без пробелов, если хотите использовать пробелы или другие знаки препинания, то название правила нужно брать в кавычки. Далее мы видим, что все правило заключено в вот такие [] скобки. А теперь разберем по порядку каждую строчку.
enable – включает правило, если написать disable, правило не будет проверятся и работать
weight 1 – указание веса правила равным единице. Вес правила – это то, что определяет насколько это правило важнее и приоритетнее других. Обычно большинству правил ставятся одинаковые веса, а высокоприоритетным правилам (например, таймерам) ставятся большие. Кстати, вес можно менять динамически в коде, чуешь, чем пахнет?:) Можно менять логику выполнения на лету, в зависимости от потребностей.
repeatcount 0 - число повторов, которое одно правило может быть выполнено в течении одной проверки. Некоторые правила могут тоже генерировать факты и правило может сработать еще раз, и ты уж сам решаешь, сколько раз оно должно среагировать. Обычно для большинства достаточно тут указать ноль, т.е. выполнится оно только раз, если пройдут условия и все, больше до следующей проверки не будет выполнятся, освободив возможность выполнится другим правилам.
Так, все что мы рассмотрели до ключевого слова if – это настройки правила.
Важно запомнить, что все ключевые слова пишутся как указано здесь – в нижнем регистре, и вообще язык чувствителен к регистру.
Далее идет ключевое слово if, после которого в круглых скобках заключены условия. Условия делятся на две части – левая часть, то с чем сравнивают (имя факта или переменная) и левая часть, то, что сравнивают (имя факта, переменная и/или арифметические операции). Вообще в языке существует только четыре типа данных:
1)Текст
2)Число
3)Факт
4)Переменная
Все что не является переменной или фактом – то либо текст, либо число. Число – это то, что начинается с цифры, все остальное текст. Для текста, в принципе кавычки не нужны, можно их опускать, но если вы используете разделители в тексте (пробелы, знаки препинания, ключевые слова и т.д.) то кавычки ставить нужно. Теперь узнаем, какие бывают типы сравнения:
(Левая _часть Правая_часть) – равносильно проверки на равенство
(Левая _часть !Правая_часть) – равносильно проверки на неравенство
(Левая _часть >Правая_часть) – равносильно проверки на то, что левая часть больше правой - только для чисел!
(Левая _часть <Правая_часть) – равносильно проверки на то, что левая часть меньше правой - только для чисел!
(Левая _часть ?) – левая часть может принимать любое значение
Особый случай условие (true null) – оно будет всегда истинно, используется, если нужно чтобы правило сработало при любых условиях.
Кстати, есть возможность создавать условия ИЛИ
(condest.Name "Левая точка" or condest.Name "Правая точка").
После блока условий, идет ключевое слова then и идет блок действий. Какие действия могут быть произведены:
add Имя_факта Значение_факта – добавить новый или обновить существующий факт.
delete Имя_Факта - удаляет факт. Можно указать вместо имени звездочку и произойдет очистка всей памяти от фактов.
set Имя_переменной Значение_переменной – назначить новое значение переменной
enable Имя_правила – включить правило
enable Имя_правила Условие – держит включенным правило только пока исполняются нужные условия. Вот какие типы условий бывают:
1)Временные – ms, ss,mm,hh,dd (миллисекунды, секунды, минуты, часы, дни).
(enable this 10ss) – правило будет работать в течении 10 секунд
2)Успешные – su, na.
(enable this 10su) – правило выполнится успешно десять раз и отключится
(enable this 10na) – правило десять раз будет признано успешно выполненным ( но действий выполнять не будет) и потом отключится. Можно применять как заглушку, вроде и действий не выполнится, но и не даст другим правилам сработать.
3)Проверочные – без обозначения.
(enable this 10) – правило десять раз пропустит проверку (т.е. не будет участвовать в ней и никогда не выполнится) и затем отключится.
disable Имя_правила – выключить правило
disable Имя_правила Условие – держит выключенным правило только пока исполняются нужные условия. Вот какие типы условий бывают:
1)Временные – ms, ss,mm,hh,dd (миллисекунды, секунды, минуты, часы, дни).
(disable this 10ss) – правило будет НЕ работать в течении 10 секунд
2)Успешные – su, na.
(disable this 10su) – правило 10 раз типа выполнится (проверится, могло ли оно выполнится или нет) и включится
(disable this 10na) – правило десять раз будет признано успешно выполненным ( но действий выполнять не будет и выполнятся тоже) и потом включится.
3)Проверочные – без обозначения.
(disable this 10) – правило десять раз пропустит проверку (т.е. не будет участвовать в ней и никогда не выполнится) и затем включится.
onoff Имя_правила – инвертирует значение включенности и выключенности правила.
Если нужно включить/выключить свое правило – можно указывать ключевое слово this. А если нужно включить/выключить все правила можно указать ключевое слово all или звездочку *. (disable this 5ss) или (onoff all)
return – прекращает проверку все остальных правил. Нужно тогда, когда вы уже приняли решение, и дополнительные проверки не нужны.
weight Имя_правила Новое_Значение – изменение веса нужного правила, вместо значения можно ставить не только новый вес, но и увелечение или уменьшении оного. Например (weight Имя_правила +10) добавит к текущему весу правила еще десять очков.
invoke Имя_метода_или_данные [переменное число параметров через запятую] – служит для рассылки данных или вызова метода.
(invoke MessageBox "Привет от месседж бокса! Текущий сдвиг="+var_offsetX, "Заголовок "+var_conpo.Name)//пример вызова функции с двумя параметрами
На самом деле этот инвок методов не вызывает, а передает имя и переменное число параметров, тому методу, который вы подписали на событие Receive.
Это безопаснее, позволяет не только методы вызывать, но и просто быстро передать нужные данные, а главное скрипты не смогут испортить программу, вызвав не то, что вы разрешили в вашем коде.
Так, теперь ты знаешь как составлять правила и пора рассказать тебе о том, какие же виды правил бывают.
1)Обычные, т.е. те что мы сейчас рассмотрели. Хочешь узнать, что делать если условия сошлись для нескольких правил сразу? Такое бывает и очень часто. Все правила, чьи условия оказались верными, переходят в зону победителей, где из них выбирается одно единственное, которое и выполнится. По каким же критериям оно выбирается?
а) Вес правила. Победителем будет признано то правило, чей вес будет больше.
б) Если вес равен считают кол-ва условий, победит то правило, у которого условий будет больше (оно более специализированное)
в) Если вес правил и кол-во условий равно, то считается количество обобщенных условий, т.е. те у которых может быть любой значение (Name ?). Выигрывает то правило, у кого обобщенных условий меньше.
2)Правило инициализации – правило, которое будет выполнено один раз, перед всеми правилами, служит для инициализации начальных фактов или переменных.
Т.е. обычное правило, только с именем init и выполнится оно всего лишь один раз, перед всеми.
3)Правило по умолчанию. Сработает только тогда, когда не сработало не одно правило. Действует как default в switch.
Так, с типами правил разобрались. В основном будем работать с обычными правилам. Расскажу сейчас как с помощью обычных правил, можно делать таймер Вот пример правила, которое будет каждые 5 секунд включать/выключать другое правило, меняя логику программы.
Ну вот, теоретическая часть закончена, осталось лишь сказать о том, что скрипты поддерживают два вида комментариев, как в С++:
1)//однострочный комментарий
2)/* многострочный
комментарий*/
Немного практики.
Сейчас напишем небольшой примерчик, чтобы убедится, что это все работает. Сразу скажу, что правила обычно пишутся под готовые или наполовину готовые большие программы, но никак не программы под правила. Так что в этом примере не увидим всех преимуществ, но зато увидим как же все таки это функционирует.
Для начала создаем новое оконное приложение, подключаем библиотеку и конструкторе формы прописываем инициализацию:
Затем пишем метод приема сообщений от системы правил:
Теперь по таймеру, например четыре раза в секунду мы будем вызывать метод который передаст системе нужные факты (координаты окна, длину окна и координаты мыши):
Все! В программе больше писать ничего не нужно. Теперь создадим в папке с бинарником файл rules.txt и запишем туда правила. Кстати, не забудь сохранить файл в кодировке utf-8!
Составим первое правило, оно будет отслеживать, не выходит ли окно за левый край экрана, и если выходит – то вернем координату к нулю.
Создаем аналогичное правило для отслеживания выхода за верхнюю границу экрана:
Теперь накодим два правила, которые будут срабатывать. если курсор мышки будет
выходить за пределы окна по Х-координате, окно будет ползти к курсору
Все эти правила сработают только при условиях, а сейчас создадим правило, которое будет всегда отображать текущие координаты окна и мыши в заголовке формы нашего приложения. Естественно, чтобы оно срабатывало всегда, и даже тогда. когда срабатывают другие правила – то придется увеличить ей вес:
А чтобы было еще веселей, напишем правило таймер, которое каждые десять секунд будет то включать перемещения за курсором, то отключать:
Теперь запустив приложение можно наблюдать постоянное изменение заголовка, если меняются координаты мыши/окна и перемещение за мышкой, которое, то включитс, на 10 сек, то отключится, тоже на 10 сек. А если поставить stack 0, то скрипты отключатся и будет обычное окно, без поведения и заголовка с координатами.

Вот теперь все, пришло время подвести итоги сегодняшнего урока. Попробую перечислить основные преимущества включения правил в программные продукты:
1)Возможность изменения/добавления/удаления логики программы без затрагивания исходного кода.
2)Правильно составленные правила избавляют код от кучи вложенных if’ов и делают логику более прозрачной.
3) Изменение приоритета выполнения логических частей.
4)Включение/отключение логических частей по времени или условию.
5)Три вида правил позволяют строить достаточно гибкие конструкции.
6)Простота изучения и использования.
7)Возможность полного отключения сразу всех правил, ПО будет работать, будто вы и не внедряли никаких скриптов (для этого достаточно stack 0 написать).
А теперь минусы системы:
1)Система правил подойдет далеко не для всех решений. У нее очень узкий круг задач.
2)Систему писал только я, поэтому она не самая производительная и удобная.
3)Возможность присутствия скрытых недоработок или затаившихся ошибок.
4)Еще не очень доработанный синтаксис при работе с математикой.
Вообщем вывод таков – узкоспециализированная система со своими плюсами и минусами, но возможно именно тебе она и облегчит жизнь.
P.S. Если наберется достаточное кол-во желающих, то я могу написать статью как я делал эту библиотечку, чтоб ты знал, как же такое чудо-юдо сотворить
. За сим откланяюсь и ухожу во свояси дебажить остальные проекты. Удачи! 
your_code_your_rules.zip [71.22 Kb] (cкачиваний: 11)
По сути, программа представляет из себя эдакий автокад для чертежа карт рельсовых путей. Поддерживается векторная и растровая графика, логические связи и интеллектуальные скоростные режимы набора, значительно ускоряющие рутинные операции. Все, что есть на карте, представляет собой объект со своими уникальными характеристиками и поведением. Естественно реализовано копирование объектов, масштабирование/перемещение/вращение, откат изменений, создание дистрибутивов карт и прочая стандартная хренотень. Так же пока еще в стадии разработки возможность поиска маршрутов и нахождение коллизий с другими маршрутами (чтобы поезда не врезались друг в друга).
Конечно, рассказывать, как сделать такой софт я не буду по нескольким причинам:
1)Это долго – тут не статью, тут книгу писать можно (кстати хорошая идея
2)Это сложно. Да-да, это действительно чуть посложнее, чем написать хэлловорлд.
3)Это опасно для моего здоровья. Так как софт и права на него принадлежат фирме, мне могут открутить яйца, если я выложи в инет исходники
Так а к чему же эта статья спросишь ты? А статья о той проблеме, с которой я столкнулся при написании программы. Как я уже говорил, тут есть скоростной интеллектуальный режим набора рельсовых цепей и рельсовых стрелок, суть его сводится к тому, чтобы сразу соединять объекты в правильные положения в зависимости от того, какие объекты соединяют и для какой цели. Например между двумя горизонтальными РЦ должен быть обязательно стык, а при соединении стрелок и некоторых РЦ они должны преобразовываться в единую гальванически связанную цепь. Все это конечно можно закодить жестко прямо в коде, что я поначалу и сделал. Но потом я начал сталкиваться с тем что таких правил соединения становится много и они могут изменятся. Хотя у меня к тому моменту было всего около десятка этих самых правил, но код уже напоминал чудо-юдо состоящее из нагроможденных и вложенных if’ов. А правил с каждым днем становилось все больше, и я решил поменять стратегию решения возникшей трудности.
Прочитав в одной книге про системы, основанные на правилах (экспертные системы), я решил написать свое ядро для обработки таких правил и свой язык, чтобы эти самые правила записывать (да-да, опять таки это будет интерпретатор). На данный момент у меня есть версия 0.1, более менее стабильная и с ней уже можно работать. Вот о том, как внедрить ее в свои продукты и пойдет речь.
Как подключить?
Для того, чтобы подключить движок к .net программе нужно будет добавить ссылку на dll.
Затем объявляем главную переменную для работы:
private JF_Ruls.RulespaceManager rm;
Теперь инициализируем ее нашими скриптами (которые мы позже напишем):
rm = new JF_Ruls.Parser("имя файла", "Имя простанства правил").Parse();
Как видишь переменную типа RulespaceManager самому нельзя создать, ее можно получить только пропарсив файл со скриптами.
Кратко рассмотрим что же нам дает этот класс:
1)
public void AddFact(JF_Ruls.Fact fact)
Добавляет новый факт в общую память фактов. Твоя программа добавляет факты в память, а мой движок уже на основе правил решает, что ему делать с этими фактами.
2)
public void ClearAllFacts()
Очищает всю память фактов. Не рекомендуется просто так использовать, лучше очистку проводить в скриптах.
3)
public void DeleteFact(JF_Ruls.Fact fact)
Удалить один факт, если он там есть.
4)
public JF_Ruls.Fact GetFact(JF_Ruls.Fact fact)
Получить конкретный факт и его значение.
5)
public void CheckFactsMemoryByRules(bool WithDefaultRule)
Наверное, самая важная функция. После добавления или удаления фактов вызываем этот метод, он запускает анализатор фактов и выполняет нужные правила.
6)
public event JF_Ruls.RulespaceManager.ReturnResult Receive
Событие, подписавшись на которое мы сможем получать уведомления и данные из движка.
Вот я вот тут все говорю – факты, факты, а что же такое у нас факт? Факт это объект содержащий имя факта и его значение. Все в текстовом варианте. Хотя как потом ты увидишь, там можно хранить все, и текст и числа. Вот, к примеру, чтобы добавить новый факт в память и выполнить проверку нужно написать вот это:
rm.AddFact(new JF_Ruls.Fact("conpo.Name", conpo.Name));//заносим имя точки
rm.CheckFactsMemoryByRules(true);//включаем проверку на правила
rm.CheckFactsMemoryByRules(true);//включаем проверку на правила
В последнем методе мы указали true для того чтобы использовать для проверки еще и правило по умолчанию (default rule), о котором чуть позже.
И последнее, о чем нужно знать при взаимодействии с вашим кодом, это класс CallBackVariable. Этот класс служит для взаимодействия между переменными вашего кода и переменными из скриптов. Создать новую переменную этого типа можно вот таким образом:
JF_Ruls.CallBackVariable offsetX = new JF_Ruls.CallBackVariable("var_offsetX", 0, JF_Ruls.CallBackVariable.VariableType.Numeric, rm);
Первый параметр – это имя переменной в скриптах, в нашем случае это var_offsetX. Важно запомнить, что все переменные в скриптах начинаются с префикса «var_»!
Это нужно для того чтобы различать, где имена фактов, где значения, а где переменные. Так, второй параметр означает текущее значение переменной, так как тип значения object, то сюда можно записывать и строки и числа. Следующий параметр – это перечисления типа значения, это может быть цифровой (Numeric) или текстовый (String). И последний параметр – ссылка на объект типа RulespaceManager.
Так же класс CallBackVariable содержит методы для преведения значения к типам double, int, string и float.
offsetX.GetInt();
Скрипты – как много в этом звуке…
Быстренько рассмотрев взаимодействие с кодом твоей программы, мы приступим к изучению языка составления правил. Он очень прост, и тем, кто знает какой либо современный язык программирования – выучить его не составит труда.
Первое что надо усвоить – это пространство правил (rulespace). Оно служит для объединения правил по области их действия, например, правила отвечающие за расчет физики, или правила для рисования. Любое правило должно принадлежать какому-либо пространству правил. В принципе пространство правил - аналог пространства имен (namespace) в C# или C++.
rulespace ConnectLogic
{
stack 100//указываем максимальную глубину стека проверок
}
{
stack 100//указываем максимальную глубину стека проверок
}
Вот так мы объявили пространство правил ConnectLogic, которое, судя по названию, занимается логикой соединений. Все что находится между { и } будет принадлежать этому пространству правил. Далее ты заметил строку «stack 100», это значит, что установить глубину вложенных проверок до 100 уровней, чтобы ненароком не улететь в бесконечную рекурсию, которая правда бывает в большинстве случаев из-за неправильно составленных правил.
Идем дальше, костяк системы – правила. Идеология такова – все должно состоять из правил. Правила должны состоять из условий (фактов) и действий, которые будут выполнены, если правило выиграет (да-да, именно выиграет, привыкайте к этому термину, дальше объясню, почему именно так).
Вот пример простого правила с моей системы:
define Обычное_Соединение_ГоризонтальнойРЦ_с_горизонтальнойРЦ
[
enable
weight 1
repeatcount 0
if
(conpo.ParentShape.Class RC)
(condest.ParentShape.Class RC)
(conpo.ParentShape.MyType ГоризонтальнаяРельсоваяЦепь)
(condest.ParentShape.MyType ГоризонтальнаяРельсоваяЦепь)
(condest.Name "Правая точка")
then
(delete *)
(set var_offsetX 4)
(return)
]
[
enable
weight 1
repeatcount 0
if
(conpo.ParentShape.Class RC)
(condest.ParentShape.Class RC)
(conpo.ParentShape.MyType ГоризонтальнаяРельсоваяЦепь)
(condest.ParentShape.MyType ГоризонтальнаяРельсоваяЦепь)
(condest.Name "Правая точка")
then
(delete *)
(set var_offsetX 4)
(return)
]
Здесь идет объявление правила Обычное_Соединение_ГоризонтальнойРЦ_с_горизонтальнойРЦ. Как видите идет без пробелов, если хотите использовать пробелы или другие знаки препинания, то название правила нужно брать в кавычки. Далее мы видим, что все правило заключено в вот такие [] скобки. А теперь разберем по порядку каждую строчку.
enable – включает правило, если написать disable, правило не будет проверятся и работать
weight 1 – указание веса правила равным единице. Вес правила – это то, что определяет насколько это правило важнее и приоритетнее других. Обычно большинству правил ставятся одинаковые веса, а высокоприоритетным правилам (например, таймерам) ставятся большие. Кстати, вес можно менять динамически в коде, чуешь, чем пахнет?:) Можно менять логику выполнения на лету, в зависимости от потребностей.
repeatcount 0 - число повторов, которое одно правило может быть выполнено в течении одной проверки. Некоторые правила могут тоже генерировать факты и правило может сработать еще раз, и ты уж сам решаешь, сколько раз оно должно среагировать. Обычно для большинства достаточно тут указать ноль, т.е. выполнится оно только раз, если пройдут условия и все, больше до следующей проверки не будет выполнятся, освободив возможность выполнится другим правилам.
Так, все что мы рассмотрели до ключевого слова if – это настройки правила.
Важно запомнить, что все ключевые слова пишутся как указано здесь – в нижнем регистре, и вообще язык чувствителен к регистру.
Далее идет ключевое слово if, после которого в круглых скобках заключены условия. Условия делятся на две части – левая часть, то с чем сравнивают (имя факта или переменная) и левая часть, то, что сравнивают (имя факта, переменная и/или арифметические операции). Вообще в языке существует только четыре типа данных:
1)Текст
2)Число
3)Факт
4)Переменная
Все что не является переменной или фактом – то либо текст, либо число. Число – это то, что начинается с цифры, все остальное текст. Для текста, в принципе кавычки не нужны, можно их опускать, но если вы используете разделители в тексте (пробелы, знаки препинания, ключевые слова и т.д.) то кавычки ставить нужно. Теперь узнаем, какие бывают типы сравнения:
(Левая _часть Правая_часть) – равносильно проверки на равенство
(Левая _часть !Правая_часть) – равносильно проверки на неравенство
(Левая _часть >Правая_часть) – равносильно проверки на то, что левая часть больше правой - только для чисел!
(Левая _часть <Правая_часть) – равносильно проверки на то, что левая часть меньше правой - только для чисел!
(Левая _часть ?) – левая часть может принимать любое значение
Особый случай условие (true null) – оно будет всегда истинно, используется, если нужно чтобы правило сработало при любых условиях.
Кстати, есть возможность создавать условия ИЛИ
(condest.Name "Левая точка" or condest.Name "Правая точка").
После блока условий, идет ключевое слова then и идет блок действий. Какие действия могут быть произведены:
add Имя_факта Значение_факта – добавить новый или обновить существующий факт.
delete Имя_Факта - удаляет факт. Можно указать вместо имени звездочку и произойдет очистка всей памяти от фактов.
set Имя_переменной Значение_переменной – назначить новое значение переменной
enable Имя_правила – включить правило
enable Имя_правила Условие – держит включенным правило только пока исполняются нужные условия. Вот какие типы условий бывают:
1)Временные – ms, ss,mm,hh,dd (миллисекунды, секунды, минуты, часы, дни).
(enable this 10ss) – правило будет работать в течении 10 секунд
2)Успешные – su, na.
(enable this 10su) – правило выполнится успешно десять раз и отключится
(enable this 10na) – правило десять раз будет признано успешно выполненным ( но действий выполнять не будет) и потом отключится. Можно применять как заглушку, вроде и действий не выполнится, но и не даст другим правилам сработать.
3)Проверочные – без обозначения.
(enable this 10) – правило десять раз пропустит проверку (т.е. не будет участвовать в ней и никогда не выполнится) и затем отключится.
disable Имя_правила – выключить правило
disable Имя_правила Условие – держит выключенным правило только пока исполняются нужные условия. Вот какие типы условий бывают:
1)Временные – ms, ss,mm,hh,dd (миллисекунды, секунды, минуты, часы, дни).
(disable this 10ss) – правило будет НЕ работать в течении 10 секунд
2)Успешные – su, na.
(disable this 10su) – правило 10 раз типа выполнится (проверится, могло ли оно выполнится или нет) и включится
(disable this 10na) – правило десять раз будет признано успешно выполненным ( но действий выполнять не будет и выполнятся тоже) и потом включится.
3)Проверочные – без обозначения.
(disable this 10) – правило десять раз пропустит проверку (т.е. не будет участвовать в ней и никогда не выполнится) и затем включится.
onoff Имя_правила – инвертирует значение включенности и выключенности правила.
Если нужно включить/выключить свое правило – можно указывать ключевое слово this. А если нужно включить/выключить все правила можно указать ключевое слово all или звездочку *. (disable this 5ss) или (onoff all)
return – прекращает проверку все остальных правил. Нужно тогда, когда вы уже приняли решение, и дополнительные проверки не нужны.
weight Имя_правила Новое_Значение – изменение веса нужного правила, вместо значения можно ставить не только новый вес, но и увелечение или уменьшении оного. Например (weight Имя_правила +10) добавит к текущему весу правила еще десять очков.
invoke Имя_метода_или_данные [переменное число параметров через запятую] – служит для рассылки данных или вызова метода.
(invoke MessageBox "Привет от месседж бокса! Текущий сдвиг="+var_offsetX, "Заголовок "+var_conpo.Name)//пример вызова функции с двумя параметрами
На самом деле этот инвок методов не вызывает, а передает имя и переменное число параметров, тому методу, который вы подписали на событие Receive.
void rm_Receive(string FuncName, object[] parameters)//обрабатываем данные полученные от правил
{
switch (FuncName)
{
case "MessageBox":
if (parameters.Length == 2)
{
MessageBox.Show(parameters[0].ToString(), parameters[1].ToString());
}
else
{
MessageBox.Show(parameters[0].ToString(), "Сообщение");
}
break;
}
}
{
switch (FuncName)
{
case "MessageBox":
if (parameters.Length == 2)
{
MessageBox.Show(parameters[0].ToString(), parameters[1].ToString());
}
else
{
MessageBox.Show(parameters[0].ToString(), "Сообщение");
}
break;
}
}
Это безопаснее, позволяет не только методы вызывать, но и просто быстро передать нужные данные, а главное скрипты не смогут испортить программу, вызвав не то, что вы разрешили в вашем коде.
Так, теперь ты знаешь как составлять правила и пора рассказать тебе о том, какие же виды правил бывают.
1)Обычные, т.е. те что мы сейчас рассмотрели. Хочешь узнать, что делать если условия сошлись для нескольких правил сразу? Такое бывает и очень часто. Все правила, чьи условия оказались верными, переходят в зону победителей, где из них выбирается одно единственное, которое и выполнится. По каким же критериям оно выбирается?
а) Вес правила. Победителем будет признано то правило, чей вес будет больше.
б) Если вес равен считают кол-ва условий, победит то правило, у которого условий будет больше (оно более специализированное)
в) Если вес правил и кол-во условий равно, то считается количество обобщенных условий, т.е. те у которых может быть любой значение (Name ?). Выигрывает то правило, у кого обобщенных условий меньше.
2)Правило инициализации – правило, которое будет выполнено один раз, перед всеми правилами, служит для инициализации начальных фактов или переменных.
define init//начальная инициализация
[
if
(true null)//условие, которое всегда выполнится
then
(disable this)//что-то инициализируем
]
[
if
(true null)//условие, которое всегда выполнится
then
(disable this)//что-то инициализируем
]
Т.е. обычное правило, только с именем init и выполнится оно всего лишь один раз, перед всеми.
3)Правило по умолчанию. Сработает только тогда, когда не сработало не одно правило. Действует как default в switch.
define default//самое простое соеденение
[
enable
if
(conpo.ParentShape.Class ?)
(condest.ParentShape.Class ?)
then
(delete *)
(set var_offsetX 0)
]
[
enable
if
(conpo.ParentShape.Class ?)
(condest.ParentShape.Class ?)
then
(delete *)
(set var_offsetX 0)
]
Так, с типами правил разобрались. В основном будем работать с обычными правилам. Расскажу сейчас как с помощью обычных правил, можно делать таймер Вот пример правила, которое будет каждые 5 секунд включать/выключать другое правило, меняя логику программы.
define Timer1
[
enable
weight 100
repeatcount 0
if
(true null)
then
(onoff "Обычное Соединение ГоризонтальнойРЦ с горизонтальнойРЦ")//блокируем/разблокируем стыки между РЦ в течении 5 секунд
(disable this 5ss)
]
[
enable
weight 100
repeatcount 0
if
(true null)
then
(onoff "Обычное Соединение ГоризонтальнойРЦ с горизонтальнойРЦ")//блокируем/разблокируем стыки между РЦ в течении 5 секунд
(disable this 5ss)
]
Ну вот, теоретическая часть закончена, осталось лишь сказать о том, что скрипты поддерживают два вида комментариев, как в С++:
1)//однострочный комментарий
2)/* многострочный
комментарий*/
Немного практики.
Сейчас напишем небольшой примерчик, чтобы убедится, что это все работает. Сразу скажу, что правила обычно пишутся под готовые или наполовину готовые большие программы, но никак не программы под правила. Так что в этом примере не увидим всех преимуществ, но зато увидим как же все таки это функционирует.
Для начала создаем новое оконное приложение, подключаем библиотеку и конструкторе формы прописываем инициализацию:
RulespaceManager rsm;
public Form1()
{
rsm = new Parser("rules.txt", "MovingLogic").Parse();
rsm.Receive += new RulespaceManager.ReturnResult(rsm_Receive);
InitializeComponent();
}
public Form1()
{
rsm = new Parser("rules.txt", "MovingLogic").Parse();
rsm.Receive += new RulespaceManager.ReturnResult(rsm_Receive);
InitializeComponent();
}
Затем пишем метод приема сообщений от системы правил:
void rsm_Receive(string FuncName, object[] parameters)//прием данных с правил
{
switch (FuncName)
{
case "Window.X"://прием Х-координаты окна
this.Location =new Point(int.Parse(parameters[0].ToString()),this.Location.Y);
break;
case "Window.Y"://прием-координаты окна
this.Location = new Point(this.Location.X,int.Parse(parameters[0].ToString()));
break;
case "Window.Caption"://прием заголовка окна
this.Text = parameters[0].ToString();
break;
}
}
{
switch (FuncName)
{
case "Window.X"://прием Х-координаты окна
this.Location =new Point(int.Parse(parameters[0].ToString()),this.Location.Y);
break;
case "Window.Y"://прием-координаты окна
this.Location = new Point(this.Location.X,int.Parse(parameters[0].ToString()));
break;
case "Window.Caption"://прием заголовка окна
this.Text = parameters[0].ToString();
break;
}
}
Теперь по таймеру, например четыре раза в секунду мы будем вызывать метод который передаст системе нужные факты (координаты окна, длину окна и координаты мыши):
private void FactsMethod()//заполняем нужные факты
{
rsm.AddFact(new Fact("Window.X", this.Location.X.ToString()));
rsm.AddFact(new Fact("Window.Y", this.Location.Y.ToString()));
rsm.AddFact(new Fact("Window.Length", this.Size.Width.ToString()));
rsm.AddFact(new Fact("Mouse.X", MousePosition.X.ToString()));
rsm.AddFact(new Fact("Mouse.Y", MousePosition.X.ToString()));
rsm.CheckFactsMemoryByRules(false);
}
{
rsm.AddFact(new Fact("Window.X", this.Location.X.ToString()));
rsm.AddFact(new Fact("Window.Y", this.Location.Y.ToString()));
rsm.AddFact(new Fact("Window.Length", this.Size.Width.ToString()));
rsm.AddFact(new Fact("Mouse.X", MousePosition.X.ToString()));
rsm.AddFact(new Fact("Mouse.Y", MousePosition.X.ToString()));
rsm.CheckFactsMemoryByRules(false);
}
Все! В программе больше писать ничего не нужно. Теперь создадим в папке с бинарником файл rules.txt и запишем туда правила. Кстати, не забудь сохранить файл в кодировке utf-8!
Составим первое правило, оно будет отслеживать, не выходит ли окно за левый край экрана, и если выходит – то вернем координату к нулю.
define "Выход за левую границу экрана"
[
enable
weight 1
repeatcount 0
if
(Window.X <0)//если попытка выйти за пределы левого края
then
(delete *)
(invoke "Window.X" 0)
(return)
]
[
enable
weight 1
repeatcount 0
if
(Window.X <0)//если попытка выйти за пределы левого края
then
(delete *)
(invoke "Window.X" 0)
(return)
]
Создаем аналогичное правило для отслеживания выхода за верхнюю границу экрана:
define "Выход за верхнюю границу экрана"
[
enable
weight 1
repeatcount 0
if
(Window.Y <0)//если попытка выйти за пределы верхнего края
then
(delete *)
(invoke "Window.Y" 0)
(return)
]
[
enable
weight 1
repeatcount 0
if
(Window.Y <0)//если попытка выйти за пределы верхнего края
then
(delete *)
(invoke "Window.Y" 0)
(return)
]
Теперь накодим два правила, которые будут срабатывать. если курсор мышки будет
выходить за пределы окна по Х-координате, окно будет ползти к курсору
define "Выход за левую границу окна"
[
enable
weight 1
repeatcount 0
if
(Mouse.X Window.X+Window.Length)//если попытка выйти за пределы окна по Х
then
(invoke "Window.X" Window.X+40)
(delete *)
(return)
]
[
enable
weight 1
repeatcount 0
if
(Mouse.X Window.X+Window.Length)//если попытка выйти за пределы окна по Х
then
(invoke "Window.X" Window.X+40)
(delete *)
(return)
]
Все эти правила сработают только при условиях, а сейчас создадим правило, которое будет всегда отображать текущие координаты окна и мыши в заголовке формы нашего приложения. Естественно, чтобы оно срабатывало всегда, и даже тогда. когда срабатывают другие правила – то придется увеличить ей вес:
define "Печатаем статистику"
[
enable
weight 2
repeatcount 0
if
(true null)
then
(invoke "Window.Caption" "Координаты мыши ["+Mouse.X+","+Mouse.Y+"] Координаты окна ["+Window.X+","+Window.Y+"]")
]
[
enable
weight 2
repeatcount 0
if
(true null)
then
(invoke "Window.Caption" "Координаты мыши ["+Mouse.X+","+Mouse.Y+"] Координаты окна ["+Window.X+","+Window.Y+"]")
]
А чтобы было еще веселей, напишем правило таймер, которое каждые десять секунд будет то включать перемещения за курсором, то отключать:
define Timer1
[
enable
weight 200
if
(true null)
then
(onoff "Выход за левую границу окна")
(onoff "Выход за правую границу окна")
(disable this 10ss)
]
[
enable
weight 200
if
(true null)
then
(onoff "Выход за левую границу окна")
(onoff "Выход за правую границу окна")
(disable this 10ss)
]
Теперь запустив приложение можно наблюдать постоянное изменение заголовка, если меняются координаты мыши/окна и перемещение за мышкой, которое, то включитс, на 10 сек, то отключится, тоже на 10 сек. А если поставить stack 0, то скрипты отключатся и будет обычное окно, без поведения и заголовка с координатами.
Вот теперь все, пришло время подвести итоги сегодняшнего урока. Попробую перечислить основные преимущества включения правил в программные продукты:
1)Возможность изменения/добавления/удаления логики программы без затрагивания исходного кода.
2)Правильно составленные правила избавляют код от кучи вложенных if’ов и делают логику более прозрачной.
3) Изменение приоритета выполнения логических частей.
4)Включение/отключение логических частей по времени или условию.
5)Три вида правил позволяют строить достаточно гибкие конструкции.
6)Простота изучения и использования.
7)Возможность полного отключения сразу всех правил, ПО будет работать, будто вы и не внедряли никаких скриптов (для этого достаточно stack 0 написать).
А теперь минусы системы:
1)Система правил подойдет далеко не для всех решений. У нее очень узкий круг задач.
2)Систему писал только я, поэтому она не самая производительная и удобная.
3)Возможность присутствия скрытых недоработок или затаившихся ошибок.
4)Еще не очень доработанный синтаксис при работе с математикой.
Вообщем вывод таков – узкоспециализированная система со своими плюсами и минусами, но возможно именно тебе она и облегчит жизнь.
P.S. Если наберется достаточное кол-во желающих, то я могу написать статью как я делал эту библиотечку, чтоб ты знал, как же такое чудо-юдо сотворить
your_code_your_rules.zip [71.22 Kb] (cкачиваний: 11)
- Просмотров: 1705
Версия для печати
#1
DeXPeriX |
DeXPeriX |
Дата публикации: 8 августа 2009 11:45 | ICQ: 606986
цитировать
цитировать
#2
John Frost |
John Frost | 
ДА, началось
Ну поехали по порядку:
1)"Как я уже говорил, свой интерпретируемый язык не нужен - есть луа. На крайняк, правила и в XML'e можно хранить, который обрабатывается стандартными средствами"
Вообще кодить свои программы не нужно - уже все сделано до нас.
Да пофиг на чем писать, язык тут не главное, тут главное правила и система их обработки. Юзать язык, который расчитан на широкий круг задач в узкоспециализированных целях - полная ерундень. Интерпретатор на 150 строчек кода здесь, и его написание дело часа. А подключать и изучать этих монстров смысла нет. Это просто не выгодно по времени.
2)правила удобнее было бы делать на Prolog
Ну, или другом ИИ-ориентированном языке...
Пролог надо учить, на нем надо мыслить. Хорошее изучение языка и его средств дело не одного месяца. То что написал я - достаточно простое и легкое в освоении решение, и главное Я ЗНАЮ КАК ИЗНУТРИ ЭТО РАБОТАЕТ, я знаю каждый шаг и каждое действие.
Ну поехали по порядку:
1)"Как я уже говорил, свой интерпретируемый язык не нужен - есть луа. На крайняк, правила и в XML'e можно хранить, который обрабатывается стандартными средствами"
Вообще кодить свои программы не нужно - уже все сделано до нас.
Да пофиг на чем писать, язык тут не главное, тут главное правила и система их обработки. Юзать язык, который расчитан на широкий круг задач в узкоспециализированных целях - полная ерундень. Интерпретатор на 150 строчек кода здесь, и его написание дело часа. А подключать и изучать этих монстров смысла нет. Это просто не выгодно по времени.
2)правила удобнее было бы делать на Prolog
Пролог надо учить, на нем надо мыслить. Хорошее изучение языка и его средств дело не одного месяца. То что написал я - достаточно простое и легкое в освоении решение, и главное Я ЗНАЮ КАК ИЗНУТРИ ЭТО РАБОТАЕТ, я знаю каждый шаг и каждое действие.
Дата публикации: 8 августа 2009 12:35 | ICQ: 488251
цитировать
цитировать
#3
DeXPeriX |
DeXPeriX | 
1) Lua... Сам не знаю, но пиарю на каждом углу :) Она далеко не монстр. Хотя в основном юзают в играх. Но здесь как раз таки задача сходная - рисование ЖД-путей.
Что луа, что пролог - освоить нужно всего один раз, зато потом можно использовать всю жизнь
>Интерпретатор на 150 строчек кода здесь, и его написание дело часа
Откуда знаешь, что его хватит? Потом может понадобится новый функционал - добавится новый геморрой.
Если основной целью было показать экспертную систему - почему так мало написал непосредственно про неё? Обычно пишется краткое введение, много и подробно теории, и лишь потом закрепление на практике. У тебя же в основном рассмотрена именно твоя реализация
2) Пролог - почти синоним дискретной математики. Нужно всего-лишь уметь думать математически (особенно важна теория множеств), а синтаксис - мелочи.
Что луа, что пролог - освоить нужно всего один раз, зато потом можно использовать всю жизнь
>Интерпретатор на 150 строчек кода здесь, и его написание дело часа
Откуда знаешь, что его хватит? Потом может понадобится новый функционал - добавится новый геморрой.
Если основной целью было показать экспертную систему - почему так мало написал непосредственно про неё? Обычно пишется краткое введение, много и подробно теории, и лишь потом закрепление на практике. У тебя же в основном рассмотрена именно твоя реализация
2) Пролог - почти синоним дискретной математики. Нужно всего-лишь уметь думать математически (особенно важна теория множеств), а синтаксис - мелочи.
Дата публикации: 8 августа 2009 12:47 | ICQ: 606986
цитировать
цитировать
#4
John Frost |
John Frost | 
И вообще, я сделал вещь под наши конкретные нужды. Мне сказали придумать небольшую вещицу чтобы через пару кварталов в магазин съездить по быстренькому, я сделал велосипед, а ты предлагаешь ездить на огромном радиоуправляемом 20тонном танке с ионными пушками:-)
Дата публикации: 8 августа 2009 12:48 | ICQ: 488251
цитировать
цитировать
#5
Vanger |
Vanger | 
Dexperix, как всегда
еще Фитзимы не хватает
помните?
http://coderszone.info/339-sam-sebe-interpretator.html
http://coderszone.info/398-sam-sebe-interpretator.-chast-2..
html
тот же холивар был
только Джонни работает одним из ведущих программеров у себя и уже дофига полезного написал. а ты ?
еще Фитзимы не хватает
помните?
http://coderszone.info/339-sam-sebe-interpretator.html
http://coderszone.info/398-sam-sebe-interpretator.-chast-2..
html
тот же холивар был
только Джонни работает одним из ведущих программеров у себя и уже дофига полезного написал. а ты ?
Дата публикации: 8 августа 2009 18:25 | ICQ: --
цитировать
цитировать
#7
_NuClear |
_NuClear | 
Джони прав да и каждый делает как эму удобней
Дата публикации: 9 августа 2009 13:19 | ICQ: 958
цитировать
цитировать
#8
Джоно Фросто (с работы) |
Джоно Фросто (с работы) | Ппц, уже 7 комментов, споры и полемика, но никто, судя по счетчику, не скачал еще не разу исходник :-)
Дата публикации: 10 августа 2009 15:14 | ICQ: --
цитировать
цитировать
#9
featZima |
featZima | 
А вот и я =) И я в очередной раз придерживаюсь того, что писать свой интерпретатор - это пустая трата времени. Проект сделан на .NET, поэтому логичнее было бы подключить IronPython, и что мы получим в результате?
- минимум времени для подключение интерпретатора;
- мощный язык с поддержкой ООП и обратных вызовов;
- язык, который имеют хорошую документацию и признан во всём мире (пожалей людей, которые будут пользоваться твоим чадом)
- стабильность, так как IronPython проверен временем;
- скорость работы, обычный Python обделывает большинство интерпретируемых языков, что уж говорить о dotNET
p.s. а вообще я согласен, иногда проще написать свой велосипед, чем учиться кататься на чужих. но крупные промышленные системы это не тот случай.
p.s.2. скачал, посмотрел, нашёл ошибку, координаты мышки _всегда_ совпадают. исправь пожалуйста ;)
- минимум времени для подключение интерпретатора;
- мощный язык с поддержкой ООП и обратных вызовов;
- язык, который имеют хорошую документацию и признан во всём мире (пожалей людей, которые будут пользоваться твоим чадом)
- стабильность, так как IronPython проверен временем;
- скорость работы, обычный Python обделывает большинство интерпретируемых языков, что уж говорить о dotNET
p.s. а вообще я согласен, иногда проще написать свой велосипед, чем учиться кататься на чужих. но крупные промышленные системы это не тот случай.
p.s.2. скачал, посмотрел, нашёл ошибку, координаты мышки _всегда_ совпадают. исправь пожалуйста ;)
Дата публикации: 17 августа 2009 21:23 | ICQ: 436090461
цитировать
цитировать
#10
featZima |
featZima | 
грязная SEO оптимизация =)
Дата публикации: 17 августа 2009 21:34 | ICQ: 436090461
цитировать
цитировать
#11
Джоно Фросто [с работы] |
Джоно Фросто [с работы] | Ну начнемс :-)
featZima, как я уже и говорил DeXPeriX'у, интерпретатор здесь не играет никакой роли толком, он служит лишь для записи правил, и нафиг никому не сдались здесь прелести ООП :-) Это во первых. А во вторых, скажи-ка мне любезнейший, каким образом я бы интерпретировал IronPython код в свои правила? Интерпретировать то я могу, только тогда интерпретатор питона не нужен и мы снова получаем свой интерпретатор.
Ну и в третьих, как ты в своем питоне поменяешь приоритеты выполнения функциям или отключишь их на 20 секунд к примеру?:) Все это конечно можно реализовать, но через большую жопу. Повторяю, для тех кто в поезде, здесь я сделал и показал систему обработки правил (читай почти экспертная система), интерпретатор лишь для удобства записи, он просто заполняет массивы с правилами для движка. Учитесь смотреть внутрь, а не на поверхность :-)
P.S. и правда координаты одинаковы, т.к. я написал Mouse.X два раза вместо Mouse.X и Mouse.Y
featZima, как я уже и говорил DeXPeriX'у, интерпретатор здесь не играет никакой роли толком, он служит лишь для записи правил, и нафиг никому не сдались здесь прелести ООП :-) Это во первых. А во вторых, скажи-ка мне любезнейший, каким образом я бы интерпретировал IronPython код в свои правила? Интерпретировать то я могу, только тогда интерпретатор питона не нужен и мы снова получаем свой интерпретатор.
Ну и в третьих, как ты в своем питоне поменяешь приоритеты выполнения функциям или отключишь их на 20 секунд к примеру?:) Все это конечно можно реализовать, но через большую жопу. Повторяю, для тех кто в поезде, здесь я сделал и показал систему обработки правил (читай почти экспертная система), интерпретатор лишь для удобства записи, он просто заполняет массивы с правилами для движка. Учитесь смотреть внутрь, а не на поверхность :-)
P.S. и правда координаты одинаковы, т.к. я написал Mouse.X два раза вместо Mouse.X и Mouse.Y
Дата публикации: 18 августа 2009 10:49 | ICQ: --
цитировать
цитировать
#12
featZima |
featZima | 
Собственно тут два варианта)
1 - машина Тюринга, все правила выродить через простую таблицу, которую можно будет быстро обрабатывать, удовлетворив всем твоим требованиям. Городить для этого свой формат хранения _табличных_ данных глупо, а ещё глупее выражать это в качестве языка. Есть тот же xml, cvs, Json и много-много другого и готового.
2 - всё таки интерпретатор. И тут ООП выступает в качестве неотъемлемой части. "Правило", как таковое, выражаем через базовый объект, через потомков выражаем специфические правила. Все полученные объекты собираем в цепочку, на вход которой поступает начальное состояние системы, на выходу соответственно получим конечное.
p.s. Дискутировать можно долго, но кто-то великий сказал "Keep It Simple, Stupid!"
p.s.2. Убил 3 часа времени и реализовал версию с интерпретатором по твоему примеру. мне кажется куда лаконичнее, а главное быстрее)
http://coderszone.info/forum/index.php?showtopic=442
p.s.3. И теперь вопрос к тебе: Чем предложенные тобою метод лучше тех которые описал я (хотя на самом деле их уже давно описали до меня и даже вывели большие мат теории)?
1 - машина Тюринга, все правила выродить через простую таблицу, которую можно будет быстро обрабатывать, удовлетворив всем твоим требованиям. Городить для этого свой формат хранения _табличных_ данных глупо, а ещё глупее выражать это в качестве языка. Есть тот же xml, cvs, Json и много-много другого и готового.
2 - всё таки интерпретатор. И тут ООП выступает в качестве неотъемлемой части. "Правило", как таковое, выражаем через базовый объект, через потомков выражаем специфические правила. Все полученные объекты собираем в цепочку, на вход которой поступает начальное состояние системы, на выходу соответственно получим конечное.
p.s. Дискутировать можно долго, но кто-то великий сказал "Keep It Simple, Stupid!"
p.s.2. Убил 3 часа времени и реализовал версию с интерпретатором по твоему примеру. мне кажется куда лаконичнее, а главное быстрее)
http://coderszone.info/forum/index.php?showtopic=442
p.s.3. И теперь вопрос к тебе: Чем предложенные тобою метод лучше тех которые описал я (хотя на самом деле их уже давно описали до меня и даже вывели большие мат теории)?
Дата публикации: 18 августа 2009 17:59 | ICQ: 436090461
цитировать
цитировать
#13
John Frost |
John Frost | 
О, да вы батенька не сдаетесь?
Ну да, давай еще сразу в двоичном коде писать :-) Всеж все равно в них в конечном итоге переводиться. В каком формате хранить данные - это уже мой выбор, как хочу так и храню.
И этот человек мне говорит про то, что надо писать проще
Убить 3 часа на вот эти 8 строк кода - это конечно жесть.
if ipyMessage.mousePosition.X < ipyMessage.winPosition.X:
ipyMessage.offLeft = True
if ipyMessage.mousePosition.Y < ipyMessage.winPosition.Y:
ipyMessage.offTop = True
if ipyMessage.mousePosition.X > ipyMessage.winPosition.X + ipyMessage.winSize.X:
ipyMessage.offRight = True
if ipyMessage.mousePosition.Y > ipyMessage.winPosition.Y + ipyMessage.winSize.Y:
ipyMessage.offDown = True
Пошутили и хватит, а теперь давай серьезно:
1)Правильно составленные правила избавляют код от кучи вложенных if’ов и делают логику более прозрачной.
При двух и более условий, тебе придется делать множество вложенных if'ов, и потом при добавлении или удалении логики, придется в это куче копаться. У меня в системе до 25-30 условий, ты вообще можешь представить себе конструкцию из стольких вложенных условий? написать можно, но легко модернизировать - нельзя. Я добавляю/удаляю правила из системы не думая о других правилах, а тебе с этими ифами придется об этом думать.
2) Изменение приоритета выполнения логических частей.
3)Включение/отключение логических частей по времени или условию.
Я бы посмотрел как ты это у себя бы реализовал, сколько бы ты нервов тратил и времени:-)
Не спорю, все это можно реализовать вообще без скриптов, в самом шарпе к примеру, и я так поначалу и делал, но после 40 вложенных условий, которые еще и меняются постоянно начинаешь любить правила всей душой. На опыте я убедился, что правила легче модернизировать, чем копаться в куче условий.
P.S. раз все так пристали к скорости интерпретатора, скрипт с правилами парсится раз, при загрузке, заполняет правила и все, интерпретатора больше нет, дальше работает движок обработки правил. На работе я создавал 850 объектов, у каждого по 12 правил, проверки идут каждые полсекунды, скорость хорошая.
1 - машина Тюринга, все правила выродить через простую таблицу, которую можно будет быстро обрабатывать, удовлетворив всем твоим требованиям. Городить для этого свой формат хранения _табличных_ данных глупо, а ещё глупее выражать это в качестве языка. Есть тот же xml, cvs, Json и много-много другого и готового.
Ну да, давай еще сразу в двоичном коде писать :-) Всеж все равно в них в конечном итоге переводиться. В каком формате хранить данные - это уже мой выбор, как хочу так и храню.
2 - всё таки интерпретатор. И тут ООП выступает в качестве неотъемлемой части. "Правило", как таковое, выражаем через базовый объект, через потомков выражаем специфические правила. Все полученные объекты собираем в цепочку, на вход которой поступает начальное состояние системы, на выходу соответственно получим конечное.
И этот человек мне говорит про то, что надо писать проще
p.s.2. Убил 3 часа времени и реализовал версию с интерпретатором по твоему примеру. мне кажется куда лаконичнее, а главное быстрее)
http://coderszone.info/forum/index.php?showtopic=442
http://coderszone.info/forum/index.php?showtopic=442
Убить 3 часа на вот эти 8 строк кода - это конечно жесть.
if ipyMessage.mousePosition.X < ipyMessage.winPosition.X:
ipyMessage.offLeft = True
if ipyMessage.mousePosition.Y < ipyMessage.winPosition.Y:
ipyMessage.offTop = True
if ipyMessage.mousePosition.X > ipyMessage.winPosition.X + ipyMessage.winSize.X:
ipyMessage.offRight = True
if ipyMessage.mousePosition.Y > ipyMessage.winPosition.Y + ipyMessage.winSize.Y:
ipyMessage.offDown = True
Пошутили и хватит, а теперь давай серьезно:
1)Правильно составленные правила избавляют код от кучи вложенных if’ов и делают логику более прозрачной.
При двух и более условий, тебе придется делать множество вложенных if'ов, и потом при добавлении или удалении логики, придется в это куче копаться. У меня в системе до 25-30 условий, ты вообще можешь представить себе конструкцию из стольких вложенных условий? написать можно, но легко модернизировать - нельзя. Я добавляю/удаляю правила из системы не думая о других правилах, а тебе с этими ифами придется об этом думать.
2) Изменение приоритета выполнения логических частей.
3)Включение/отключение логических частей по времени или условию.
Я бы посмотрел как ты это у себя бы реализовал, сколько бы ты нервов тратил и времени:-)
Не спорю, все это можно реализовать вообще без скриптов, в самом шарпе к примеру, и я так поначалу и делал, но после 40 вложенных условий, которые еще и меняются постоянно начинаешь любить правила всей душой. На опыте я убедился, что правила легче модернизировать, чем копаться в куче условий.
P.S. раз все так пристали к скорости интерпретатора, скрипт с правилами парсится раз, при загрузке, заполняет правила и все, интерпретатора больше нет, дальше работает движок обработки правил. На работе я создавал 850 объектов, у каждого по 12 правил, проверки идут каждые полсекунды, скорость хорошая.
Дата публикации: 18 августа 2009 22:42 | ICQ: 488251
цитировать
цитировать
#14
featZima |
featZima | 
1) Начнём с того, что 3 часа мне понадобилось не для того чтобы написать 4 строчки на питоне, а для того чтобы написать моё первое приложение на С# с подключением IronPython... честно говоря, я час вчехлял как подключать внешние блоки =) Ещё час ушёл, чтобы разобраться как перехватывать движение мышки, а не просто проверять 4 раза в секунду ;) заметь что мой пример работает шустрее твоего...
2) мой пример, только ради того, чтобы показать лёгкость подключение готового скриптового движка и скорость его работы... Мне почему то кажется что у меня это хорошо получилось ^^ 8 строк а делает всё то же, что и твой пример, но быстрее....
+ подстветка исходного кода - мелочь, а приятно...
3) а теперь самое интересное, 3 условия (приоритет, отключение и без if-ов) -- я сделал пример использования скриптов, а не законченные колёса к твоему проекту. А чтобы заменить твою писанину на нормальный код, я и описал 2 готовых варианта (там чуть выше) -- машина Тюринга, и цепочки объеков на интерпретируемом языке. Понятно, что на словах не очень понятно, но если ты приведёшь жизненный пример, то я с лёгкостью реализую любой из двух вариантов, не используя свои псевдо-скриптовые движки ....
p.s. жду жизненный пример...
p.s.2. не хочу никого обидеть, просто хочется отстоять свою точку зрения о "правильном" коде... в данном случае - написание своих псевдо-скриптовых языков - неуместно по моему скромному мнению...
p.s.3. по поводу if-ов можешь сам посмотреть http://floomby.ru/content/4p6xloBo06/ Единственное что отличает твой язык, от истинно скриптового наличия приоритетов и выкл/вкл, что легко исправляется цепочками объектов. Ещё раз хочу заметить что любой объект в цепочке может выполнять _любые_ действия доступные .NET классу, а приоритет легко меняется перестановкой правил в цепочке )
p.s.4. вот простенький пример как на самом деле можно было переписать твои правила на скриптовом языке... Всё это можно делать с подсветкой синтаксиса и код гораздо прозрачнее... плюс любое из правил может себя легко трансмутировать =)
http://floomby.ru/content/mRXJ684250/
2) мой пример, только ради того, чтобы показать лёгкость подключение готового скриптового движка и скорость его работы... Мне почему то кажется что у меня это хорошо получилось ^^ 8 строк а делает всё то же, что и твой пример, но быстрее....
+ подстветка исходного кода - мелочь, а приятно...
3) а теперь самое интересное, 3 условия (приоритет, отключение и без if-ов) -- я сделал пример использования скриптов, а не законченные колёса к твоему проекту. А чтобы заменить твою писанину на нормальный код, я и описал 2 готовых варианта (там чуть выше) -- машина Тюринга, и цепочки объеков на интерпретируемом языке. Понятно, что на словах не очень понятно, но если ты приведёшь жизненный пример, то я с лёгкостью реализую любой из двух вариантов, не используя свои псевдо-скриптовые движки ....
p.s. жду жизненный пример...
p.s.2. не хочу никого обидеть, просто хочется отстоять свою точку зрения о "правильном" коде... в данном случае - написание своих псевдо-скриптовых языков - неуместно по моему скромному мнению...
p.s.3. по поводу if-ов можешь сам посмотреть http://floomby.ru/content/4p6xloBo06/ Единственное что отличает твой язык, от истинно скриптового наличия приоритетов и выкл/вкл, что легко исправляется цепочками объектов. Ещё раз хочу заметить что любой объект в цепочке может выполнять _любые_ действия доступные .NET классу, а приоритет легко меняется перестановкой правил в цепочке )
p.s.4. вот простенький пример как на самом деле можно было переписать твои правила на скриптовом языке... Всё это можно делать с подсветкой синтаксиса и код гораздо прозрачнее... плюс любое из правил может себя легко трансмутировать =)
http://floomby.ru/content/mRXJ684250/
Дата публикации: 18 августа 2009 23:04 | ICQ: 436090461
цитировать
цитировать
#15
Vanger |
Vanger | 
флудеры. ну как всегда. такие статьи - всегда горячая тема
Дата публикации: 19 августа 2009 14:01 | ICQ: --
цитировать
цитировать
#16
featZima |
featZima | 
То, что я стараюсь писать качественный код, не делает меня флудером ;)
Дата публикации: 19 августа 2009 14:47 | ICQ: 436090461
цитировать
цитировать
#17
Джоно Фросто |
Джоно Фросто | Короче, завершу холивар, иначе это будет идти вечно:
1)Для любой цели существует множество способов рещения, и то, что оптимально для одного, неприемлемо для другого. На то мы все и разные.
Для людей, которые прицепились к примеру, ребята, это не пример настоящей программы, это пример что мои правила работают. К сожалению я не могу написать для примера большую экспертную систему, чтобы вы ощутили приемущества правил. Поищите пожалуйста информацию о системах, основанных на правилах.
2) Я показал свой способ решения, сделал свой движок обработки правил и язык для их описания. Я никого не заставляю их юзать, и не говорю что это идеал. И если внимательно читать статью, то можно было бы заметить вот такие строчки:
3)И насчет качественного кода.... Это лично к featZime - давай оперировать действительными фактами, говорить о качественном коде может человек написавший что-то более менее серьезное и большое. Извини конечно, но если ты написал в хорошем стиле 200-300 строк, причем абсолютно не сложного кода, это не делает из тебя гуру качества. Не надо говорить мне, что я выбираю неправильные технологии и качество написания кода. У меня уже есть готовые, большие и легко расширяемые продукты, и это уже говорит о том, что я не пишу абы как. Просто очень интересно слушать о том, как надо правильно писать, от человека, который не показал еще ничего серьезного. Между теорией и практикой большая пропасть. Наше с тобой общение сейчас очень похоже на эту картинку http://cs514.vkontakte.ru/u1092225/3790906/x_bab6746e.jpg
1)Для любой цели существует множество способов рещения, и то, что оптимально для одного, неприемлемо для другого. На то мы все и разные.
"но если ты приведёшь жизненный пример, то я с лёгкостью реализую любой из двух вариантов, не используя свои псевдо-скриптовые движки ...."
Для людей, которые прицепились к примеру, ребята, это не пример настоящей программы, это пример что мои правила работают. К сожалению я не могу написать для примера большую экспертную систему, чтобы вы ощутили приемущества правил. Поищите пожалуйста информацию о системах, основанных на правилах.
2) Я показал свой способ решения, сделал свой движок обработки правил и язык для их описания. Я никого не заставляю их юзать, и не говорю что это идеал. И если внимательно читать статью, то можно было бы заметить вот такие строчки:
А теперь минусы системы:
1)Система правил подойдет далеко не для всех решений. У нее очень узкий круг задач.
2)Систему писал только я, поэтому она не самая производительная и удобная.
3)Возможность присутствия скрытых недоработок или затаившихся ошибок.
4)Еще не очень доработанный синтаксис при работе с математикой.
1)Система правил подойдет далеко не для всех решений. У нее очень узкий круг задач.
2)Систему писал только я, поэтому она не самая производительная и удобная.
3)Возможность присутствия скрытых недоработок или затаившихся ошибок.
4)Еще не очень доработанный синтаксис при работе с математикой.
3)И насчет качественного кода.... Это лично к featZime - давай оперировать действительными фактами, говорить о качественном коде может человек написавший что-то более менее серьезное и большое. Извини конечно, но если ты написал в хорошем стиле 200-300 строк, причем абсолютно не сложного кода, это не делает из тебя гуру качества. Не надо говорить мне, что я выбираю неправильные технологии и качество написания кода. У меня уже есть готовые, большие и легко расширяемые продукты, и это уже говорит о том, что я не пишу абы как. Просто очень интересно слушать о том, как надо правильно писать, от человека, который не показал еще ничего серьезного. Между теорией и практикой большая пропасть. Наше с тобой общение сейчас очень похоже на эту картинку http://cs514.vkontakte.ru/u1092225/3790906/x_bab6746e.jpg
Дата публикации: 19 августа 2009 16:10 | ICQ: --
цитировать
цитировать
#18
featZima |
featZima | 
... мы пишем кривой код и мним себя богами, но даже это не даёт право вмешиваться в чужие мысли ...
специально для Vanger-а: "только Джонни работает одним из ведущих программеров у себя и уже дофига полезного написал. а ты ?"
это оскорбление... но свои комментарии ты не удаляешь... как то я устраивал мини-соревнование, чья программа быстрее пропарсит текстовый файл... и никто из вас, написавших много полезных и больших проектов, не смог "побить" мою маленькую программу на Делфи... так неужели ты считаешь себя вправе редактировать мои комментарии?...
специально для Vanger-а: "только Джонни работает одним из ведущих программеров у себя и уже дофига полезного написал. а ты ?"
это оскорбление... но свои комментарии ты не удаляешь... как то я устраивал мини-соревнование, чья программа быстрее пропарсит текстовый файл... и никто из вас, написавших много полезных и больших проектов, не смог "побить" мою маленькую программу на Делфи... так неужели ты считаешь себя вправе редактировать мои комментарии?...
Дата публикации: 19 августа 2009 23:23 | ICQ: 436090461
цитировать
цитировать
#19
featZima |
featZima | 
Да, я написал 50 строк, допишу ещё 50 и будет система по всем параметрам превосходящая твою (скорость, расширяемость, документированность, понятность для остальных). Я пишу говно-код:? =\
Дата публикации: 20 августа 2009 00:23 | ICQ: 436090461
цитировать
цитировать
#20
Vanger |
Vanger | 
чтобы никто не обижался:
featZima, John Frost забанены на неделю
причина бана: флуд и оскорбления других участников. не надо перемещать свои личные эмоции на сайт, которые читает много других людей
правила здесь: http://coderszone.info/forum/index.php?s=1b5a88b0a06ece8070e
5f3733b5fb670&act=boardrules
написаны они не идеально, но это официальные правила. со временем доработаем
featZima, John Frost забанены на неделю
причина бана: флуд и оскорбления других участников. не надо перемещать свои личные эмоции на сайт, которые читает много других людей
правила здесь: http://coderszone.info/forum/index.php?s=1b5a88b0a06ece8070e
5f3733b5fb670&act=boardrules
написаны они не идеально, но это официальные правила. со временем доработаем
Дата публикации: 20 августа 2009 01:13 | ICQ: --
цитировать
цитировать
#21
Джоно Фросто В бане |
Джоно Фросто В бане | Зашибись, забанили админа :-)
Алгоритмы поиска и сортировки изобретены до тебя, так что не твоя заслуга. И не говори что это был твой алгоритм, исходник ты так и не показал, а я свой отдал _NuClear'у, когда он попросил.
Вот тот спор кстати http://coderszone.info/forum/index.php?showtopic=68
как то я устраивал мини-соревнование, чья программа быстрее пропарсит текстовый файл... и никто из вас, написавших много полезных и больших проектов, не смог "побить" мою маленькую программу на Делфи... так неужели ты считаешь себя вправе редактировать мои комментарии?..
.Алгоритмы поиска и сортировки изобретены до тебя, так что не твоя заслуга. И не говори что это был твой алгоритм, исходник ты так и не показал, а я свой отдал _NuClear'у, когда он попросил.
Вот тот спор кстати http://coderszone.info/forum/index.php?showtopic=68
Дата публикации: 20 августа 2009 08:17 | ICQ: --
цитировать
цитировать
#22
Vanger |
Vanger | 
ребята, если ЦМС не работает как надо и вы по какойто причине не забанены, это не значит что все отменяется
на выходных разберусь с проблемой
если очень хочется - можно писать с не зареганного юзера, как в последнем посте Джонни
но за повторный флуд забаню на серваке подсеть айпи адресов ваших провайдеров. уже больше чем на неделю. думаю никто не хотчет сидеть на сайте из под прокси
p.s. давайте жить дружно и соблюдать правила
(с) Злобный Админ
на выходных разберусь с проблемой
если очень хочется - можно писать с не зареганного юзера, как в последнем посте Джонни
но за повторный флуд забаню на серваке подсеть айпи адресов ваших провайдеров. уже больше чем на неделю. думаю никто не хотчет сидеть на сайте из под прокси
p.s. давайте жить дружно и соблюдать правила
(с) Злобный Админ
Дата публикации: 21 августа 2009 23:30 | ICQ: --
цитировать
цитировать
#24
Vanger |
Vanger | 
Действие бана для Джонни и Фитзимы закончилось
Дата публикации: 27 августа 2009 10:52 | ICQ: --
цитировать
цитировать
#25
Polodin |
Polodin | Пиво лучше пить холодным, а водку ледяной)
Дата публикации: 13 октября 2009 01:05 | ICQ: --
цитировать
цитировать



И второе, правила удобнее было бы делать на Prolog