aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/libparser/node
diff options
context:
space:
mode:
Diffstat (limited to 'src/libparser/node')
-rw-r--r--src/libparser/node/allsamenode.cpp86
-rw-r--r--src/libparser/node/allsamenode.h33
-rw-r--r--src/libparser/node/bind.cpp114
-rw-r--r--src/libparser/node/bind.h50
-rw-r--r--src/libparser/node/countexecutenode.cpp76
-rw-r--r--src/libparser/node/countexecutenode.h50
-rw-r--r--src/libparser/node/dicerollernode.cpp121
-rw-r--r--src/libparser/node/dicerollernode.h63
-rw-r--r--src/libparser/node/executionnode.cpp101
-rw-r--r--src/libparser/node/executionnode.h102
-rw-r--r--src/libparser/node/explodedicenode.cpp117
-rw-r--r--src/libparser/node/explodedicenode.h29
-rw-r--r--src/libparser/node/filternode.cpp94
-rw-r--r--src/libparser/node/filternode.h40
-rw-r--r--src/libparser/node/forloopnode.cpp103
-rw-r--r--src/libparser/node/forloopnode.h36
-rw-r--r--src/libparser/node/groupnode.cpp312
-rw-r--r--src/libparser/node/groupnode.h72
-rw-r--r--src/libparser/node/helpnode.cpp142
-rw-r--r--src/libparser/node/helpnode.h69
-rw-r--r--src/libparser/node/ifnode.cpp354
-rw-r--r--src/libparser/node/ifnode.h117
-rw-r--r--src/libparser/node/jumpbackwardnode.cpp168
-rw-r--r--src/libparser/node/jumpbackwardnode.h68
-rw-r--r--src/libparser/node/keepdiceexecnode.cpp131
-rw-r--r--src/libparser/node/keepdiceexecnode.h47
-rw-r--r--src/libparser/node/listaliasnode.cpp85
-rw-r--r--src/libparser/node/listaliasnode.h64
-rw-r--r--src/libparser/node/listsetrollnode.cpp190
-rw-r--r--src/libparser/node/listsetrollnode.h62
-rw-r--r--src/libparser/node/mergenode.cpp150
-rw-r--r--src/libparser/node/mergenode.h50
-rw-r--r--src/libparser/node/node.pri33
-rw-r--r--src/libparser/node/numbernode.cpp84
-rw-r--r--src/libparser/node/numbernode.h47
-rw-r--r--src/libparser/node/occurencecountnode.cpp185
-rw-r--r--src/libparser/node/occurencecountnode.h60
-rw-r--r--src/libparser/node/paintnode.cpp125
-rw-r--r--src/libparser/node/paintnode.h60
-rw-r--r--src/libparser/node/parenthesesnode.cpp119
-rw-r--r--src/libparser/node/parenthesesnode.h46
-rw-r--r--src/libparser/node/repeaternode.cpp162
-rw-r--r--src/libparser/node/repeaternode.h48
-rw-r--r--src/libparser/node/replacevaluenode.cpp134
-rw-r--r--src/libparser/node/replacevaluenode.h50
-rw-r--r--src/libparser/node/rerolldicenode.cpp148
-rw-r--r--src/libparser/node/rerolldicenode.h72
-rw-r--r--src/libparser/node/scalaroperatornode.cpp286
-rw-r--r--src/libparser/node/scalaroperatornode.h127
-rw-r--r--src/libparser/node/sortresult.cpp148
-rw-r--r--src/libparser/node/sortresult.h69
-rw-r--r--src/libparser/node/splitnode.cpp93
-rw-r--r--src/libparser/node/splitnode.h44
-rw-r--r--src/libparser/node/startingnode.cpp61
-rw-r--r--src/libparser/node/startingnode.h57
-rw-r--r--src/libparser/node/stringnode.cpp58
-rw-r--r--src/libparser/node/stringnode.h29
-rw-r--r--src/libparser/node/switchcasenode.cpp149
-rw-r--r--src/libparser/node/switchcasenode.h50
-rw-r--r--src/libparser/node/uniquenode.cpp93
-rw-r--r--src/libparser/node/uniquenode.h44
-rw-r--r--src/libparser/node/valueslistnode.cpp62
-rw-r--r--src/libparser/node/valueslistnode.h24
-rw-r--r--src/libparser/node/variablenode.cpp112
-rw-r--r--src/libparser/node/variablenode.h35
65 files changed, 6210 insertions, 0 deletions
diff --git a/src/libparser/node/allsamenode.cpp b/src/libparser/node/allsamenode.cpp
new file mode 100644
index 0000000..3b2f10f
--- /dev/null
+++ b/src/libparser/node/allsamenode.cpp
@@ -0,0 +1,86 @@
+#include "allsamenode.h"
+
+AllSameNode::AllSameNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+
+void AllSameNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != previous_result)
+ {
+ m_result->setPrevious(previous_result);
+ bool allSame= true;
+ int i= 0;
+ qint64 previousValue= 0;
+ if(previous_result->getResultList().size() < 2)
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QStringLiteral("T operator must operate on more than 1 die"));
+ return;
+ }
+ for(auto& die : previous_result->getResultList())
+ {
+ if(i == 0)
+ previousValue= die->getValue();
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ if(previousValue != die->getValue())
+ allSame= false;
+ ++i;
+ }
+
+ while(allSame)
+ {
+ QList<Die*> list= m_diceResult->getResultList();
+ qint64 pValue= 0;
+ int i= 0;
+ for(auto& die : list)
+ {
+ die->roll(true);
+ if(i == 0)
+ pValue= die->getValue();
+ if(pValue != die->getValue())
+ allSame= false;
+ ++i;
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString AllSameNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"AllSameNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 AllSameNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* AllSameNode::getCopy() const
+{
+ return new AllSameNode();
+}
diff --git a/src/libparser/node/allsamenode.h b/src/libparser/node/allsamenode.h
new file mode 100644
index 0000000..e5c1dc2
--- /dev/null
+++ b/src/libparser/node/allsamenode.h
@@ -0,0 +1,33 @@
+#ifndef ALLSAMENODE_H
+#define ALLSAMENODE_H
+
+#include "executionnode.h"
+
+#include "result/diceresult.h"
+#include "validator.h"
+
+class AllSameNode : public ExecutionNode
+{
+public:
+ AllSameNode();
+// virtual ~AllSameNode();
+
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // FILTERNODE_H
diff --git a/src/libparser/node/bind.cpp b/src/libparser/node/bind.cpp
new file mode 100644
index 0000000..490071f
--- /dev/null
+++ b/src/libparser/node/bind.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "bind.h"
+
+BindNode::BindNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void BindNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == m_previousNode)
+ return;
+
+ m_result->setPrevious(previous->getResult());
+ for(auto start : *m_startList)
+ {
+ ExecutionNode* last= getLatestNode(start);
+ if(nullptr != last)
+ {
+ auto tmpResult= last->getResult();
+ while(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ m_diceResult->setHomogeneous(false);
+ for(auto& die : dice->getResultList())
+ {
+ if(!die->hasBeenDisplayed())
+ {
+ Die* tmpdie= new Die(*die);
+ die->displayed();
+ m_diceResult->getResultList().append(tmpdie);
+ }
+ }
+ }
+ tmpResult= tmpResult->getPrevious();
+ }
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+ExecutionNode* BindNode::getLatestNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode() && (next->getNextNode() != this))
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+QString BindNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"Bind Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 BindNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* BindNode::getCopy() const
+{
+ BindNode* node= new BindNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+std::vector<ExecutionNode*>* BindNode::getStartList() const
+{
+ return m_startList;
+}
+
+void BindNode::setStartList(std::vector<ExecutionNode*>* startList)
+{
+ m_startList= startList;
+}
diff --git a/src/libparser/node/bind.h b/src/libparser/node/bind.h
new file mode 100644
index 0000000..71bbfb0
--- /dev/null
+++ b/src/libparser/node/bind.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef BINDNODE_H
+#define BINDNODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The MergeNode class is an ExecutionNode. It is dedicated to merge result of several commands.
+ */
+class BindNode : public ExecutionNode
+{
+public:
+ BindNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ std::vector<ExecutionNode*>* getStartList() const;
+ void setStartList(std::vector<ExecutionNode*>* startList);
+
+private:
+ ExecutionNode* getLatestNode(ExecutionNode* node);
+
+private:
+ DiceResult* m_diceResult;
+ std::vector<ExecutionNode*>* m_startList;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/countexecutenode.cpp b/src/libparser/node/countexecutenode.cpp
new file mode 100644
index 0000000..b45fe37
--- /dev/null
+++ b/src/libparser/node/countexecutenode.cpp
@@ -0,0 +1,76 @@
+#include "countexecutenode.h"
+#include "result/diceresult.h"
+#include "validatorlist.h"
+
+CountExecuteNode::CountExecuteNode() : m_scalarResult(new ScalarResult()), m_validatorList(nullptr)
+{
+ m_result= m_scalarResult;
+}
+void CountExecuteNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+CountExecuteNode::~CountExecuteNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+
+void CountExecuteNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QStringLiteral("No scalar result before Swith/Case operator"));
+ return;
+ }
+ DiceResult* previousResult= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != previousResult)
+ {
+ m_result->setPrevious(previousResult);
+ qint64 sum= 0;
+ std::function<void(Die*, qint64)> f= [&sum](const Die*, qint64 score) { sum+= score; };
+ m_validatorList->validResult(previousResult, true, true, f);
+ m_scalarResult->setValue(sum);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+QString CountExecuteNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"CountExecuteNode %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 CountExecuteNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* CountExecuteNode::getCopy() const
+{
+ CountExecuteNode* node= new CountExecuteNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/countexecutenode.h b/src/libparser/node/countexecutenode.h
new file mode 100644
index 0000000..37b7a4f
--- /dev/null
+++ b/src/libparser/node/countexecutenode.h
@@ -0,0 +1,50 @@
+#ifndef COUNTEXECUTENODE_H
+#define COUNTEXECUTENODE_H
+
+#include "executionnode.h"
+
+#include "result/scalarresult.h"
+
+class ValidatorList;
+/**
+ * @brief The CountExecuteNode class
+ */
+class CountExecuteNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief CountExecuteNode
+ */
+ CountExecuteNode();
+ virtual ~CountExecuteNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ ScalarResult* m_scalarResult;
+ ValidatorList* m_validatorList;
+};
+
+#endif // COUNTEXECUTENODE_H
diff --git a/src/libparser/node/dicerollernode.cpp b/src/libparser/node/dicerollernode.cpp
new file mode 100644
index 0000000..2b00c0a
--- /dev/null
+++ b/src/libparser/node/dicerollernode.cpp
@@ -0,0 +1,121 @@
+#include "dicerollernode.h"
+#include "die.h"
+
+#include <QDebug>
+#include <QThread>
+#include <QThreadPool>
+#include <QTime>
+
+DiceRollerNode::DiceRollerNode(qint64 max, qint64 min)
+ : m_max(max), m_diceResult(new DiceResult()), m_min(min), m_operator(Dice::ArithmeticOperator::PLUS)
+{
+ m_result= m_diceResult;
+}
+void DiceRollerNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ Result* result= previous->getResult();
+ if(nullptr != result)
+ {
+ auto num= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ if(num <= 0)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_DICE_TO_ROLL, QObject::tr("No dice to roll"));
+ }
+ m_diceCount= num > 0 ? static_cast<quint64>(num) : 0;
+ m_result->setPrevious(result);
+
+ auto possibleValue= static_cast<quint64>(std::abs((m_max - m_min) + 1));
+ if(possibleValue < m_diceCount && m_unique)
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr("More unique values asked than possible values (D operator)"));
+ return;
+ }
+
+ for(quint64 i= 0; i < m_diceCount; ++i)
+ {
+ Die* die= new Die();
+ die->setOp(m_operator);
+ die->setBase(m_min);
+ die->setMaxValue(m_max);
+ die->roll();
+ if(m_unique)
+ {
+ const auto& equal= [](const Die* a, const Die* b) { return a->getValue() == b->getValue(); };
+ while(m_diceResult->contains(die, equal))
+ {
+ die->roll(false);
+ }
+ }
+ m_diceResult->insertResult(die);
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+
+quint64 DiceRollerNode::getFaces() const
+{
+ return static_cast<quint64>(std::abs(m_max - m_min) + 1);
+}
+
+std::pair<qint64, qint64> DiceRollerNode::getRange() const
+{
+ return std::make_pair(m_min, m_max);
+}
+QString DiceRollerNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"DiceRollerNode faces: %2\"]").arg(m_id).arg(getFaces());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 DiceRollerNode::getPriority() const
+{
+ qint64 priority= 4;
+ // if(nullptr!=m_nextNode)
+ // {
+ // priority = m_nextNode->getPriority();
+ // }
+ return priority;
+}
+ExecutionNode* DiceRollerNode::getCopy() const
+{
+ DiceRollerNode* node= new DiceRollerNode(m_max, m_min);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+Dice::ArithmeticOperator DiceRollerNode::getOperator() const
+{
+ return m_operator;
+}
+
+void DiceRollerNode::setOperator(const Dice::ArithmeticOperator& dieOperator)
+{
+ m_operator= dieOperator;
+ m_diceResult->setOperator(dieOperator);
+}
+
+bool DiceRollerNode::getUnique() const
+{
+ return m_unique;
+}
+
+void DiceRollerNode::setUnique(bool unique)
+{
+ m_unique= unique;
+}
diff --git a/src/libparser/node/dicerollernode.h b/src/libparser/node/dicerollernode.h
new file mode 100644
index 0000000..52178cb
--- /dev/null
+++ b/src/libparser/node/dicerollernode.h
@@ -0,0 +1,63 @@
+#ifndef DICEROLLERNODE_H
+#define DICEROLLERNODE_H
+
+#include <Qt>
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <utility>
+/**
+ * @brief The DiceRollerNode class rolls dice of one kind.
+ */
+class DiceRollerNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief DiceRollerNode builds an instance
+ * @param faces, number of faces of dices
+ * @param offset, first value of dice.
+ */
+ DiceRollerNode(qint64 max, qint64 min= 1);
+
+ /**
+ * @brief run - starts to roll dice.
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief getFaces accessor
+ * @return the face count
+ */
+ quint64 getFaces() const;
+ std::pair<qint64, qint64> getRange() const;
+
+ /**
+ * @brief toString
+ * @param wl
+ * @return use to generate dot tree;
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return priority for dice roll: 4 (higher)
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+ // private members
+ Dice::ArithmeticOperator getOperator() const;
+ void setOperator(const Dice::ArithmeticOperator& dieOperator);
+
+ bool getUnique() const;
+ void setUnique(bool unique);
+
+private:
+ quint64 m_diceCount;
+ qint64 m_max; /// faces
+ DiceResult* m_diceResult{nullptr};
+ qint64 m_min;
+ Dice::ArithmeticOperator m_operator;
+ bool m_unique{false};
+};
+
+#endif // DICEROLLERNODE_H
diff --git a/src/libparser/node/executionnode.cpp b/src/libparser/node/executionnode.cpp
new file mode 100644
index 0000000..4545934
--- /dev/null
+++ b/src/libparser/node/executionnode.cpp
@@ -0,0 +1,101 @@
+#include "executionnode.h"
+
+#include <QUuid>
+
+ExecutionNode::ExecutionNode()
+ : m_previousNode(nullptr)
+ , m_result(nullptr)
+ , m_nextNode(nullptr)
+ , m_errors(QMap<Dice::ERROR_CODE, QString>())
+ , m_id(QString("\"%1\"").arg(QUuid::createUuid().toString()))
+{
+}
+ExecutionNode::~ExecutionNode()
+{
+ if(nullptr != m_result)
+ {
+ delete m_result;
+ m_result= nullptr;
+ }
+ if(nullptr != m_nextNode)
+ {
+ delete m_nextNode;
+ m_nextNode= nullptr;
+ }
+}
+
+Result* ExecutionNode::getResult()
+{
+ return m_result;
+}
+void ExecutionNode::setNextNode(ExecutionNode* node)
+{
+ m_nextNode= node;
+}
+void ExecutionNode::setPreviousNode(ExecutionNode* node)
+{
+ m_previousNode= node;
+}
+ExecutionNode* ExecutionNode::getNextNode()
+{
+ return m_nextNode;
+}
+QMap<Dice::ERROR_CODE, QString> ExecutionNode::getExecutionErrorMap()
+{
+ if(nullptr != m_nextNode)
+ {
+ auto const& keys= m_nextNode->getExecutionErrorMap().keys();
+ for(auto& key : keys)
+ {
+ m_errors.insert(key, m_nextNode->getExecutionErrorMap().value(key));
+ }
+ }
+ return m_errors;
+}
+QString ExecutionNode::getHelp()
+{
+ return QString();
+}
+ExecutionNode* ExecutionNode::getPreviousNode() const
+{
+ return m_previousNode;
+}
+void ExecutionNode::generateDotTree(QString& s)
+{
+ auto str= toString(true);
+ if(s.contains(str))
+ return;
+ s.append(toString(true));
+ s.append(";\n");
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ // s.append(" [label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+ }
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+}
+qint64 ExecutionNode::getScalarResult()
+{
+ if(m_result == nullptr)
+ return 0;
+ return m_result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+}
diff --git a/src/libparser/node/executionnode.h b/src/libparser/node/executionnode.h
new file mode 100644
index 0000000..d1bdf66
--- /dev/null
+++ b/src/libparser/node/executionnode.h
@@ -0,0 +1,102 @@
+#ifndef EXECUTIONNODE_H
+#define EXECUTIONNODE_H
+
+#include "result/result.h"
+#include <diceparser/diceparserhelper.h>
+
+/**
+ * @brief The ExecutionNode class
+ */
+class ExecutionNode
+{
+public:
+ /**
+ * @brief ExecutionNode
+ */
+ ExecutionNode();
+ /**
+ * @brief ~ExecutionNode
+ */
+ virtual ~ExecutionNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr)= 0;
+ /**
+ * @brief getResult
+ * @return
+ */
+ virtual Result* getResult();
+ /**
+ * @brief setNextNode
+ */
+ void setNextNode(ExecutionNode*);
+ /**
+ * @brief getNextNode
+ * @return
+ */
+ ExecutionNode* getNextNode();
+ /**
+ * @brief getPreviousNode
+ * @return
+ */
+ virtual ExecutionNode* getPreviousNode() const;
+ void setPreviousNode(ExecutionNode* node);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const= 0;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const= 0;
+ /**
+ * @brief getErrorList
+ * @return
+ */
+ virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap();
+
+ /**
+ * @brief generateDotTree
+ */
+ virtual void generateDotTree(QString&);
+
+ /**
+ * @brief getHelp
+ * @return
+ */
+ virtual QString getHelp();
+
+ /**
+ * @brief getCopy
+ * @return should return a copy of that node.
+ */
+ virtual ExecutionNode* getCopy() const= 0;
+
+ virtual qint64 getScalarResult();
+
+protected:
+ /**
+ * @brief m_nextNode
+ */
+ ExecutionNode* m_previousNode= nullptr;
+ /**
+ * @brief m_result
+ */
+ Result* m_result= nullptr;
+ /**
+ * @brief m_nextNode
+ */
+ ExecutionNode* m_nextNode= nullptr;
+ /**
+ * @brief m_errors
+ */
+ QMap<Dice::ERROR_CODE, QString> m_errors;
+
+ QString m_id;
+};
+
+#endif // EXECUTIONNODE_H
diff --git a/src/libparser/node/explodedicenode.cpp b/src/libparser/node/explodedicenode.cpp
new file mode 100644
index 0000000..1546883
--- /dev/null
+++ b/src/libparser/node/explodedicenode.cpp
@@ -0,0 +1,117 @@
+#include "explodedicenode.h"
+#include "validatorlist.h"
+
+ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void ExplodeDiceNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != previous) && (nullptr != previous->getResult()))
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previous_result);
+ if(nullptr != previous_result)
+ {
+ Die* exampleDie;
+ for(auto& die : previous_result->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ exampleDie= tmpdie;
+ }
+
+ // QList<Die*> list= m_diceResult->getResultList();
+
+ bool hasExploded= false;
+ std::function<void(Die*, qint64)> f= [&hasExploded, this](Die* die, qint64) {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE
+ == m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())))
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition (%1) cause an endless loop with this dice: %2")
+ .arg(toString(true))
+ .arg(QStringLiteral("d[%1,%2]")
+ .arg(static_cast<int>(die->getBase()))
+ .arg(static_cast<int>(die->getMaxValue()))));
+ }
+ hasExploded= true;
+ die->roll(true);
+ };
+ do
+ {
+ hasExploded= false;
+ m_validatorList->validResult(m_diceResult, false, false, f);
+ } while(hasExploded);
+
+ /*for(auto& die : list)
+ {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE
+ == m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())))
+ {
+
+ continue;
+ }
+
+ while(m_validatorList->hasValid(die, false))
+ {
+ die->roll(true);
+ }
+ }*/
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+ExplodeDiceNode::~ExplodeDiceNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+void ExplodeDiceNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+QString ExplodeDiceNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"ExplodeDiceNode %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ExplodeDiceNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* ExplodeDiceNode::getCopy() const
+{
+ ExplodeDiceNode* node= new ExplodeDiceNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/explodedicenode.h b/src/libparser/node/explodedicenode.h
new file mode 100644
index 0000000..77b4a44
--- /dev/null
+++ b/src/libparser/node/explodedicenode.h
@@ -0,0 +1,29 @@
+#ifndef EXPLOSEDICENODE_H
+#define EXPLOSEDICENODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValidatorList;
+
+/**
+ * @brief The ExplodeDiceNode class explode dice while is valid by the validator.
+ */
+class ExplodeDiceNode : public ExecutionNode
+{
+public:
+ ExplodeDiceNode();
+ virtual ~ExplodeDiceNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual void setValidatorList(ValidatorList*);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+protected:
+ DiceResult* m_diceResult;
+ ValidatorList* m_validatorList= nullptr;
+};
+
+#endif // EXPLOSEDICENODE_H
diff --git a/src/libparser/node/filternode.cpp b/src/libparser/node/filternode.cpp
new file mode 100644
index 0000000..b72b6e1
--- /dev/null
+++ b/src/libparser/node/filternode.cpp
@@ -0,0 +1,94 @@
+#include "filternode.h"
+#include "validatorlist.h"
+
+FilterNode::FilterNode() : m_diceResult(new DiceResult()), m_eachValue(false)
+{
+ m_result= m_diceResult;
+}
+
+FilterNode::~FilterNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+void FilterNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+void FilterNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previousDiceResult);
+
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList2;
+ std::function<void(Die*, qint64)> f= [&diceList2](Die* die, qint64) {
+ if(die == nullptr)
+ return;
+ Die* tmpdie= new Die(*die);
+ diceList2.append(tmpdie);
+ die->displayed();
+ };
+ m_validatorList->validResult(previousDiceResult, true, true, f);
+
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ diceList.erase(std::remove_if(diceList.begin(), diceList.end(),
+ [&diceList2](Die* die) { return diceList2.contains(die); }),
+ diceList.end());
+ for(Die* tmp : diceList)
+ {
+ tmp->setHighlighted(false);
+ tmp->setDisplayed(true);
+ }
+
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+
+QString FilterNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"FilterNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 FilterNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+
+ return priority;
+}
+ExecutionNode* FilterNode::getCopy() const
+{
+ FilterNode* node= new FilterNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/filternode.h b/src/libparser/node/filternode.h
new file mode 100644
index 0000000..7af6fe2
--- /dev/null
+++ b/src/libparser/node/filternode.h
@@ -0,0 +1,40 @@
+#ifndef FILTERNODE_H
+#define FILTERNODE_H
+
+#include "executionnode.h"
+
+#include "result/diceresult.h"
+
+class ValidatorList;
+
+class FilterNode : public ExecutionNode
+{
+public:
+ FilterNode();
+ virtual ~FilterNode();
+
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+ ValidatorList* m_validatorList;
+ bool m_eachValue;
+};
+
+#endif // FILTERNODE_H
diff --git a/src/libparser/node/forloopnode.cpp b/src/libparser/node/forloopnode.cpp
new file mode 100644
index 0000000..aba6ff4
--- /dev/null
+++ b/src/libparser/node/forloopnode.cpp
@@ -0,0 +1,103 @@
+#include "forloopnode.h"
+
+#include "die.h"
+
+MockNode::MockNode() {}
+
+void MockNode::run(ExecutionNode* node)
+{
+ return;
+}
+
+void MockNode::setResult(Result* result)
+{
+ m_result= result;
+}
+
+QString MockNode::toString(bool) const
+{
+ return {};
+};
+qint64 MockNode::getPriority() const
+{
+ return 0;
+}
+ExecutionNode* MockNode::getCopy() const
+{
+ return new MockNode();
+}
+// end mocknode
+
+ForLoopNode::ForLoopNode() : m_diceResult(new DiceResult) {}
+
+void ForLoopNode::setInternal(ExecutionNode* node)
+{
+ m_internal.reset(node);
+}
+
+void ForLoopNode::run(ExecutionNode* previous)
+{
+ if(nullptr != previous)
+ {
+ auto prevResult= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != prevResult)
+ {
+ m_diceResult->setPrevious(prevResult);
+ QList<Die*> diceList= prevResult->getResultList();
+ for(Die* dice : diceList)
+ {
+ MockNode node;
+ DiceResult diceResult;
+ diceResult.insertResult(dice);
+ node.setResult(&diceResult);
+ m_internal->run(&node);
+
+ auto tmp= m_internal.get();
+ while(nullptr != tmp->getNextNode())
+ {
+ tmp= tmp->getNextNode();
+ }
+ Result* internalResult= tmp->getResult();
+ auto value= internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+
+ Die* neodie= new Die();
+ *neodie= *dice;
+ neodie->setValue(value);
+ m_diceResult->insertResult(neodie);
+ node.setResult(nullptr);
+ diceResult.clear();
+ dice->displayed();
+ }
+ }
+ }
+ m_result= m_diceResult;
+ if(m_nextNode != nullptr)
+ m_nextNode->run(this);
+}
+
+qint64 ForLoopNode::getPriority() const
+{
+ return 2;
+}
+
+QString ForLoopNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"ForLoopNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+ExecutionNode* ForLoopNode::getCopy() const
+{
+ auto node= new ForLoopNode();
+ if(m_internal)
+ {
+ node->setInternal(m_internal->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/forloopnode.h b/src/libparser/node/forloopnode.h
new file mode 100644
index 0000000..a9acf20
--- /dev/null
+++ b/src/libparser/node/forloopnode.h
@@ -0,0 +1,36 @@
+#ifndef FORLOOPNODE_H
+#define FORLOOPNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <memory>
+
+class MockNode : public ExecutionNode
+{
+public:
+ MockNode();
+ void run(ExecutionNode* node);
+ void setResult(Result* result);
+ QString toString(bool withLabel) const;
+ qint64 getPriority() const;
+ ExecutionNode* getCopy() const;
+};
+
+class ForLoopNode : public ExecutionNode
+{
+public:
+ ForLoopNode();
+ void run(ExecutionNode* previous);
+
+ void setInternal(ExecutionNode* internal);
+
+ QString toString(bool withLabel) const;
+ qint64 getPriority() const;
+ ExecutionNode* getCopy() const;
+
+private:
+ std::unique_ptr<ExecutionNode> m_internal;
+ DiceResult* m_diceResult;
+};
+
+#endif // FORLOOPNODE_H
diff --git a/src/libparser/node/groupnode.cpp b/src/libparser/node/groupnode.cpp
new file mode 100644
index 0000000..860d758
--- /dev/null
+++ b/src/libparser/node/groupnode.cpp
@@ -0,0 +1,312 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "groupnode.h"
+#include "result/diceresult.h"
+//-------------------------------
+int DieGroup::getSum() const
+{
+ int sum= 0;
+ for(int i : *this)
+ {
+ sum+= i;
+ }
+ return sum;
+}
+
+void DieGroup::removeValue(DieGroup i)
+{
+ for(auto x : i)
+ {
+ removeOne(x);
+ }
+}
+
+int DieGroup::getLost() const
+{
+ return getSum() - m_exceptedValue;
+}
+
+qint64 DieGroup::getExceptedValue() const
+{
+ return m_exceptedValue;
+}
+
+void DieGroup::setExceptedValue(qint64 exceptedValue)
+{
+ m_exceptedValue= exceptedValue;
+}
+
+//---------------------
+GroupNode::GroupNode(bool complexOutput)
+ : m_scalarResult(new ScalarResult), m_stringResult(new StringResult), m_complexOutput(complexOutput)
+{
+}
+
+void GroupNode::run(ExecutionNode* previous)
+{
+ if(m_complexOutput)
+ m_result= m_stringResult;
+ else
+ m_result= m_scalarResult;
+
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ auto list= dice->getResultList();
+ DieGroup allResult;
+ for(auto& die : list)
+ {
+ allResult << die->getListValue();
+ }
+ std::sort(allResult.begin(), allResult.end(), std::greater<qint64>());
+ if(allResult.getSum() > m_groupValue)
+ {
+ auto copy= allResult;
+ auto const die= getGroup(allResult);
+
+ for(auto list : die)
+ {
+ for(auto val : list)
+ {
+ copy.removeOne(val);
+ }
+ }
+ m_scalarResult->setValue(die.size());
+ QStringList list;
+ for(auto group : die)
+ {
+ QStringList values;
+ std::transform(group.begin(), group.end(), std::back_inserter(values),
+ [](qint64 val) { return QString::number(val); });
+ list << QStringLiteral("{%1}").arg(values.join(","));
+ }
+ QStringList unused;
+ std::transform(copy.begin(), copy.end(), std::back_inserter(unused),
+ [](qint64 val) { return QString::number(val); });
+ if(!unused.isEmpty())
+ m_stringResult->addText(
+ QStringLiteral("%1 (%2 - [%3])").arg(die.size()).arg(list.join(",")).arg(unused.join(",")));
+ else
+ m_stringResult->addText(QStringLiteral("%1 (%2)").arg(die.size()).arg(list.join(",")));
+ }
+ else
+ {
+ m_scalarResult->setValue(0);
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString GroupNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SplitNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 GroupNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* GroupNode::getCopy() const
+{
+ GroupNode* node= new GroupNode(m_complexOutput);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+int GroupNode::getGroupValue() const
+{
+ return m_groupValue;
+}
+
+void GroupNode::setGroupValue(qint64 groupValue)
+{
+ m_groupValue= groupValue;
+}
+
+bool GroupNode::composeWithPrevious(DieGroup previous, qint64 first, qint64 current, DieGroup& addValue)
+{
+ if(previous.getSum() + first + current == m_groupValue)
+ {
+ addValue.append(previous);
+ addValue.append(first);
+ addValue.append(current);
+ return true;
+ }
+
+ if(previous.isEmpty())
+ return false;
+
+ int maxComboLength= previous.size();
+ bool hasReachMax= false;
+
+ QList<DieGroup> possibleUnion;
+ for(auto va : previous)
+ {
+ DieGroup dieG;
+ dieG.append(va);
+ possibleUnion.append(dieG);
+ }
+
+ while(!hasReachMax)
+ {
+ auto tmpValues= previous;
+ QList<DieGroup> possibleTmp;
+ for(auto& diaG : possibleUnion)
+ {
+ if(tmpValues.isEmpty())
+ break;
+ tmpValues.removeValue(diaG);
+
+ for(auto& value : tmpValues)
+ {
+ DieGroup dia;
+ dia.append(diaG);
+ dia.append(value);
+ if(dia.size() >= maxComboLength - 1)
+ hasReachMax= true;
+ else
+ possibleTmp.append(dia);
+ }
+ }
+ if(possibleTmp.isEmpty())
+ hasReachMax= true;
+ else
+ {
+ possibleTmp.append(possibleUnion);
+ possibleUnion= possibleTmp;
+ }
+ }
+ std::sort(possibleUnion.begin(), possibleUnion.end(),
+ [=](const DieGroup& a, const DieGroup& b) { return a.getLost() > b.getLost(); });
+ bool found= false;
+ for(int i= 0; (!found && i < possibleUnion.size()); ++i)
+ {
+ auto& value= possibleUnion.at(i);
+ if(value.getSum() + current + first >= m_groupValue)
+ {
+ addValue << value << current << first;
+ found= true;
+ }
+ }
+ return found;
+}
+
+QList<DieGroup> GroupNode::getGroup(DieGroup values)
+{
+ if(values.isEmpty())
+ return {};
+
+ auto first= values.takeFirst();
+
+ QList<DieGroup> result;
+ QMap<qint64, DieGroup> loseMap;
+ if(first >= m_groupValue)
+ {
+ DieGroup group;
+ group << first;
+ loseMap[0]= group;
+ }
+ else
+ {
+ auto it= values.rbegin();
+ bool foundPerfect= false;
+ qint64 cumuledValue= 0;
+ DieGroup previousValue;
+ while((values.rend() != it) && !foundPerfect)
+ {
+ if(first + *it == m_groupValue)
+ {
+ foundPerfect= true;
+ DieGroup group;
+ group << first << *it;
+ loseMap[0]= group;
+ }
+ else if(first + *it > m_groupValue)
+ {
+ DieGroup group;
+ group << first << *it;
+ loseMap[first + *it - m_groupValue]= group;
+ }
+ else if(first + *it + cumuledValue == m_groupValue)
+ {
+ DieGroup group;
+ group << first << *it << previousValue;
+ foundPerfect= true;
+ loseMap[0]= group;
+ }
+ else if(first + *it + cumuledValue > m_groupValue)
+ {
+ DieGroup group;
+ group.setExceptedValue(m_groupValue);
+ auto b= composeWithPrevious(previousValue, first, *it, group);
+ if(b)
+ loseMap[group.getLost()]= group;
+ }
+ previousValue << *it;
+ cumuledValue+= *it;
+ ++it;
+ }
+ }
+ if(!loseMap.isEmpty())
+ {
+ DieGroup die= loseMap.first();
+ result.append(die);
+ DieGroup valueToRemove= die;
+ if(!valueToRemove.isEmpty())
+ {
+ valueToRemove.removeFirst();
+ values.removeValue(valueToRemove);
+
+ if(values.getSum() >= m_groupValue)
+ {
+ result.append(getGroup(values));
+ }
+ }
+ }
+ return result;
+}
diff --git a/src/libparser/node/groupnode.h b/src/libparser/node/groupnode.h
new file mode 100644
index 0000000..d037080
--- /dev/null
+++ b/src/libparser/node/groupnode.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef GROUPNODE_H
+#define GROUPNODE_H
+
+#include "node/executionnode.h"
+#include "result/scalarresult.h"
+#include "result/stringresult.h"
+#include <QList>
+
+class DieGroup : public QList<qint64>
+{
+public:
+ int getSum() const;
+ void removeValue(DieGroup);
+
+ int getLost() const;
+
+ qint64 getExceptedValue() const;
+ void setExceptedValue(qint64 exceptedValue);
+
+private:
+ qint64 m_exceptedValue= 0;
+};
+/**
+ * @brief The GroupNode class is an ExecutionNode.
+ */
+class GroupNode : public ExecutionNode
+{
+public:
+ GroupNode(bool complexOutput= false);
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+
+ int getGroupValue() const;
+ void setGroupValue(qint64 groupValue);
+
+ QList<DieGroup> getGroup(DieGroup);
+
+protected:
+ bool composeWithPrevious(DieGroup previous, qint64 first, qint64 current, DieGroup& addValue);
+
+private:
+ ScalarResult* m_scalarResult;
+ StringResult* m_stringResult;
+ qint64 m_groupValue;
+ QList<DieGroup> m_groupsList;
+ bool m_complexOutput= false;
+};
+
+#endif // GROUPNODE_H
diff --git a/src/libparser/node/helpnode.cpp b/src/libparser/node/helpnode.cpp
new file mode 100644
index 0000000..8ab48a9
--- /dev/null
+++ b/src/libparser/node/helpnode.cpp
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "helpnode.h"
+
+HelpNode::HelpNode() : m_path("https://github.com/Rolisteam/DiceParser/blob/master/HelpMe.md")
+{
+ m_result= new StringResult();
+}
+void HelpNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ StringResult* txtResult= dynamic_cast<StringResult*>(m_result);
+ txtResult->setHighLight(false);
+
+ if((nullptr == previous) && (txtResult != nullptr))
+ {
+ txtResult->addText(QObject::tr("Rolisteam Dice Parser:\n"
+ "\n"
+ "Example (with ! as prefix):\n"
+ "!2d6\n"
+ "!1d20\n"
+ "!6d10e10k3 (L5R)\n"
+ "\n"
+ "Full documentation at: %1")
+ .arg(m_path));
+ /*txtResult->setText(QObject::tr("Rolisteam Dice Parser:\n"
+ "\n"
+ "Example (with ! as prefix):\n"
+ "!2d6\n"
+ "!1d20\n"
+ "\n"
+ "Operator list:\n"
+ "\n"
+ "k : Keep : 2d10k1 => roll two 10-sided dice and keep the
+ higher one (kl1 for smaller one)\n" "K : Keep And Explode : 2d10K1 => Equivalent of 2d10e10k1\n" "s :
+ Sort : 8d10 => roll eight 10-sided dice and sort the result list\n" "c : Count :
+ 8d10c[>7] => roll eight 10-sided dice and count how many dice are higher than 7\n" "r : Reroll :
+ 8d6r1 => roll eight 6-sided dice and reroll dice once if its result is 1. (result of the reroll can be
+ 1)\n" "e : Explode : 8d10e10 => roll eight 10-sided dice and while dice makes a 10 it is
+ reroll. The result is added to those dice.\n" "a : Reroll and add : 8d6a1 => roll eight 6-sided dice
+ and reroll dice once and the result is added at 1\n" "m : Merge : 1d20;1d10mk1 => roll one 20-side
+ die and one 10-sided die and keep the higher die\n" "i : if : 1d100i[=100]{\"jackpot\"} => Roll
+ one 100-side die and display \"jackpot\" if the die result is 100.\n" "f : filter : 4d10f[!=4] =>
+ roll four 10-sided dice and ignore all dice with 4 as result"
+ "; : Next instruction : 1d20;2d10;3d8 => roll one 20-sided die, two 10-sided
+ dice and three 8-sided dice \n" "g : Group : 8d10g10 => count how many group of 10 it is
+ possible to do (according to rule of 7th sea).\n"
+ "# : Comment : 1d2 #flip coin=> display flip coin as comment of 1 or 2
+ result.\n"
+ "\n"
+ "Validator:\n"
+ "\n"
+ "Supported conditions: >,<,=,>=,<=,!=\n"
+ "Supported operators: % (modulo), &,^,| \n"
+ "\n"
+ " Examples:\n"
+ "\n"
+ "c[>7 & %2=0] : count how many dice are higher than 7 and even\n"
+ "c[>7 | %2=0] : count how many dice are higher than 7 or even\n"
+ "c[>7 ^ %2=0] : count how many dice are higher than 7 or even but not higher
+ than 7 and even\n"
+ "\n"
+ "List:\n"
+ "\n"
+ "1L[green,blue] => pick value from the list (green or blue)\n"
+ "2L[green,blue] => pick two values from the list (green,green | green,blue |
+ blue,green | blue,blue)\n" "2Lu[green,blue] => pick two unique values from the list (green,blue |
+ blue,green)\n"
+ "\n"
+ "Arithmetic\n"
+ "\n"
+ "8+8+8 => 24\n"
+ "24-4 => 20\n"
+ "(3+4)*2 => 14\n"
+ "7/2 => 3.5\n"
+ "2^4 => 16\n"
+ "1d6+6 => roll one 6-sided die and add 6 to its result\n"
+ "(2d4+2)d10 => roll two 4-sided dice, add 2 to the result[2;8] then roll from
+ four to ten 10-sided dice\n"
+ "\n"
+ "Full documentation at: %1").arg(m_path));*/
+ m_result->setPrevious(nullptr);
+ }
+ else if(nullptr != previous)
+ {
+ txtResult->addText(previous->getHelp());
+ m_result->setPrevious(previous->getResult());
+ }
+ txtResult->finished();
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString HelpNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"Rolisteam Dice Parser:\nFull documentation at: %2\"]").arg(m_id, m_path);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 HelpNode::getPriority() const
+{
+ return 0;
+}
+void HelpNode::setHelpPath(QString path)
+{
+ m_path= path;
+}
+
+ExecutionNode* HelpNode::getCopy() const
+{
+ HelpNode* node= new HelpNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/helpnode.h b/src/libparser/node/helpnode.h
new file mode 100644
index 0000000..a333c6d
--- /dev/null
+++ b/src/libparser/node/helpnode.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef HELPNODE_H
+#define HELPNODE_H
+#include "executionnode.h"
+
+#include <QObject>
+#include <QString>
+
+#include "result/stringresult.h"
+
+/**
+ * @brief The HelpNode class
+ */
+class HelpNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief HelpNode
+ */
+ HelpNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ void run(ExecutionNode* previous);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief setHelpPath
+ * @param path
+ */
+ void setHelpPath(QString path);
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ QString m_path;
+};
+
+#endif // HELPNODE_H
diff --git a/src/libparser/node/ifnode.cpp b/src/libparser/node/ifnode.cpp
new file mode 100644
index 0000000..8de3cd5
--- /dev/null
+++ b/src/libparser/node/ifnode.cpp
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "ifnode.h"
+#include "result/diceresult.h"
+#include "validatorlist.h"
+
+PartialDiceRollNode::PartialDiceRollNode() : m_diceResult(new DiceResult)
+{
+ m_result= m_diceResult;
+}
+
+void PartialDiceRollNode::insertDie(Die* die)
+{
+ m_diceResult->insertResult(die);
+}
+
+void PartialDiceRollNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ Result* presult= previous->getResult();
+ if(nullptr != presult)
+ {
+ m_result->setPrevious(presult);
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+ExecutionNode* PartialDiceRollNode::getCopy() const
+{
+ return new PartialDiceRollNode();
+}
+qint64 PartialDiceRollNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
+
+QString PartialDiceRollNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"PartialDiceRollNode \"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+DiceResult* getFirstDiceResult(Result* result)
+{
+ DiceResult* found= nullptr;
+
+ if(nullptr == result)
+ return found;
+ do
+ {
+ found= dynamic_cast<DiceResult*>(result);
+ result= result->getPrevious();
+ } while((nullptr == found) && (result != nullptr));
+
+ return found;
+}
+
+IfNode::IfNode() : m_conditionType(Dice::AllOfThem), m_true(nullptr), m_false(nullptr)
+{
+ // m_result = new DiceResult();
+}
+
+IfNode::~IfNode()
+{
+ m_result= nullptr;
+}
+
+void IfNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ ExecutionNode* previousLoop= previous;
+ ExecutionNode* nextNode= nullptr;
+ bool runNext= (nullptr == m_nextNode) ? false : true;
+ Result* previousResult= previous->getResult();
+ m_result= previousResult->getCopy();
+
+ if(nullptr != m_result)
+ {
+ qreal value= previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+
+ if(nullptr != m_validatorList)
+ {
+ DiceResult* previousDiceResult= getFirstDiceResult(previousResult);
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ if(m_conditionType == Dice::OnEach)
+ {
+ for(Die* dice : diceList)
+ {
+ auto diceNode= new PartialDiceRollNode();
+ diceNode->insertDie(new Die(*dice));
+ if(m_validatorList->hasValid(dice, true, true))
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+
+ if(nullptr != nextNode)
+ {
+ if(nullptr == previousLoop->getNextNode())
+ {
+ previousLoop->setNextNode(nextNode);
+ }
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ diceNode->setNextNode(nextNode);
+ diceNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+ else if((m_conditionType == Dice::OneOfThem) || (m_conditionType == Dice::AllOfThem))
+ {
+ bool trueForAll= true;
+ bool falseForAll= true;
+
+ bool oneIsTrue= false;
+ bool oneIsFalse= false;
+
+ for(Die* dice : diceList)
+ {
+ bool result= m_validatorList->hasValid(dice, true, true);
+ trueForAll= trueForAll ? result : false;
+ falseForAll= falseForAll ? result : false;
+
+ oneIsTrue|= result;
+ oneIsFalse= !result ? true : oneIsFalse;
+ }
+ if(m_conditionType == Dice::OneOfThem)
+ {
+ if(oneIsTrue)
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else // if(oneIsFalse)
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+ }
+ else if(m_conditionType == Dice::AllOfThem)
+ {
+ if(trueForAll)
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else // if(falseForAll)
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+ }
+
+ if(nullptr != nextNode)
+ {
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ nextNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+
+ if(m_conditionType == Dice::OnScalar)
+ {
+ Die dice;
+ auto val= static_cast<qint64>(value);
+ dice.setValue(val);
+ dice.insertRollValue(val);
+ dice.setMaxValue(val);
+ if(m_validatorList->hasValid(&dice, true, true))
+ {
+ nextNode= m_true;
+ }
+ else
+ {
+ nextNode= m_false;
+ }
+ if(nullptr != nextNode)
+ {
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ nextNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+ }
+
+ if((nullptr != m_nextNode) && (runNext))
+ {
+ m_nextNode->run(previousLoop);
+ }
+}
+
+void IfNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+void IfNode::setInstructionTrue(ExecutionNode* node)
+{
+ m_true= node;
+}
+
+void IfNode::setInstructionFalse(ExecutionNode* node)
+{
+ m_false= node;
+}
+void IfNode::generateDotTree(QString& s)
+{
+ s.append(toString(true));
+ s.append(";\n");
+
+ if((nullptr != m_true) && (m_true != m_nextNode))
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_true->toString(false));
+ s.append("[label=\"true" + m_validatorList->toString() + "\"];\n");
+
+ m_true->generateDotTree(s);
+ }
+ if((nullptr != m_false) && (m_false != m_nextNode))
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_false->toString(false));
+ s.append("[label=\"false\"];\n");
+ m_false->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\"];\n");
+ m_result->generateDotTree(s);
+ }
+ }
+}
+
+QString IfNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"IfNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 IfNode::getPriority() const
+{
+ return 0;
+}
+
+ExecutionNode* IfNode::getLeafNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode())
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+
+Dice::ConditionType IfNode::getConditionType() const
+{
+ return m_conditionType;
+}
+
+void IfNode::setConditionType(const Dice::ConditionType& conditionType)
+{
+ m_conditionType= conditionType;
+}
+ExecutionNode* IfNode::getCopy() const
+{
+ IfNode* node= new IfNode();
+
+ node->setConditionType(m_conditionType);
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_false)
+ {
+ node->setInstructionFalse(m_false->getCopy());
+ }
+ if(nullptr != m_true)
+ {
+ node->setInstructionTrue(m_true->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/ifnode.h b/src/libparser/node/ifnode.h
new file mode 100644
index 0000000..912d65c
--- /dev/null
+++ b/src/libparser/node/ifnode.h
@@ -0,0 +1,117 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef IFNODE_H
+#define IFNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <diceparser/diceparserhelper.h>
+
+class ValidatorList;
+class PartialDiceRollNode : public ExecutionNode
+{
+public:
+ PartialDiceRollNode();
+
+ void insertDie(Die* die);
+ virtual void run(ExecutionNode* previous= nullptr) override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+ virtual QString toString(bool withLabel) const override;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+/**
+ * @brief The ifNode class explode dice while is valid by the validator.
+ */
+class IfNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief IfNode
+ */
+ IfNode();
+ /**
+ * @brief ~IfNode
+ */
+ virtual ~IfNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief setInstructionTrue
+ */
+ virtual void setInstructionTrue(ExecutionNode*);
+ /**
+ * @brief setInstructionFalse
+ */
+ virtual void setInstructionFalse(ExecutionNode*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ /**
+ * @brief generateDotTree
+ */
+ virtual void generateDotTree(QString&);
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+ /**
+ * @brief getConditionType
+ * @return
+ */
+ Dice::ConditionType getConditionType() const;
+
+ /**
+ * @brief setConditionType
+ * @param conditionType
+ */
+ void setConditionType(const Dice::ConditionType& conditionType);
+
+protected:
+ ExecutionNode* getLeafNode(ExecutionNode* node);
+
+protected:
+ ValidatorList* m_validatorList= nullptr;
+ Dice::ConditionType m_conditionType;
+
+ ExecutionNode* m_true;
+ ExecutionNode* m_false;
+};
+#endif
diff --git a/src/libparser/node/jumpbackwardnode.cpp b/src/libparser/node/jumpbackwardnode.cpp
new file mode 100644
index 0000000..9fa0f45
--- /dev/null
+++ b/src/libparser/node/jumpbackwardnode.cpp
@@ -0,0 +1,168 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "jumpbackwardnode.h"
+#include <QDebug>
+
+JumpBackwardNode::JumpBackwardNode()
+{
+ m_previousNode= nullptr;
+ m_backwardNode= nullptr;
+ m_diceResult= new DiceResult();
+ m_result= m_diceResult;
+}
+
+qint64 JumpBackwardNode::getPriority() const
+{
+ return 4;
+}
+QString JumpBackwardNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"JumpBackwardNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+void JumpBackwardNode::generateDotTree(QString& s)
+{
+ s.append(toString(true));
+ s.append(";\n");
+
+ if(nullptr != m_backwardNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_backwardNode->toString(false));
+ s.append("[label=\"backward\"];\n");
+ // m_backwardNode->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\"];\n");
+ m_result->generateDotTree(s);
+ }
+ }
+}
+
+void JumpBackwardNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ ExecutionNode* parent= previous;
+ bool found= false;
+ // int i = 3;
+ Result* result= nullptr;
+ while((nullptr != parent) && (!found))
+ {
+ result= parent->getResult();
+ if(nullptr != result)
+ {
+ //--i;
+ if(/*(i==0)&&*/ (result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ found= true;
+ m_backwardNode= parent;
+ }
+ else
+ {
+ JumpBackwardNode* jpNode= dynamic_cast<JumpBackwardNode*>(parent);
+ if(nullptr != jpNode)
+ {
+ found= true;
+ m_backwardNode= parent;
+ }
+ }
+ }
+ if(!found)
+ {
+ parent= parent->getPreviousNode();
+ }
+ }
+ if(nullptr == result)
+ {
+ m_errors.insert(
+ Dice::ERROR_CODE::DIE_RESULT_EXPECTED,
+ QObject::tr(" The @ operator expects dice result. Please check the documentation to fix your command."));
+ }
+ else
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != diceResult)
+ {
+ for(auto& die : diceResult->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ //*tmpdie= *die;
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ }
+ }
+
+ m_result->setPrevious(previous->getResult());
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ if(nullptr != diceResult)
+ {
+ for(int i= 0; i < diceResult->getResultList().size(); ++i)
+ {
+ Die* tmp= diceResult->getResultList().at(i);
+ Die* tmp2= m_diceResult->getResultList().at(i);
+ if(tmp->isHighlighted())
+ {
+ tmp2->setHighlighted(true);
+ }
+ }
+ }
+ }
+}
+
+ExecutionNode* JumpBackwardNode::getCopy() const
+{
+ JumpBackwardNode* node= new JumpBackwardNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/jumpbackwardnode.h b/src/libparser/node/jumpbackwardnode.h
new file mode 100644
index 0000000..598a540
--- /dev/null
+++ b/src/libparser/node/jumpbackwardnode.h
@@ -0,0 +1,68 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef JUMPBACKWARDNODE_H
+#define JUMPBACKWARDNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The JumpBackwardNode class is dedicated to change the previous dice of one dice option.
+ */
+class JumpBackwardNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief JumpBackwardNode allows to get result from remote node in the execution tree.
+ */
+ JumpBackwardNode();
+ /**
+ * @brief run - performs the actions
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief generateDotTree
+ * @param s
+ */
+ virtual void generateDotTree(QString& s);
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+ ExecutionNode* m_backwardNode;
+};
+
+#endif // JUMPBACKWARDNODE_H
diff --git a/src/libparser/node/keepdiceexecnode.cpp b/src/libparser/node/keepdiceexecnode.cpp
new file mode 100644
index 0000000..b197822
--- /dev/null
+++ b/src/libparser/node/keepdiceexecnode.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include <QList>
+
+#include "diceparser/parsingtoolbox.h"
+#include "keepdiceexecnode.h"
+
+KeepDiceExecNode::KeepDiceExecNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+KeepDiceExecNode::~KeepDiceExecNode() {}
+void KeepDiceExecNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous || nullptr == m_numberOfDiceNode)
+ {
+ return;
+ }
+ m_numberOfDiceNode->run(previous);
+ auto lastnode= ParsingToolBox::getLeafNode(m_numberOfDiceNode);
+ if(nullptr == lastnode)
+ return;
+ auto result= lastnode->getResult();
+ if(nullptr == result)
+ return;
+ if(!result->hasResultOfType(Dice::RESULT_TYPE::SCALAR))
+ return;
+
+ auto numberOfDice= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previousDiceResult);
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ if(numberOfDice < 0)
+ {
+ numberOfDice= diceList.size() + numberOfDice;
+ }
+
+ QList<Die*> diceList3= diceList.mid(0, static_cast<int>(numberOfDice));
+ QList<Die*> diceList2;
+
+ for(Die* die : qAsConst(diceList3))
+ {
+ Die* tmpdie= new Die(*die);
+ diceList2.append(tmpdie);
+ die->displayed();
+ die->setSelected(false);
+ }
+
+ if(numberOfDice > static_cast<qint64>(diceList.size()))
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr(" You ask to keep %1 dice but the result only has %2")
+ .arg(numberOfDice)
+ .arg(diceList.size()));
+ }
+
+ for(auto& tmp : diceList.mid(static_cast<int>(numberOfDice), -1))
+ {
+ tmp->setHighlighted(false);
+ }
+
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+
+void KeepDiceExecNode::setDiceKeepNumber(ExecutionNode* n)
+{
+ m_numberOfDiceNode= n;
+}
+QString KeepDiceExecNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ // auto param= m_numberOfDiceNode->toString(wl);
+ return QString("%1 [label=\"KeepDiceExecNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 KeepDiceExecNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* KeepDiceExecNode::getCopy() const
+{
+ KeepDiceExecNode* node= new KeepDiceExecNode();
+ if(nullptr != m_numberOfDiceNode)
+ {
+ node->setDiceKeepNumber(m_numberOfDiceNode->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/keepdiceexecnode.h b/src/libparser/node/keepdiceexecnode.h
new file mode 100644
index 0000000..0dd6616
--- /dev/null
+++ b/src/libparser/node/keepdiceexecnode.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef KEEPDICEEXECNODE_H
+#define KEEPDICEEXECNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The KeepDiceExecNode class splits the dice result to get the m_numberOfDice dice from the beginning of the
+ * dice result. Usually the pervious node of an KeepDiceExecNode is an SortNode.
+ */
+class KeepDiceExecNode : public ExecutionNode
+{
+public:
+ KeepDiceExecNode();
+ virtual ~KeepDiceExecNode();
+
+ virtual void run(ExecutionNode* previous);
+ virtual void setDiceKeepNumber(ExecutionNode* valueNode );
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ ExecutionNode* m_numberOfDiceNode = nullptr;
+ DiceResult* m_diceResult;
+};
+
+#endif // KEEPDICEEXECNODE_H
diff --git a/src/libparser/node/listaliasnode.cpp b/src/libparser/node/listaliasnode.cpp
new file mode 100644
index 0000000..c3f6d31
--- /dev/null
+++ b/src/libparser/node/listaliasnode.cpp
@@ -0,0 +1,85 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "listaliasnode.h"
+
+ListAliasNode::ListAliasNode(const QList<DiceAlias*>& apAlias) : m_aliasList(apAlias)
+{
+ m_result= new StringResult();
+}
+void ListAliasNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ StringResult* txtResult= dynamic_cast<StringResult*>(m_result);
+ txtResult->setHighLight(false);
+
+ txtResult->addText(buildList());
+ txtResult->finished();
+ if(nullptr != previous)
+ {
+ // txtResult->setText(previous->getHelp());
+ m_result->setPrevious(previous->getResult());
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString ListAliasNode::buildList() const
+{
+ QString result(QObject::tr("List of Alias:\n"));
+ for(auto& key : m_aliasList)
+ {
+ result+= QString("%1 : %2 # %3\n").arg(key->pattern(), key->command(), key->comment());
+ }
+ return result;
+}
+QString ListAliasNode::toString(bool wl) const
+{
+ QStringList resultList;
+ for(auto& key : m_aliasList)
+ {
+ resultList << "{" << key->pattern() << key->command() << "}";
+ }
+
+ if(wl)
+ {
+ return QString("%1 [label=\"ListAliasNode %2\"]").arg(m_id, resultList.join(","));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ListAliasNode::getPriority() const
+{
+ return 0;
+}
+
+ExecutionNode* ListAliasNode::getCopy() const
+{
+ ListAliasNode* node= new ListAliasNode(m_aliasList);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/listaliasnode.h b/src/libparser/node/listaliasnode.h
new file mode 100644
index 0000000..2a6f96e
--- /dev/null
+++ b/src/libparser/node/listaliasnode.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef LISTALIASNODE_H
+#define LISTALIASNODE_H
+
+#include <diceparser/dicealias.h>
+
+#include "executionnode.h"
+#include "result/stringresult.h"
+
+/**
+ * @brief The ListAliasNode class is dedicated to display the list of the current aliases.
+ */
+class ListAliasNode : public ExecutionNode
+{
+public:
+ ListAliasNode(const QList<DiceAlias*>& mapAlias);
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief buildList
+ * @return
+ */
+ virtual QString buildList() const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ const QList<DiceAlias*>& m_aliasList;
+};
+
+#endif // LISTALIASNODE_H
diff --git a/src/libparser/node/listsetrollnode.cpp b/src/libparser/node/listsetrollnode.cpp
new file mode 100644
index 0000000..2cee645
--- /dev/null
+++ b/src/libparser/node/listsetrollnode.cpp
@@ -0,0 +1,190 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "listsetrollnode.h"
+#include "die.h"
+
+#include <QDebug>
+
+ListSetRollNode::ListSetRollNode() : m_diceResult(new DiceResult()), m_stringResult(new StringResult()), m_unique(false)
+{
+ m_result= m_stringResult;
+}
+ListSetRollNode::~ListSetRollNode()
+{
+ if(nullptr != m_diceResult)
+ {
+ delete m_diceResult;
+ m_diceResult= nullptr;
+ }
+}
+
+QStringList ListSetRollNode::getList() const
+{
+ return m_values;
+}
+QString ListSetRollNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"ListSetRoll list:%2\"]").arg(m_id, m_values.join(","));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ListSetRollNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
+void ListSetRollNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ Result* result= previous->getResult();
+ if(nullptr != result)
+ {
+ quint64 diceCount= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ if(diceCount > static_cast<quint64>(m_values.size()) && m_unique)
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr("More unique values asked than possible values (L operator)"));
+ }
+ else
+ {
+ m_result->setPrevious(result);
+ for(quint64 i= 0; i < diceCount; ++i)
+ {
+ QStringList rollResult;
+ Die* die= new Die();
+ computeFacesNumber(die);
+ die->roll();
+ m_diceResult->insertResult(die);
+ getValueFromDie(die, rollResult);
+ for(auto const& str : qAsConst(rollResult))
+ {
+ m_stringResult->addText(str);
+ }
+ }
+ m_stringResult->finished();
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+void ListSetRollNode::setListValue(QStringList lirs)
+{
+ m_values= lirs;
+}
+void ListSetRollNode::setUnique(bool u)
+{
+ m_unique= u;
+}
+void ListSetRollNode::setNoComma(bool b)
+{
+ if(m_stringResult)
+ m_stringResult->setNoComma(b);
+}
+void ListSetRollNode::setRangeList(QList<Range>& ranges)
+{
+ m_rangeList= ranges;
+}
+void ListSetRollNode::computeFacesNumber(Die* die)
+{
+ if(m_rangeList.isEmpty())
+ {
+ die->setMaxValue(m_values.size());
+ }
+ else
+ {
+ Q_ASSERT(m_values.size() == m_rangeList.size());
+ qint64 max;
+ int i= 0;
+ for(Range& range : m_rangeList)
+ {
+ if(((i == 0) || (max < range.getEnd())) && (range.isFullyDefined()))
+ {
+ max= range.getEnd();
+ }
+ ++i;
+ }
+ die->setMaxValue(max);
+ }
+}
+void ListSetRollNode::getValueFromDie(Die* die, QStringList& rollResult)
+{
+ if(m_rangeList.isEmpty())
+ {
+ if(die->getValue() - 1 < m_values.size())
+ {
+ auto str= m_values[die->getValue() - 1];
+ while(m_unique && rollResult.contains(str))
+ {
+ die->roll(false);
+ str= m_values[die->getValue() - 1];
+ }
+ rollResult << str;
+ }
+ }
+ else
+ {
+ Q_ASSERT(m_values.size() == m_rangeList.size());
+ bool found= false;
+ while(!found)
+ {
+ int i= 0;
+ for(Range& range : m_rangeList)
+ {
+ auto it= std::find(m_rangeIndexResult.begin(), m_rangeIndexResult.end(), i);
+ auto isValid= range.hasValid(die, false);
+ if((isValid && !m_unique) || (isValid && it == m_rangeIndexResult.end()))
+ {
+ m_rangeIndexResult.push_back(i);
+ rollResult << m_values[i];
+ found= true;
+ }
+ ++i;
+ }
+ if(!found)
+ {
+ die->roll(false);
+ }
+ }
+ }
+}
+ExecutionNode* ListSetRollNode::getCopy() const
+{
+ ListSetRollNode* node= new ListSetRollNode();
+ QList<Range> dataList= m_rangeList;
+ node->setRangeList(dataList);
+ node->setUnique(m_unique);
+ node->setListValue(m_values);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/listsetrollnode.h b/src/libparser/node/listsetrollnode.h
new file mode 100644
index 0000000..a6c5e1a
--- /dev/null
+++ b/src/libparser/node/listsetrollnode.h
@@ -0,0 +1,62 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef LISTSETROLLNODE_H
+#define LISTSETROLLNODE_H
+
+#include <QStringList>
+
+#include "executionnode.h"
+#include "range.h"
+#include "result/diceresult.h"
+#include "result/stringresult.h"
+/**
+ * @brief The ListSetRollNode class is dedicated to pick up item from list.
+ */
+class ListSetRollNode : public ExecutionNode
+{
+public:
+ ListSetRollNode();
+ virtual ~ListSetRollNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ QStringList getList() const;
+
+ void setListValue(QStringList);
+ void setUnique(bool);
+ void setNoComma(bool);
+ void setRangeList(QList<Range>&);
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ void getValueFromDie(Die* die, QStringList& rollResult);
+ void computeFacesNumber(Die* die);
+
+private:
+ QStringList m_values;
+ DiceResult* m_diceResult;
+ StringResult* m_stringResult;
+ std::vector<int> m_rangeIndexResult;
+ bool m_unique;
+ QList<Range> m_rangeList;
+};
+
+#endif // LISTSETROLLNODE_H
diff --git a/src/libparser/node/mergenode.cpp b/src/libparser/node/mergenode.cpp
new file mode 100644
index 0000000..096bb8c
--- /dev/null
+++ b/src/libparser/node/mergenode.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "mergenode.h"
+
+#include <diceparser/parsingtoolbox.h>
+
+MergeNode::MergeNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void MergeNode::run(ExecutionNode* previous)
+{
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Merge operator"));
+ return;
+ }
+
+ m_previousNode= previous;
+ m_result->setPrevious(previous->getResult());
+ ExecutionNode* previousLast= nullptr;
+ std::vector<Result*> pastResult;
+ for(auto start : *m_startList)
+ {
+ ExecutionNode* last= getLatestNode(start);
+ if(nullptr == last || nullptr == previousLast)
+ {
+ previousLast= last;
+ continue;
+ }
+
+ auto startResult= start->getResult();
+ if(nullptr == startResult)
+ continue;
+
+ startResult->setPrevious(previousLast->getResult());
+ previousLast->setNextNode(start);
+
+ previousLast= last;
+ Result* tmpResult= last->getResult();
+ while(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ ///@todo TODO improve here to set homogeneous while is really
+ m_diceResult->setHomogeneous(false);
+ for(auto& die : dice->getResultList())
+ {
+ if(!m_diceResult->getResultList().contains(die) && (!die->hasBeenDisplayed()))
+ {
+ Die* tmpdie= new Die(*die);
+ die->displayed();
+ m_diceResult->getResultList().append(tmpdie);
+ }
+ }
+ }
+ auto it= std::find_if(pastResult.begin(), pastResult.end(),
+ [tmpResult](const Result* a) { return (a == tmpResult->getPrevious()); });
+ if(it == pastResult.end())
+ {
+ pastResult.push_back(previousLast->getResult());
+ tmpResult= tmpResult->getPrevious();
+ }
+ else
+ {
+ tmpResult->setPrevious(nullptr);
+ tmpResult= nullptr;
+ }
+ }
+ }
+
+ auto first= m_startList->front();
+ m_startList->clear();
+ m_startList->push_back(first);
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+#include <QDebug>
+ExecutionNode* MergeNode::getLatestNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode() && (next->getNextNode() != this))
+ {
+ // qDebug() << "find latest node" << next->toString(true) << next->getNextNode()->toString(true);
+ next= next->getNextNode();
+ }
+ return next;
+}
+QString MergeNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"Merge Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 MergeNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* MergeNode::getCopy() const
+{
+ MergeNode* node= new MergeNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+std::vector<ExecutionNode*>* MergeNode::getStartList() const
+{
+ return m_startList;
+}
+
+void MergeNode::setStartList(std::vector<ExecutionNode*>* startList)
+{
+ m_startList= startList;
+}
diff --git a/src/libparser/node/mergenode.h b/src/libparser/node/mergenode.h
new file mode 100644
index 0000000..515a2e9
--- /dev/null
+++ b/src/libparser/node/mergenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef MERGENODE_H
+#define MERGENODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The MergeNode class is an ExecutionNode. It is dedicated to merge result of several commands.
+ */
+class MergeNode : public ExecutionNode
+{
+public:
+ MergeNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ std::vector<ExecutionNode*>* getStartList() const;
+ void setStartList(std::vector<ExecutionNode*>* startList);
+
+private:
+ ExecutionNode* getLatestNode(ExecutionNode* node);
+
+private:
+ DiceResult* m_diceResult= nullptr;
+ std::vector<ExecutionNode*>* m_startList= nullptr;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/node.pri b/src/libparser/node/node.pri
new file mode 100644
index 0000000..6cf7005
--- /dev/null
+++ b/src/libparser/node/node.pri
@@ -0,0 +1,33 @@
+HEADERS += \
+ $$PWD/dicerollernode.h \
+ $$PWD/executionnode.h \
+ $$PWD/rerolldicenode.h \
+ $$PWD/startingnode.h \
+ $$PWD/scalaroperatornode.h \
+ $$PWD/numbernode.h \
+ $$PWD/sortresult.h \
+ $$PWD/keepdiceexecnode.h \
+ $$PWD/countexecutenode.h \
+ $$PWD/explodedicenode.h \
+ $$PWD/parenthesesnode.h \
+ $$PWD/helpnode.h \
+ $$PWD/jumpbackwardnode.h \
+ $$PWD/listsetrollnode.h\
+ $$PWD/listaliasnode.h
+
+SOURCES += \
+ $$PWD/dicerollernode.cpp \
+ $$PWD/executionnode.cpp \
+ $$PWD/startingnode.cpp \
+ $$PWD/rerolldicenode.cpp \
+ $$PWD/scalaroperatornode.cpp \
+ $$PWD/numbernode.cpp \
+ $$PWD/sortresult.cpp \
+ $$PWD/keepdiceexecnode.cpp \
+ $$PWD/countexecutenode.cpp \
+ $$PWD/explodedicenode.cpp \
+ $$PWD/parenthesesnode.cpp \
+ $$PWD/helpnode.cpp \
+ $$PWD/jumpbackwardnode.cpp \
+ $$PWD/listsetrollnode.cpp\
+ $$PWD/listaliasnode.cpp
diff --git a/src/libparser/node/numbernode.cpp b/src/libparser/node/numbernode.cpp
new file mode 100644
index 0000000..e50656e
--- /dev/null
+++ b/src/libparser/node/numbernode.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "numbernode.h"
+
+NumberNode::NumberNode() : m_scalarResult(new ScalarResult())
+{
+ m_result= m_scalarResult;
+}
+NumberNode::~NumberNode()
+{
+ /*if( nullptr != m_scalarResult)
+ {
+ delete m_scalarResult;
+ m_scalarResult = nullptr;
+ }*/
+}
+
+void NumberNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void NumberNode::setNumber(qint64 a)
+{
+ m_scalarResult->setValue(a);
+ m_number= a;
+}
+QString NumberNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"NumberNode %2\"]").arg(m_id).arg(m_number);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 NumberNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* NumberNode::getCopy() const
+{
+ NumberNode* node= new NumberNode();
+ node->setNumber(m_number);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/numbernode.h b/src/libparser/node/numbernode.h
new file mode 100644
index 0000000..02df984
--- /dev/null
+++ b/src/libparser/node/numbernode.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef NUMBERNODE_H
+#define NUMBERNODE_H
+
+#include "node/executionnode.h"
+#include "result/scalarresult.h"
+
+/**
+ * @brief The NumberNode class is an ExecutionNode. It is dedicated to store number.
+ */
+class NumberNode : public ExecutionNode
+{
+public:
+ NumberNode();
+ virtual ~NumberNode();
+ void run(ExecutionNode* previous);
+ void setNumber(qint64);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ qint64 m_number;
+ ScalarResult* m_scalarResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/occurencecountnode.cpp b/src/libparser/node/occurencecountnode.cpp
new file mode 100644
index 0000000..fc5c2f2
--- /dev/null
+++ b/src/libparser/node/occurencecountnode.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "occurencecountnode.h"
+#include "result/diceresult.h"
+#include "result/stringresult.h"
+#include "validatorlist.h"
+#include <QVector>
+
+OccurenceCountNode::OccurenceCountNode() : ExecutionNode() {}
+
+void OccurenceCountNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ std::map<qint64, qint64> mapOccurence;
+ if(nullptr == m_previousNode)
+ return;
+
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(m_previousNode->getResult());
+ if(nullptr == previousDiceResult)
+ return;
+
+ auto const& diceList= previousDiceResult->getResultList();
+ QVector<qint64> vec;
+
+ for(auto dice : diceList)
+ {
+ auto val= dice->getValue();
+
+ vec << val;
+ auto it= mapOccurence.find(val);
+ if(it == mapOccurence.end())
+ mapOccurence[val]= 1;
+ else
+ mapOccurence[val]+= 1;
+ }
+
+ std::sort(vec.begin(), vec.end());
+ if(nullptr == m_nextNode)
+ {
+ runForStringResult(mapOccurence, vec);
+ }
+ else
+ {
+ runForDiceResult(mapOccurence);
+ }
+}
+QString OccurenceCountNode::toString(bool label) const
+{
+ if(label)
+ {
+ return QString("%1 [label=\"OccurenceCountNode %2\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+ExecutionNode* OccurenceCountNode::getCopy() const
+{
+ return nullptr;
+}
+qint64 OccurenceCountNode::getPriority() const
+{
+ qint64 priority= 0;
+
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+qint64 OccurenceCountNode::getWidth() const
+{
+ return m_width;
+}
+
+void OccurenceCountNode::setWidth(const qint64& width)
+{
+ m_width= width;
+}
+
+qint64 OccurenceCountNode::getHeight() const
+{
+ return m_height;
+}
+
+void OccurenceCountNode::setHeight(const qint64& height)
+{
+ m_height= height;
+}
+
+ValidatorList* OccurenceCountNode::getValidatorList() const
+{
+ return m_validatorList;
+}
+
+void OccurenceCountNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+void OccurenceCountNode::runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec)
+{
+ m_stringResult= new StringResult();
+ m_result= m_stringResult;
+ QStringList list;
+ for(auto key : mapOccurence)
+ {
+ if(nullptr != m_validatorList)
+ {
+ Die die;
+ die.insertRollValue(key.first);
+ if(!m_validatorList->hasValid(&die, true))
+ continue;
+ }
+
+ if(key.second < m_width)
+ continue;
+
+ if(key.first >= m_height)
+ list << QStringLiteral("%1x%2").arg(key.second).arg(key.first);
+ }
+
+ QStringList resultList;
+ std::for_each(vec.begin(), vec.end(), [&resultList](qint64 val) { resultList << QString::number(val); });
+
+ QString result;
+
+ if(!list.isEmpty())
+ result= list.join(',');
+ else
+ result= QObject::tr("No matching result");
+
+ m_stringResult->addText(QStringLiteral("%1 - [%2]").arg(result).arg(resultList.join(',')));
+ m_stringResult->finished();
+}
+void OccurenceCountNode::runForDiceResult(const std::map<qint64, qint64>& mapOccurence)
+{
+ m_diceResult= new DiceResult();
+ m_result= m_diceResult;
+ QStringList list;
+ for(auto key : mapOccurence)
+ {
+ if(nullptr != m_validatorList)
+ {
+ Die die;
+ die.insertRollValue(key.first);
+ if(!m_validatorList->hasValid(&die, true))
+ continue;
+ }
+
+ if(key.second < m_width)
+ continue;
+
+ if(key.first >= m_height)
+ {
+ // list << QStringLiteral("%1x%2").arg(key.second).arg(key.first);
+ Die* die= new Die();
+ die->insertRollValue(key.second * key.first);
+ m_diceResult->insertResult(die);
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
diff --git a/src/libparser/node/occurencecountnode.h b/src/libparser/node/occurencecountnode.h
new file mode 100644
index 0000000..4801bfb
--- /dev/null
+++ b/src/libparser/node/occurencecountnode.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef OCCURENCECOUNTNODE_H
+#define OCCURENCECOUNTNODE_H
+
+#include "executionnode.h"
+
+class ValidatorList;
+class StringResult;
+class DiceResult;
+class OccurenceCountNode : public ExecutionNode
+{
+public:
+ OccurenceCountNode();
+
+ void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool withLabel) const;
+
+ ExecutionNode* getCopy() const;
+ qint64 getPriority() const;
+
+ qint64 getWidth() const;
+ void setWidth(const qint64& width);
+
+ qint64 getHeight() const;
+ void setHeight(const qint64& height);
+
+ ValidatorList* getValidatorList() const;
+ void setValidatorList(ValidatorList* validator);
+
+private:
+ void runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec);
+ void runForDiceResult(const std::map<qint64, qint64>& mapOccurence);
+
+private:
+ qint64 m_width= 1;
+ qint64 m_height= 0;
+ ValidatorList* m_validatorList= nullptr;
+ StringResult* m_stringResult= nullptr;
+ DiceResult* m_diceResult= nullptr;
+};
+
+#endif // OCCURENCECOUNTNODE_H
diff --git a/src/libparser/node/paintnode.cpp b/src/libparser/node/paintnode.cpp
new file mode 100644
index 0000000..22c020e
--- /dev/null
+++ b/src/libparser/node/paintnode.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "paintnode.h"
+
+ColorItem::ColorItem(QString str, int val) : m_colorNumber(val), m_color(str) {}
+
+int ColorItem::colorNumber() const
+{
+ return m_colorNumber;
+}
+
+void ColorItem::setColorNumber(int colorNumber)
+{
+ m_colorNumber= colorNumber;
+}
+
+QString ColorItem::color() const
+{
+ return m_color;
+}
+
+void ColorItem::setColor(const QString& color)
+{
+ m_color= color;
+}
+
+///////////////////////////////////
+/// @brief PainterNode::PainterNode
+///////////////////////////////////
+
+PainterNode::PainterNode() : ExecutionNode()
+{
+ m_nextNode= nullptr;
+}
+
+PainterNode::~PainterNode()
+{
+ m_result= nullptr;
+}
+
+void PainterNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Paint operator"));
+ return;
+ }
+ Result* previousResult= previous->getResult();
+ if(nullptr == previousResult)
+ return;
+
+ m_diceResult= dynamic_cast<DiceResult*>(previousResult->getCopy());
+ if(nullptr != m_diceResult)
+ {
+ QList<Die*> diceList= m_diceResult->getResultList();
+ int pastDice= 0;
+ for(ColorItem& item : m_colors)
+ {
+ int current= item.colorNumber();
+ QList<Die*>::iterator it;
+ for(it= diceList.begin() + pastDice; it != diceList.end() && current > 0; ++it)
+ {
+ (*it)->setColor(item.color());
+ --current;
+ ++pastDice;
+ }
+ }
+ m_diceResult->setPrevious(previousResult);
+ m_result= m_diceResult;
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString PainterNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"PainterNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 PainterNode::getPriority() const
+{
+ return 4;
+}
+
+void PainterNode::insertColorItem(QString color, int value)
+{
+ ColorItem item(color, value);
+ m_colors.append(item);
+}
+ExecutionNode* PainterNode::getCopy() const
+{
+ PainterNode* node= new PainterNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/paintnode.h b/src/libparser/node/paintnode.h
new file mode 100644
index 0000000..06d849e
--- /dev/null
+++ b/src/libparser/node/paintnode.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PAINTERNODE_H
+#define PAINTERNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <QString>
+
+class ColorItem
+{
+public:
+ ColorItem(QString str, int val);
+ int colorNumber() const;
+ void setColorNumber(int colorNumber);
+
+ QString color() const;
+ void setColor(const QString& color);
+
+private:
+ int m_colorNumber;
+ QString m_color;
+};
+/**
+ * @brief The PainterNode class means to manage color attribute of dice.
+ */
+class PainterNode : public ExecutionNode
+{
+public:
+ PainterNode();
+ virtual ~PainterNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ void insertColorItem(QString color, int value);
+ virtual ExecutionNode* getCopy() const;
+
+protected:
+ QList<ColorItem> m_colors;
+ DiceResult* m_diceResult= nullptr;
+};
+
+#endif
diff --git a/src/libparser/node/parenthesesnode.cpp b/src/libparser/node/parenthesesnode.cpp
new file mode 100644
index 0000000..9557536
--- /dev/null
+++ b/src/libparser/node/parenthesesnode.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "parenthesesnode.h"
+
+ParenthesesNode::ParenthesesNode() : m_internalNode(nullptr) {}
+void ParenthesesNode::setInternelNode(ExecutionNode* node)
+{
+ m_internalNode= node;
+}
+void ParenthesesNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != m_internalNode)
+ {
+ m_internalNode->run(this);
+ ExecutionNode* temp= m_internalNode;
+ while(nullptr != temp->getNextNode())
+ {
+ temp= temp->getNextNode();
+ }
+ m_result= temp->getResult();
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString ParenthesesNode::toString(bool b) const
+{
+ if(b)
+ {
+ return QString("%1 [label=\"ParenthesesNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ParenthesesNode::getPriority() const
+{
+ qint64 priority= 3;
+ return priority;
+}
+ExecutionNode* ParenthesesNode::getCopy() const
+{
+ ParenthesesNode* node= new ParenthesesNode();
+ if(nullptr != m_internalNode)
+ {
+ node->setInternelNode(m_internalNode->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void ParenthesesNode::generateDotTree(QString& s)
+{
+ auto str= toString(true);
+ if(s.contains(str))
+ return;
+ s.append(str);
+ s.append(";\n");
+
+ if(nullptr != m_internalNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_internalNode->toString(false));
+ s.append("[label=\"internal\"];\n");
+ m_internalNode->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append(" [label=\"next\"];\n");
+ // s.append(" [label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+ }
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+}
diff --git a/src/libparser/node/parenthesesnode.h b/src/libparser/node/parenthesesnode.h
new file mode 100644
index 0000000..153dfc1
--- /dev/null
+++ b/src/libparser/node/parenthesesnode.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PARENTHESESNODE_H
+#define PARENTHESESNODE_H
+
+#include "executionnode.h"
+/**
+ * @brief The ParenthesesNode class is an ExecutionNode. It is dedicated to manage expression which was inside
+ * ParenthesesNode. It is acting just like an StartingNode by for an internal execution tree.
+ */
+class ParenthesesNode : public ExecutionNode
+{
+public:
+ ParenthesesNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ void setInternelNode(ExecutionNode* node);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ virtual void generateDotTree(QString&);
+
+private:
+ ExecutionNode* m_internalNode;
+};
+
+#endif // PARENTHESESNODE_H
diff --git a/src/libparser/node/repeaternode.cpp b/src/libparser/node/repeaternode.cpp
new file mode 100644
index 0000000..f93a9fe
--- /dev/null
+++ b/src/libparser/node/repeaternode.cpp
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "node/repeaternode.h"
+
+#include "executionnode.h"
+#include "result/scalarresult.h"
+#include "result/stringresult.h"
+#include <QDebug>
+#include <diceparser/diceparserhelper.h>
+#include <diceparser/parsingtoolbox.h>
+
+using InstructionSet= std::vector<ExecutionNode*>;
+
+QStringList allFirstResultAsString(const InstructionSet& startingNodes, bool& hasAlias)
+{
+ ParsingToolBox parsingBox;
+ // QStringList allResult;
+ QStringList stringListResult;
+ for(auto node : startingNodes)
+ {
+ auto pair= parsingBox.hasResultOfType(Dice::RESULT_TYPE::STRING, node);
+ auto pairStr= parsingBox.hasResultOfType(Dice::RESULT_TYPE::SCALAR, node, true);
+ if(pair.first)
+ {
+ stringListResult << pair.second.toString();
+ hasAlias= true;
+ }
+ else if(pairStr.first)
+ {
+ stringListResult << QString::number(pairStr.second.toReal());
+ hasAlias= true;
+ }
+ }
+ return stringListResult;
+}
+
+std::vector<ExecutionNode*> makeCopy(std::vector<ExecutionNode*> cmds)
+{
+ std::vector<ExecutionNode*> copy;
+ std::transform(cmds.begin(), cmds.end(), std::back_inserter(copy),
+ [](ExecutionNode* node) { return node->getCopy(); });
+ return copy;
+}
+
+RepeaterNode::RepeaterNode() {}
+
+void RepeaterNode::run(ExecutionNode* previousNode)
+{
+ m_previousNode= previousNode;
+
+ if(nullptr == m_times || m_cmd.empty())
+ return;
+
+ m_times->run(this);
+ m_times= ParsingToolBox::getLeafNode(m_times);
+ auto times= m_times->getResult();
+ if(!times)
+ return;
+
+ std::vector<InstructionSet> m_startingNodes;
+ auto timeCount= times->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ auto cmd= makeCopy(m_cmd);
+ std::vector<Result*> resultVec;
+ for(int i= 0; i < timeCount; ++i)
+ {
+ m_startingNodes.push_back(cmd);
+ std::for_each(cmd.begin(), cmd.end(),
+ [this, &resultVec](ExecutionNode* node)
+ {
+ node->run(this);
+ auto end= ParsingToolBox::getLeafNode(node);
+ auto leafResult= end->getResult();
+
+ if(nullptr == leafResult)
+ return;
+
+ resultVec.push_back(leafResult);
+ });
+ cmd= makeCopy(m_cmd);
+ }
+ if(m_sumAll)
+ {
+ auto scalar= new ScalarResult();
+ qreal value= 0.0;
+ std::for_each(resultVec.begin(), resultVec.end(),
+ [&value](Result* result) { value+= result->getResult(Dice::RESULT_TYPE::SCALAR).toDouble(); });
+ scalar->setValue(value);
+ m_result= scalar;
+ }
+ else
+ {
+ auto string= new StringResult();
+
+ QStringList listOfStrResult;
+ for(auto instructions : m_startingNodes)
+ {
+ ParsingToolBox parsingBox;
+ parsingBox.setStartNodes(instructions);
+ auto finalString
+ = parsingBox.finalStringResult([](const QString& result, const QString&, bool) { return result; });
+ listOfStrResult << finalString;
+ }
+ if(!listOfStrResult.isEmpty())
+ string->addText(listOfStrResult.join('\n'));
+
+ m_result= string;
+
+ // qDebug().noquote() << listOfStrResult.join('\n');
+ }
+
+ if(nullptr != m_nextNode)
+ m_nextNode->run(this);
+}
+
+QString RepeaterNode::toString(bool withLabel) const
+{
+ return withLabel ? QStringLiteral("") : QStringLiteral("");
+}
+
+qint64 RepeaterNode::getPriority() const
+{
+ return 4;
+}
+
+ExecutionNode* RepeaterNode::getCopy() const
+{
+ return nullptr;
+}
+
+void RepeaterNode::setCommand(const std::vector<ExecutionNode*>& cmd)
+{
+ m_cmd= cmd;
+}
+
+void RepeaterNode::setTimeNode(ExecutionNode* time)
+{
+ m_times= time;
+}
+
+void RepeaterNode::setSumAll(bool b)
+{
+ m_sumAll= b;
+}
diff --git a/src/libparser/node/repeaternode.h b/src/libparser/node/repeaternode.h
new file mode 100644
index 0000000..fa1a50a
--- /dev/null
+++ b/src/libparser/node/repeaternode.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REPEATER_NODE_H
+#define REPEATER_NODE_H
+
+#include "node/executionnode.h"
+#include <memory>
+
+class RepeaterNode : public ExecutionNode
+{
+public:
+ RepeaterNode();
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+
+ virtual ExecutionNode* getCopy() const override;
+
+ void setCommand(const std::vector<ExecutionNode*>& node);
+ void setTimeNode(ExecutionNode* times);
+ void setSumAll(bool b);
+
+private:
+ std::vector<ExecutionNode*> m_cmd;
+ ExecutionNode* m_times= nullptr;
+ bool m_sumAll= false;
+};
+
+#endif // REPEATER_NODE_H
diff --git a/src/libparser/node/replacevaluenode.cpp b/src/libparser/node/replacevaluenode.cpp
new file mode 100644
index 0000000..c313fb0
--- /dev/null
+++ b/src/libparser/node/replacevaluenode.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "replacevaluenode.h"
+
+#include "diceresult.h"
+#include <QDebug>
+#include <diceparser/parsingtoolbox.h>
+
+ReplaceValueNode::ReplaceValueNode() : m_diceResult(new DiceResult)
+{
+ m_result= m_diceResult;
+}
+
+void ReplaceValueNode::setStopAtFirt(bool b)
+{
+ m_stopAtFirst= b;
+}
+
+void ReplaceValueNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR,
+ QStringLiteral("No previous node before Switch/Case operator"));
+ return;
+ }
+ auto previousResult= previous->getResult();
+ m_result->setPrevious(previousResult);
+
+ if(nullptr == previousResult
+ || (!previousResult->hasResultOfType(Dice::RESULT_TYPE::SCALAR)
+ && !previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QStringLiteral("No scalar or dice result before Switch/Case operator"));
+ return;
+ }
+
+ QList<Die*> dieList;
+ if(previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ auto diceResult= dynamic_cast<DiceResult*>(previousResult);
+ if(diceResult)
+ dieList.append(diceResult->getResultList());
+ }
+
+ for(auto die : dieList)
+ {
+ QStringList resultList;
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ if(info->validatorList)
+ {
+ auto res= info->validatorList->hasValid(die, false);
+ if(!res)
+ continue;
+ }
+ else if(!resultList.isEmpty())
+ break;
+
+ auto replaceValresult= info->node->getResult();
+ if(replaceValresult)
+ die->replaceLastValue(replaceValresult->getResult(Dice::RESULT_TYPE::SCALAR).toInt());
+ break;
+ }
+ m_diceResult->insertResult(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString ReplaceValueNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"ReplaceValueNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 ReplaceValueNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* ReplaceValueNode::getCopy() const
+{
+ ReplaceValueNode* node= new ReplaceValueNode();
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ node->insertCase(info->node, info->validatorList);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void ReplaceValueNode::insertCase(ExecutionNode* node, ValidatorList* validator)
+{
+ std::unique_ptr<Dice::CaseInfo> info(new Dice::CaseInfo{validator, node});
+ m_branchList.push_back(std::move(info));
+}
diff --git a/src/libparser/node/replacevaluenode.h b/src/libparser/node/replacevaluenode.h
new file mode 100644
index 0000000..36bdec2
--- /dev/null
+++ b/src/libparser/node/replacevaluenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REPLACEVALUENODE_H
+#define REPLACEVALUENODE_H
+
+#include <memory>
+#include <vector>
+
+#include "executionnode.h"
+#include "validatorlist.h"
+
+class DiceResult;
+class ReplaceValueNode : public ExecutionNode
+{
+public:
+ ReplaceValueNode();
+ void setStopAtFirt(bool b);
+
+ void run(ExecutionNode* previous= nullptr) override;
+
+ QString toString(bool withLabel) const override;
+ qint64 getPriority() const override;
+ ExecutionNode* getCopy() const override;
+
+ void insertCase(ExecutionNode* node, ValidatorList* validator);
+
+private:
+ std::vector<std::unique_ptr<Dice::CaseInfo>> m_branchList;
+ DiceResult* m_diceResult= nullptr;
+ bool m_stopAtFirst= false;
+};
+
+#endif // REPLACEVALUENODE_H
diff --git a/src/libparser/node/rerolldicenode.cpp b/src/libparser/node/rerolldicenode.cpp
new file mode 100644
index 0000000..fd8c258
--- /dev/null
+++ b/src/libparser/node/rerolldicenode.cpp
@@ -0,0 +1,148 @@
+#include <diceparser/parsingtoolbox.h>
+
+#include "rerolldicenode.h"
+#include "validatorlist.h"
+#include <utility>
+
+RerollDiceNode::RerollDiceNode(bool reroll, bool addingMode)
+ : m_diceResult(new DiceResult()), m_validatorList(nullptr), m_reroll(reroll), m_adding(addingMode)
+{
+ m_result= m_diceResult;
+}
+RerollDiceNode::~RerollDiceNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ m_validatorList= nullptr;
+ }
+}
+void RerollDiceNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != previous) && (nullptr != previous->getResult()))
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previous_result);
+ if(nullptr != previous_result)
+ {
+ for(auto& die : previous_result->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ }
+ // m_diceResult->setResultList(list);
+
+ QList<Die*>& list= m_diceResult->getResultList();
+ QList<Die*> toRemove;
+
+ for(auto& die : list)
+ {
+ bool finished= false;
+ auto state= m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue()));
+ if((Dice::CONDITION_STATE::ALWAYSTRUE == state && m_adding)
+ || (!m_reroll && !m_adding && state == Dice::CONDITION_STATE::UNREACHABLE))
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition (%1) cause an endless loop with this dice: %2")
+ .arg(toString(true))
+ .arg(QStringLiteral("d[%1,%2]")
+ .arg(static_cast<int>(die->getBase()))
+ .arg(static_cast<int>(die->getMaxValue()))));
+ continue;
+ }
+ while(m_validatorList->hasValid(die, false) && !finished)
+ {
+ if(m_instruction != nullptr)
+ {
+ m_instruction->run(this);
+ auto lastNode= ParsingToolBox::getLeafNode(m_instruction);
+ if(lastNode != nullptr)
+ {
+ auto lastResult= dynamic_cast<DiceResult*>(lastNode->getResult());
+ if(lastResult != nullptr)
+ {
+ toRemove.append(die);
+ list.append(lastResult->getResultList());
+ lastResult->clear();
+ }
+ }
+ }
+ else
+ {
+ die->roll(m_adding);
+ }
+ if(m_reroll)
+ {
+ finished= true;
+ }
+ }
+ }
+
+ for(auto die : toRemove)
+ {
+ list.removeOne(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ else
+ {
+ m_errors.insert(
+ Dice::ERROR_CODE::DIE_RESULT_EXPECTED,
+ QObject::tr(
+ " The a operator expects dice result. Please check the documentation and fix your command."));
+ }
+ }
+}
+void RerollDiceNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+QString RerollDiceNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"RerollDiceNode validatior: %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+ // return QString("RerollDiceNode [label=\"RerollDiceNode validatior:%1\"");
+}
+qint64 RerollDiceNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+
+ return priority;
+}
+ExecutionNode* RerollDiceNode::getCopy() const
+{
+ RerollDiceNode* node= new RerollDiceNode(m_reroll, m_adding);
+ node->setValidatorList(m_validatorList);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+ExecutionNode* RerollDiceNode::getInstruction() const
+{
+ return m_instruction;
+}
+
+void RerollDiceNode::setInstruction(ExecutionNode* instruction)
+{
+ m_instruction= instruction;
+}
diff --git a/src/libparser/node/rerolldicenode.h b/src/libparser/node/rerolldicenode.h
new file mode 100644
index 0000000..68b732e
--- /dev/null
+++ b/src/libparser/node/rerolldicenode.h
@@ -0,0 +1,72 @@
+#ifndef REROLLDICENODE_H
+#define REROLLDICENODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValidatorList;
+/**
+ * @brief The RerollDiceNode class reroll dice given a condition and replace(or add) the result.
+ */
+class RerollDiceNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief The ReRollMode enum
+ */
+ enum ReRollMode
+ {
+ EQUAL,
+ LESSER,
+ GREATER
+ };
+ /**
+ * @brief RerollDiceNode
+ * @param reroll If true reroll the dice only once, otherwise until the condition is false
+ */
+ RerollDiceNode(bool reroll, bool addingMode);
+
+ /**
+ * @brief ~RerollDiceNode
+ */
+ virtual ~RerollDiceNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous);
+
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+ ExecutionNode* getInstruction() const;
+ void setInstruction(ExecutionNode* instruction);
+
+private:
+ DiceResult* m_diceResult= nullptr;
+ ValidatorList* m_validatorList= nullptr;
+ ExecutionNode* m_instruction= nullptr;
+
+ const bool m_reroll;
+ const bool m_adding;
+};
+
+#endif // REROLLDICENODE_H
diff --git a/src/libparser/node/scalaroperatornode.cpp b/src/libparser/node/scalaroperatornode.cpp
new file mode 100644
index 0000000..c1c4dc5
--- /dev/null
+++ b/src/libparser/node/scalaroperatornode.cpp
@@ -0,0 +1,286 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "scalaroperatornode.h"
+
+#include "result/diceresult.h"
+#include <QDebug>
+
+ScalarOperatorNode::ScalarOperatorNode()
+ : m_internalNode(nullptr), m_scalarResult(new ScalarResult()), m_arithmeticOperator(Dice::ArithmeticOperator::PLUS)
+{
+ m_result= m_scalarResult;
+}
+ScalarOperatorNode::~ScalarOperatorNode()
+{
+ if(nullptr != m_internalNode)
+ {
+ delete m_internalNode;
+ m_internalNode= nullptr;
+ }
+}
+
+void ScalarOperatorNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != m_internalNode)
+ {
+ m_internalNode->run(this);
+ }
+ if(nullptr != previous)
+ {
+ auto previousResult= previous->getResult();
+
+ if(nullptr != previousResult)
+ {
+ ExecutionNode* internal= m_internalNode;
+ if(nullptr != internal)
+ {
+ while(nullptr != internal->getNextNode())
+ {
+ internal= internal->getNextNode();
+ }
+
+ Result* internalResult= internal->getResult();
+ m_result->setPrevious(internalResult);
+ if(nullptr != m_internalNode->getResult())
+ {
+ m_internalNode->getResult()->setPrevious(previousResult);
+ }
+
+ if(internalResult == nullptr)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QObject::tr("No Valid result in arithmetic operation: %1").arg(toString(true)));
+ return;
+ }
+
+ switch(m_arithmeticOperator)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ m_scalarResult->setValue(add(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ m_scalarResult->setValue(substract(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ m_scalarResult->setValue(multiple(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::DIVIDE:
+ m_scalarResult->setValue(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ m_scalarResult->setValue(
+ static_cast<int>(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())));
+ break;
+ case Dice::ArithmeticOperator::POW:
+ m_scalarResult->setValue(pow(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+/*bool ScalarOperatorNode::setOperatorChar(QChar c)
+{
+ if(m_scalarOperationList.contains(c))
+ {
+ m_operator = m_scalarOperationList.value(c);
+ return true;
+ }
+ return false;
+}*/
+
+void ScalarOperatorNode::setInternalNode(ExecutionNode* node)
+{
+ m_internalNode= node;
+}
+qint64 ScalarOperatorNode::add(qreal a, qreal b)
+{
+ return static_cast<qint64>(a + b);
+}
+qint64 ScalarOperatorNode::substract(qreal a, qreal b)
+{
+ return static_cast<qint64>(a - b);
+}
+qreal ScalarOperatorNode::divide(qreal a, qreal b)
+{
+ if(qFuzzyCompare(b, 0))
+ {
+ m_errors.insert(Dice::ERROR_CODE::DIVIDE_BY_ZERO, QObject::tr("Division by zero"));
+ return 0;
+ }
+ return static_cast<qreal>(a / b);
+}
+qint64 ScalarOperatorNode::multiple(qreal a, qreal b)
+{
+ return static_cast<qint64>(a * b);
+}
+qint64 ScalarOperatorNode::pow(qreal a, qreal b)
+{
+ return static_cast<qint64>(std::pow(a, b));
+}
+Dice::ArithmeticOperator ScalarOperatorNode::getArithmeticOperator() const
+{
+ return m_arithmeticOperator;
+}
+
+void ScalarOperatorNode::setArithmeticOperator(const Dice::ArithmeticOperator& arithmeticOperator)
+{
+ m_arithmeticOperator= arithmeticOperator;
+}
+
+QString ScalarOperatorNode::toString(bool wl) const
+{
+ QString op= "";
+ switch(m_arithmeticOperator)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ op= "+";
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ op= "-";
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ op= "*";
+ break;
+ case Dice::ArithmeticOperator::DIVIDE:
+ op= "/";
+ break;
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ op= "|";
+ break;
+ case Dice::ArithmeticOperator::POW:
+ op= "^";
+ break;
+ }
+ if(wl)
+ {
+ return QString("%1 [label=\"ScalarOperatorNode %2\"]").arg(m_id, op);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ScalarOperatorNode::getPriority() const
+{
+ if((m_arithmeticOperator == Dice::ArithmeticOperator::PLUS)
+ || (m_arithmeticOperator == Dice::ArithmeticOperator::MINUS))
+ {
+ return 1;
+ }
+ else if(m_arithmeticOperator == Dice::ArithmeticOperator::POW)
+ {
+ return 3;
+ }
+ else
+ {
+ return 2;
+ }
+}
+void ScalarOperatorNode::generateDotTree(QString& s)
+{
+ auto id= toString(true);
+ if(s.contains(id))
+ return;
+ s.append(id);
+ s.append(";\n");
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr");
+ s.append(" [label=\"nextNode\"];\n");
+ }
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+ QString str;
+ str.append("\n");
+ if(nullptr != m_internalNode)
+ {
+ str.append(toString(false));
+ str.append(" -> ");
+ str.append(m_internalNode->toString(false));
+ str.append(" [label=\"internalNode\"];\n");
+ m_internalNode->generateDotTree(str);
+ }
+ s.append(str);
+}
+QMap<Dice::ERROR_CODE, QString> ScalarOperatorNode::getExecutionErrorMap()
+{
+ if(nullptr != m_internalNode)
+ {
+ auto keys= m_internalNode->getExecutionErrorMap().keys();
+ for(const auto& key : keys)
+ {
+ m_errors.insert(key, m_internalNode->getExecutionErrorMap().value(key));
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ auto keys= m_nextNode->getExecutionErrorMap().keys();
+ for(auto const& key : keys)
+ {
+ m_errors.insert(key, m_nextNode->getExecutionErrorMap().value(key));
+ }
+ }
+ return m_errors;
+}
+ExecutionNode* ScalarOperatorNode::getCopy() const
+{
+ ScalarOperatorNode* node= new ScalarOperatorNode();
+ node->setInternalNode(m_internalNode->getCopy());
+ node->setArithmeticOperator(m_arithmeticOperator);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/scalaroperatornode.h b/src/libparser/node/scalaroperatornode.h
new file mode 100644
index 0000000..57a1049
--- /dev/null
+++ b/src/libparser/node/scalaroperatornode.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SCALAROPERATORNODE_H
+#define SCALAROPERATORNODE_H
+
+#include <QChar>
+#include <QMap>
+
+#include "die.h"
+#include "executionnode.h"
+#include "result/scalarresult.h"
+
+/**
+ * @brief The ScalarOperatorNode class
+ */
+class ScalarOperatorNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief The ArithmeticOperator enum
+ */
+ // enum ArithmeticOperator {PLUS,MINUS,DIVIDE,MULTIPLICATION};
+ /**
+ * @brief ScalarOperatorNode
+ */
+ ScalarOperatorNode();
+ /**
+ * @brief ~ScalarOperatorNode
+ */
+ virtual ~ScalarOperatorNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief setInternalNode
+ * @param node
+ */
+ void setInternalNode(ExecutionNode* node);
+ /**
+ * @brief toString
+ * @param wl
+ * @return
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief generateDotTree
+ * @param s
+ */
+ void generateDotTree(QString& s);
+ /**
+ * @brief getErrorList
+ * @return
+ */
+ virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap();
+ /**
+ * @brief getArithmeticOperator
+ * @return
+ */
+ Dice::ArithmeticOperator getArithmeticOperator() const;
+ /**
+ * @brief setArithmeticOperator
+ * @param arithmeticOperator
+ */
+ void setArithmeticOperator(const Dice::ArithmeticOperator& arithmeticOperator);
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ /**
+ * @brief add
+ * @return
+ */
+ static qint64 add(qreal, qreal);
+ /**
+ * @brief substract
+ * @return
+ */
+ static qint64 substract(qreal, qreal);
+ /**
+ * @brief divide not static because of error management
+ * @return
+ */
+ qreal divide(qreal, qreal);
+ /**
+ * @brief multiple
+ * @return
+ */
+ static qint64 multiple(qreal, qreal);
+
+ static qint64 pow(qreal a, qreal b);
+
+private:
+ ExecutionNode* m_internalNode;
+ ScalarResult* m_scalarResult;
+ Dice::ArithmeticOperator m_arithmeticOperator;
+};
+
+#endif // SCALAROPERATORNODE_H
diff --git a/src/libparser/node/sortresult.cpp b/src/libparser/node/sortresult.cpp
new file mode 100644
index 0000000..5d514cf
--- /dev/null
+++ b/src/libparser/node/sortresult.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "sortresult.h"
+
+#include "die.h"
+
+SortResultNode::SortResultNode() : m_diceResult(new DiceResult)
+{
+ m_ascending= true;
+ m_result= m_diceResult;
+}
+void SortResultNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_diceResult->setPrevious(previousDiceResult);
+ if(nullptr == previousDiceResult)
+ return;
+
+ auto const& diceList= previousDiceResult->getResultList();
+ QList<Die*> diceList2= m_diceResult->getResultList();
+
+ /* const auto& asce = [](const Die* a,const Die* b){
+ return a->getValue() < b->getValue();
+ };
+ const auto& desc = [](const Die* a,const Die* b){
+ return a->getValue() > b->getValue();
+ };
+
+ for(auto const dice : diceList)
+ {
+ Die* tmp1 = new Die(*dice);
+ diceList2.append(tmp1);
+ }
+ if(m_ascending)
+ std::sort(diceList2.begin(), diceList2.end(), asce);
+ else
+ std::sort(diceList2.begin(), diceList2.end(), desc);*/
+
+ // half-interval search sorting
+ for(int i= 0; i < diceList.size(); ++i)
+ {
+ Die* tmp1= new Die(*diceList[i]);
+ //qDebug() << tmp1->getColor() << diceList[i]->getColor();
+ //*tmp1=*diceList[i];
+ diceList[i]->displayed();
+
+ int j= 0;
+ bool found= false;
+ int start= 0;
+ int end= diceList2.size();
+ Die* tmp2= nullptr;
+ while(!found)
+ {
+ int distance= end - start;
+ j= (start + end) / 2;
+ if(distance == 0)
+ {
+ j= end;
+ found= true;
+ }
+ else
+ {
+ tmp2= diceList2[j];
+ if(tmp1->getValue() < tmp2->getValue())
+ {
+ end= j;
+ }
+ else
+ {
+ start= j + 1;
+ }
+ }
+ }
+ diceList2.insert(j, tmp1);
+ }
+
+ if(!m_ascending)
+ {
+ for(int i= 0; i < diceList2.size() / 2; ++i)
+ {
+ diceList2.swapItemsAt(i, diceList2.size() - (1 + i));
+ }
+ }
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+void SortResultNode::setSortAscending(bool asc)
+{
+ m_ascending= asc;
+}
+QString SortResultNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ auto order= m_ascending ? QStringLiteral("Ascending") : QStringLiteral("Descending");
+ return QString("%1 [label=\"SortResultNode %2\"]").arg(m_id, order);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 SortResultNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* SortResultNode::getCopy() const
+{
+ SortResultNode* node= new SortResultNode();
+ node->setSortAscending(m_ascending);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/sortresult.h b/src/libparser/node/sortresult.h
new file mode 100644
index 0000000..f7510be
--- /dev/null
+++ b/src/libparser/node/sortresult.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SORTRESULT_H
+#define SORTRESULT_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The SortResultNode class is an ExecutionNode, and it is dedicated to sort dice list.
+ * The sort is made by hand, using half-interval search algorithm.
+ */
+class SortResultNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief SortResultNode
+ */
+ SortResultNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+
+ /**
+ * @brief setSortAscending
+ * @param asc
+ */
+ void setSortAscending(bool asc);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ bool m_ascending;
+ DiceResult* m_diceResult;
+};
+
+#endif // SORTRESULT_H
diff --git a/src/libparser/node/splitnode.cpp b/src/libparser/node/splitnode.cpp
new file mode 100644
index 0000000..8faa0a5
--- /dev/null
+++ b/src/libparser/node/splitnode.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "splitnode.h"
+
+SplitNode::SplitNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void SplitNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ for(auto& oldDie : dice->getResultList())
+ {
+ oldDie->displayed();
+ m_diceResult->setOperator(oldDie->getOp());
+ for(qint64& value : oldDie->getListValue())
+ {
+ Die* tmpdie= new Die();
+ tmpdie->insertRollValue(value);
+ tmpdie->setBase(oldDie->getBase());
+ tmpdie->setMaxValue(oldDie->getMaxValue());
+ tmpdie->setValue(value);
+ tmpdie->setOp(oldDie->getOp());
+ m_diceResult->insertResult(tmpdie);
+ }
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString SplitNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SplitNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 SplitNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* SplitNode::getCopy() const
+{
+ SplitNode* node= new SplitNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/splitnode.h b/src/libparser/node/splitnode.h
new file mode 100644
index 0000000..0ceeb00
--- /dev/null
+++ b/src/libparser/node/splitnode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SPLITNODE_H
+#define SPLITNODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The SplitNode class is an ExecutionNode. It is dedicated to split result of one dice into one dimension array.
+ */
+class SplitNode : public ExecutionNode
+{
+public:
+ SplitNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/startingnode.cpp b/src/libparser/node/startingnode.cpp
new file mode 100644
index 0000000..97248c6
--- /dev/null
+++ b/src/libparser/node/startingnode.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "startingnode.h"
+#include <QDebug>
+
+StartingNode::StartingNode() {}
+void StartingNode::run(ExecutionNode*)
+{
+ m_previousNode= nullptr;
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString StartingNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"StartingNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 StartingNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* StartingNode::getCopy() const
+{
+ StartingNode* node= new StartingNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/startingnode.h b/src/libparser/node/startingnode.h
new file mode 100644
index 0000000..eea72a9
--- /dev/null
+++ b/src/libparser/node/startingnode.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef STARTINGNODE_H
+#define STARTINGNODE_H
+
+#include "executionnode.h"
+
+/**
+ * @brief The StartingNode class is an ExecutionNode, StartingNode is dedicated to be the first node
+ * in the execution tree.
+ */
+class StartingNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief StartingNode
+ */
+ StartingNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withlabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+};
+
+#endif // STARTINGNODE_H
diff --git a/src/libparser/node/stringnode.cpp b/src/libparser/node/stringnode.cpp
new file mode 100644
index 0000000..e908463
--- /dev/null
+++ b/src/libparser/node/stringnode.cpp
@@ -0,0 +1,58 @@
+#include "stringnode.h"
+
+StringNode::StringNode() : m_stringResult(new StringResult())
+{
+ m_result= m_stringResult;
+}
+
+void StringNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void StringNode::setString(QString str)
+{
+ m_data= str;
+ m_stringResult->addText(m_data);
+ m_stringResult->finished();
+}
+QString StringNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ QString dataCopy= m_data;
+
+ return QString("%1 [label=\"StringNode %2\"]").arg(m_id, dataCopy.replace('%', '\\'));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 StringNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* StringNode::getCopy() const
+{
+ StringNode* node= new StringNode();
+ node->setString(m_data);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/stringnode.h b/src/libparser/node/stringnode.h
new file mode 100644
index 0000000..4079b7f
--- /dev/null
+++ b/src/libparser/node/stringnode.h
@@ -0,0 +1,29 @@
+#ifndef STRINGNODE_H
+#define STRINGNODE_H
+
+#include "node/executionnode.h"
+#include "result/stringresult.h"
+
+/**
+ * @brief The StringNode class is an ExecutionNode. It is dedicated to store string and display result.
+ */
+class StringNode : public ExecutionNode
+{
+public:
+ StringNode();
+ void run(ExecutionNode* previous);
+ void setString(QString str);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ QString m_data;
+ StringResult* m_stringResult;
+};
+
+#endif // STRINGNODE_H
diff --git a/src/libparser/node/switchcasenode.cpp b/src/libparser/node/switchcasenode.cpp
new file mode 100644
index 0000000..880fa4d
--- /dev/null
+++ b/src/libparser/node/switchcasenode.cpp
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "switchcasenode.h"
+
+#include "stringresult.h"
+#include <QDebug>
+#include <diceparser/parsingtoolbox.h>
+
+SwitchCaseNode::SwitchCaseNode() : m_stringResult(new StringResult)
+{
+ m_result= m_stringResult;
+}
+
+void SwitchCaseNode::setStopAtFirt(bool b)
+{
+ m_stopAtFirst= b;
+}
+
+void SwitchCaseNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR,
+ QStringLiteral("No previous node before Switch/Case operator"));
+ return;
+ }
+ auto previousResult= previous->getResult();
+ m_result->setPrevious(previousResult);
+
+ if(nullptr == previousResult
+ || (!previousResult->hasResultOfType(Dice::RESULT_TYPE::SCALAR)
+ && !previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QStringLiteral("No scalar or dice result before Switch/Case operator"));
+ return;
+ }
+
+ auto diceResult= dynamic_cast<DiceResult*>(previousResult);
+
+ QSet<QString> alreadyValidDice;
+ QStringList finalResultList;
+ if(diceResult)
+ {
+ for(auto die : diceResult->getResultList())
+ {
+ QStringList resultList;
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ if(m_stopAtFirst && !resultList.isEmpty())
+ break;
+ if(info->validatorList)
+ {
+ if(info->validatorList->hasValid(die, true))
+ {
+ auto lastNode= ParsingToolBox::getLeafNode(info->node);
+ if(lastNode && lastNode->getResult())
+ {
+ resultList << lastNode->getResult()->getStringResult();
+ }
+ }
+ }
+ else if(resultList.isEmpty())
+ {
+ info->node->run(m_previousNode);
+ auto lastNode= ParsingToolBox::getLeafNode(info->node);
+ if(lastNode && lastNode->getResult())
+ {
+ resultList << lastNode->getResult()->getStringResult();
+ }
+ else
+ resultList << QString();
+ }
+ }
+ finalResultList << resultList;
+ }
+ }
+ for(auto const& str : qAsConst(finalResultList))
+ m_stringResult->addText(str);
+
+ if(m_stringResult->getText().isEmpty())
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT, QStringLiteral("No value fits the Switch/Case operator"));
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString SwitchCaseNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SwitchCaseNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 SwitchCaseNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* SwitchCaseNode::getCopy() const
+{
+ SwitchCaseNode* node= new SwitchCaseNode();
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ node->insertCase(info->node, info->validatorList);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void SwitchCaseNode::insertCase(ExecutionNode* node, ValidatorList* validator)
+{
+ std::unique_ptr<Dice::CaseInfo> info(new Dice::CaseInfo{validator, node});
+ m_branchList.push_back(std::move(info));
+}
diff --git a/src/libparser/node/switchcasenode.h b/src/libparser/node/switchcasenode.h
new file mode 100644
index 0000000..a0f658d
--- /dev/null
+++ b/src/libparser/node/switchcasenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SWITCHCASENODE_H
+#define SWITCHCASENODE_H
+
+#include <memory>
+#include <vector>
+
+#include "executionnode.h"
+#include "validatorlist.h"
+
+class StringResult;
+class SwitchCaseNode : public ExecutionNode
+{
+public:
+ SwitchCaseNode();
+ void setStopAtFirt(bool b);
+
+ void run(ExecutionNode* previous= nullptr) override;
+
+ QString toString(bool withLabel) const override;
+ qint64 getPriority() const override;
+ ExecutionNode* getCopy() const override;
+
+ void insertCase(ExecutionNode* node, ValidatorList* validator);
+
+private:
+ std::vector<std::unique_ptr<Dice::CaseInfo>> m_branchList;
+ StringResult* m_stringResult;
+ bool m_stopAtFirst= false;
+};
+
+#endif // SWITCHCASENODE_H
diff --git a/src/libparser/node/uniquenode.cpp b/src/libparser/node/uniquenode.cpp
new file mode 100644
index 0000000..c4668be
--- /dev/null
+++ b/src/libparser/node/uniquenode.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "uniquenode.h"
+
+UniqueNode::UniqueNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void UniqueNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ auto const& resultList= dice->getResultList();
+ std::vector<qint64> formerValues;
+ formerValues.reserve(resultList.size());
+ for(auto& oldDie : resultList)
+ {
+ auto value= oldDie->getValue();
+ auto it= std::find(formerValues.begin(), formerValues.end(), value);
+
+ if(it == formerValues.end())
+ {
+ auto die= new Die(*oldDie);
+ m_diceResult->insertResult(die);
+ formerValues.push_back(value);
+ }
+ oldDie->displayed();
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString UniqueNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"UniqueNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 UniqueNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* UniqueNode::getCopy() const
+{
+ UniqueNode* node= new UniqueNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/uniquenode.h b/src/libparser/node/uniquenode.h
new file mode 100644
index 0000000..039ba11
--- /dev/null
+++ b/src/libparser/node/uniquenode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef UNIQUENODE_H
+#define UNIQUENODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The UniqueNode class is an ExecutionNode. It is dedicated to unique result of one dice into one dimension array.
+ */
+class UniqueNode : public ExecutionNode
+{
+public:
+ UniqueNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/valueslistnode.cpp b/src/libparser/node/valueslistnode.cpp
new file mode 100644
index 0000000..33a347d
--- /dev/null
+++ b/src/libparser/node/valueslistnode.cpp
@@ -0,0 +1,62 @@
+#include "valueslistnode.h"
+
+#include "variablenode.h"
+
+ValuesListNode::ValuesListNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+
+void ValuesListNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ for(auto node : m_data)
+ {
+ node->run(this);
+ auto result= node->getResult();
+ if(!result)
+ continue;
+ auto val= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ Die* die= new Die();
+ auto dyna= dynamic_cast<VariableNode*>(node);
+ if(nullptr != dyna)
+ dyna->setDisplayed();
+ die->insertRollValue(val);
+ m_diceResult->insertResult(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void ValuesListNode::insertValue(ExecutionNode* value)
+{
+ m_data.push_back(value);
+}
+ExecutionNode* ValuesListNode::getCopy() const
+{
+ ValuesListNode* node= new ValuesListNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+QString ValuesListNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"ValuesListNode list:\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ValuesListNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
diff --git a/src/libparser/node/valueslistnode.h b/src/libparser/node/valueslistnode.h
new file mode 100644
index 0000000..100f275
--- /dev/null
+++ b/src/libparser/node/valueslistnode.h
@@ -0,0 +1,24 @@
+#ifndef VALUESLISTNODE_H
+#define VALUESLISTNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValuesListNode : public ExecutionNode
+{
+public:
+ ValuesListNode();
+
+ virtual void run(ExecutionNode* previous= nullptr) override;
+ virtual QString toString(bool) const override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+
+ void insertValue(ExecutionNode*);
+
+private:
+ std::vector<ExecutionNode*> m_data;
+ DiceResult* m_diceResult = nullptr;
+};
+
+#endif // VALUESLISTNODE_H
diff --git a/src/libparser/node/variablenode.cpp b/src/libparser/node/variablenode.cpp
new file mode 100644
index 0000000..709ab46
--- /dev/null
+++ b/src/libparser/node/variablenode.cpp
@@ -0,0 +1,112 @@
+#include "variablenode.h"
+
+#include "diceresult.h"
+#include <diceparser/parsingtoolbox.h>
+
+VariableNode::VariableNode() {}
+
+void VariableNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != m_data) && (m_data->size() > m_index))
+ {
+ auto value= (*m_data)[m_index];
+ value= ParsingToolBox::getLeafNode(value);
+ if(nullptr == value)
+ return;
+
+ auto result= value->getResult();
+ if(!result)
+ return;
+
+ m_result= result->getCopy();
+ auto diceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != diceResult)
+ {
+ for(auto& die : diceResult->getResultList())
+ {
+ die->setDisplayed(false);
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ else
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VARIBALE, QObject::tr("No variable at index:%1").arg(m_index + 1));
+ }
+}
+
+void VariableNode::setDisplayed()
+{
+ if(!m_result)
+ return;
+ auto diceResult= dynamic_cast<DiceResult*>(m_result);
+ if(nullptr == diceResult)
+ return;
+
+ for(auto& die : diceResult->getResultList())
+ {
+ die->setDisplayed(true);
+ }
+}
+
+QString VariableNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"VariableNode index: %2\"]").arg(m_id).arg(m_index + 1);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 VariableNode::getPriority() const
+{
+ qint64 priority= 4;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* VariableNode::getCopy() const
+{
+ VariableNode* node= new VariableNode();
+ node->setIndex(m_index);
+ if(nullptr != m_data)
+ {
+ node->setData(m_data);
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+quint64 VariableNode::getIndex() const
+{
+ return m_index;
+}
+
+void VariableNode::setIndex(quint64 index)
+{
+ m_index= index;
+}
+
+std::vector<ExecutionNode*>* VariableNode::getData() const
+{
+ return m_data;
+}
+
+void VariableNode::setData(std::vector<ExecutionNode*>* data)
+{
+ m_data= data;
+}
diff --git a/src/libparser/node/variablenode.h b/src/libparser/node/variablenode.h
new file mode 100644
index 0000000..8bf1cb1
--- /dev/null
+++ b/src/libparser/node/variablenode.h
@@ -0,0 +1,35 @@
+#ifndef VARIABLENODE_H
+#define VARIABLENODE_H
+
+#include "node/executionnode.h"
+
+/**
+ * @brief The VariableNode class is an ExecutionNode. It is dedicated to retrive
+ * variable value from other starting node.
+ */
+class VariableNode : public ExecutionNode
+{
+public:
+ VariableNode();
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const override;
+ quint64 getIndex() const;
+ void setIndex(quint64 index);
+
+ std::vector<ExecutionNode*>* getData() const;
+ void setData(std::vector<ExecutionNode*>* data);
+
+ void setDisplayed();
+
+private:
+ quint64 m_index;
+ std::vector<ExecutionNode*>* m_data= nullptr;
+};
+
+#endif // VARIABLENODE_H