Вычислитель правил булевой логики
-
05-07-2019 - |
Вопрос
По сути, у меня есть показанный опрос, и люди отвечают на вопросы, очень похожие на тест, и есть разные пути, пока это довольно просто, но я хотел сделать это более динамичным, чтобы у меня могло быть общее правило для теста со всеми путями, чтобы упростить работу оценщика в настоящее время я просто разрешаю И, и каждое ИЛИ, по сути, становится другим правилом в наборе,
QuestionID, затем я формирую кучу правил И примерно так
<rule id="1">
<true>
<question ID=123>
<question ID=124>
</true>
<false>
<question ID=127>
<question ID=128>
</false>
</rule>
<rule id="2"><true>
<question ID=123>
<question ID=125>
</true>
<false>
<question ID=127>
</false>
</rule>
это правило 1 гласит, что если на вопросы 123 и 124 даны верные ответы, а 127, 128 - ложные, они проходят.ИЛИ (правило 2), если 123 и 125 являются истинными, а 127 - ложными, они также проходят.Это становится утомительным, если существует много комбинаций, поэтому я хочу реализовать OR в логике, я просто не уверен, какой наилучший подход подходит для этой проблемы.
Я думаю, что механизм правил слишком сложен, должен быть более простой способ, возможно, построение графика, как в LINQ, а затем оценка, чтобы увидеть, проходят ли они,
Спасибо!
-- не специализируюсь в compsci.
Решение
Это не должно быть сложно:вы уже проделали большую часть пути, поскольку ваши элементы and эффективно реализуют правило AND-type.Я бы ввел элемент, который может содержать элементы and.
В вашей власти, вы могли бы:
- Класс на основе правил с методом "public abstract bool Evaluate()"
- Классы TrueRule, FalseRule и OrRule, которые содержат списки объектов базы правил
- Класс QuestionRule, который ссылается на конкретный вопрос
Вы бы реализовали метод Evaluate для каждого из них следующим образом:
- Истинное правило: возвращает true только в том случае, если все содержащиеся правила возвращают true из Evaluate
- Фальсерула: возвращает true только в том случае, если все содержащиеся правила возвращают false из Evaluate
- Или править: возвращает true, если хотя бы одно из содержащихся правил возвращает true из Evaluate
- Правило вопроса: возвращает ответ на исходный вопрос
Эта иерархия классов реализует простое абстрактное синтаксическое дерево (AST).LINQ в форме System.Выражения.Класс Expression выполняет практически то же самое, но полезно написать свой собственный, если не очевидно, как все сочетается друг с другом.
Другие советы
Если вы используете надлежащий механизм правил, который поддерживает вывод, он будет более эффективным и расширяемым.
Взгляните на http://www.flexrule.com который представляет собой гибкий, расширяемый механизм создания правил, поддерживающий три типа правил.Правила процедуры, вывода и потока правил могут быть выведены извне из вашего приложения и выполняться с использованием этой платформы.
Я не уверен, что полностью понимаю проблему, которую вы пытаетесь решить, но вы могли бы использовать простой XPath, чтобы получить идентификатор:
Это дало бы вам все "истинные" идентификаторы, где идентификатор правила = 1:/правило[@id="1"]/истинно//@ID
То же, что и выше, только это дает вам ложные идентификаторы:/правило[@id="1"]/ложное//@ID
Наконец, ссылка на введение в XPath в .NET http://www.developer.com/xml/article.php/3383961
Удачи
Я бы предложил помещать ответы на вопросы, а не использовать true
и false
чтобы сгруппировать вопросы.Я думаю, что это облегчает чтение XML, что является спорным.Что не подлежит обсуждению, так это то, что это позволяет оценить question
элемент независимо, т.е.без какого-либо знания контекста, в котором вы пытаетесь это оценить.Это упрощает код.
Я бы также взял страницу из XML Schema и реализовал вашу логику OR как choice
элемент.A choice
элемент является истинным, если какой-либо из его дочерних элементов является истинным.Вы можете, конечно, вложить их в гнездо:
<rule id="1">
<question id="123" answer="true" />
<question id="124" answer="false" />
<choice id="1">
<question id="125" answer='true' />
<choice id="2">
<question id="126" answer='false' />
<question id="127" answer='false' />
</choice>
</choice>
</rule>
Это оставляет вам четыре довольно простых метода для реализации, каждый из которых используется предыдущим:
bool GetProvidedAnswer(int questionID)
bool IsQuestionCorrect(XmlElement question)
bool IsChoiceCorrect(XmlElement choice)
bool IsRuleSatisfied(XmlElement rule)
Структура XML делает эти методы довольно простыми в реализации:
bool IsRuleSatisfied(XmlElement rule)
{
bool satisfied = true;
foreach (XmlElement child in rule.SelectNodes("*"))
{
if (child.Name == "question")
{
satisfied = satisfied && IsQuestionCorrect(child);
}
if (child.Name == "choice")
{
satisfed = satisfied && IsChoiceCorrect(child);
}
if (!satisfied)
{
return false;
}
}
return true;
}
Возможно, стоило бы добавить List<XmlElement>
к параметрам IsFooCorrect
методы.(Если механизм правил находится в классе, вы могли бы сделать его полем класса.) Make `все методы добавляют текущий элемент в список, когда ответ неправильный.Затем вы можете изучить содержимое этого списка, чтобы точно узнать, почему правило не сработало.