From 57acb8a12a2d9b66145a0a8382e4536a4170c1b0 Mon Sep 17 00:00:00 2001 From: Renaud G Date: Wed, 18 May 2022 01:10:24 +0200 Subject: Add limitation support for explode node. --- HelpMe.md | 12 +++ src/libparser/include/diceparser/parsingtoolbox.h | 8 -- src/libparser/node/explodedicenode.cpp | 112 ++++++++++++---------- src/libparser/node/explodedicenode.h | 5 +- src/libparser/parsingtoolbox.cpp | 60 ++++++------ src/tests/dice/tst_dice.cpp | 2 + 6 files changed, 111 insertions(+), 88 deletions(-) diff --git a/HelpMe.md b/HelpMe.md index f67c04c..ada912b 100644 --- a/HelpMe.md +++ b/HelpMe.md @@ -297,6 +297,18 @@ Works like "Reroll", but continue to roll the dice until the condition is false. Explode while the value fits the Validator (See Validator for more details about syntax). +``` +3D10e(3)[Validator] +``` + +Explode node can have a limit of how many times the die will explode. + +``` +3D10e(1d10)[Validator] +``` + +The limit is a expression. + ### Examples ``` diff --git a/src/libparser/include/diceparser/parsingtoolbox.h b/src/libparser/include/diceparser/parsingtoolbox.h index 69f433a..207b878 100644 --- a/src/libparser/include/diceparser/parsingtoolbox.h +++ b/src/libparser/include/diceparser/parsingtoolbox.h @@ -32,14 +32,6 @@ #include "diceparserhelper.h" #include "highlightdice.h" -//#include "dicerollernode.h" -//#include "executionnode.h" -//#include "node/ifnode.h" -//#include "node/paintnode.h" -//#include "node/scalaroperatornode.h" -//#include "operationcondition.h" -//#include "range.h" -//#include "validatorlist.h" #include class Range; diff --git a/src/libparser/node/explodedicenode.cpp b/src/libparser/node/explodedicenode.cpp index 1546883..7c9708b 100644 --- a/src/libparser/node/explodedicenode.cpp +++ b/src/libparser/node/explodedicenode.cpp @@ -1,4 +1,5 @@ #include "explodedicenode.h" +#include "diceparser/parsingtoolbox.h" #include "validatorlist.h" ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult()) @@ -8,66 +9,70 @@ ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult()) void ExplodeDiceNode::run(ExecutionNode* previous) { m_previousNode= previous; - if((nullptr != previous) && (nullptr != previous->getResult())) - { - DiceResult* previous_result= dynamic_cast(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; - } + if(!previous) + return; - // QList list= m_diceResult->getResultList(); + if(!previous->getResult()) + return; - bool hasExploded= false; - std::function f= [&hasExploded, this](Die* die, qint64) { - if(Dice::CONDITION_STATE::ALWAYSTRUE - == m_validatorList->isValidRangeSize( - std::make_pair(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(die->getBase())) - .arg(static_cast(die->getMaxValue())))); - } - hasExploded= true; - die->roll(true); - }; - do - { - hasExploded= false; - m_validatorList->validResult(m_diceResult, false, false, f); - } while(hasExploded); + DiceResult* previous_result= dynamic_cast(previous->getResult()); + m_result->setPrevious(previous_result); - /*for(auto& die : list) - { - if(Dice::CONDITION_STATE::ALWAYSTRUE - == m_validatorList->isValidRangeSize( - std::make_pair(die->getBase(), die->getMaxValue()))) - { + if(!previous_result) + return; - continue; - } + for(auto& die : previous_result->getResultList()) + { + Die* tmpdie= new Die(*die); + m_diceResult->insertResult(tmpdie); + die->displayed(); + } - while(m_validatorList->hasValid(die, false)) - { - die->roll(true); - } - }*/ + quint64 limit= -1; + if(m_limit) + { + m_limit->run(this); + auto limitNode= ParsingToolBox::getLeafNode(m_limit); + auto result= limitNode->getResult(); + if(result->hasResultOfType(Dice::RESULT_TYPE::SCALAR)) + limit= static_cast(result->getResult(Dice::RESULT_TYPE::SCALAR).toInt()); + } - if(nullptr != m_nextNode) + bool hasExploded= false; + std::function f= [&hasExploded, this, limit](Die* die, qint64) { + static QHash explodePerDice; + if(Dice::CONDITION_STATE::ALWAYSTRUE + == m_validatorList->isValidRangeSize(std::make_pair(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(die->getBase())) + .arg(static_cast(die->getMaxValue())))); + } + hasExploded= true; + if(limit >= 0) + { + auto& d= explodePerDice[die]; + if(d == limit) { - m_nextNode->run(this); + hasExploded= false; + return; } + ++d; } + die->roll(true); + }; + do + { + hasExploded= false; + m_validatorList->validResult(m_diceResult, false, false, f); + } while(hasExploded); + + if(nullptr != m_nextNode) + { + m_nextNode->run(this); } } ExplodeDiceNode::~ExplodeDiceNode() @@ -115,3 +120,8 @@ ExecutionNode* ExplodeDiceNode::getCopy() const } return node; } + +void ExplodeDiceNode::setLimitNode(ExecutionNode* limitNode) +{ + m_limit= limitNode; +} diff --git a/src/libparser/node/explodedicenode.h b/src/libparser/node/explodedicenode.h index 77b4a44..4a561e6 100644 --- a/src/libparser/node/explodedicenode.h +++ b/src/libparser/node/explodedicenode.h @@ -21,9 +21,12 @@ public: virtual ExecutionNode* getCopy() const; + void setLimitNode(ExecutionNode* limitNode); + protected: DiceResult* m_diceResult; - ValidatorList* m_validatorList= nullptr; + ValidatorList* m_validatorList{nullptr}; + ExecutionNode* m_limit{nullptr}; }; #endif // EXPLOSEDICENODE_H diff --git a/src/libparser/parsingtoolbox.cpp b/src/libparser/parsingtoolbox.cpp index dfde37f..575b7b9 100644 --- a/src/libparser/parsingtoolbox.cpp +++ b/src/libparser/parsingtoolbox.cpp @@ -183,9 +183,9 @@ bool ParsingToolBox::readDiceLogicOperator(QString& str, Dice::ConditionOperator bool ParsingToolBox::readArithmeticOperator(QString& str, Dice::ArithmeticOperator& op) { - auto it= std::find_if(m_arithmeticOperation.begin(), m_arithmeticOperation.end(), - [str](const std::pair& pair) - { return str.startsWith(pair.first); }); + auto it= std::find_if( + m_arithmeticOperation.begin(), m_arithmeticOperation.end(), + [str](const std::pair& pair) { return str.startsWith(pair.first); }); if(it == m_arithmeticOperation.end()) return false; @@ -714,13 +714,11 @@ QString ParsingToolBox::finalStringResult(std::function>>& map) - { + [](const std::vector>>& map) { QStringList valuesStr; auto multiKey= (map.size() > 1); for(auto item : map) @@ -1290,21 +1287,18 @@ QString ParsingToolBox::replacePlaceHolderToValue(const QString& source, const Q QStringList resultList; std::transform( std::begin(list), std::end(list), std::back_inserter(resultList), - [removeUnhighlighted, colorize](const ExportedDiceResult& dice) - { + [removeUnhighlighted, colorize](const ExportedDiceResult& dice) { QStringList valuesStr; if(dice.size() == 1) { auto values= dice.values(); std::transform( std::begin(values), std::end(values), std::back_inserter(valuesStr), - [removeUnhighlighted, colorize](const QList& dice) - { + [removeUnhighlighted, colorize](const QList& dice) { QStringList textList; std::transform( std::begin(dice), std::end(dice), std::back_inserter(textList), - [removeUnhighlighted, colorize](const ListDiceResult& dice) - { + [removeUnhighlighted, colorize](const ListDiceResult& dice) { QStringList list; ListDiceResult values= dice; if(removeUnhighlighted) @@ -1315,8 +1309,9 @@ QString ParsingToolBox::replacePlaceHolderToValue(const QString& source, const Q } std::transform(std::begin(values), std::end(values), std::back_inserter(list), - [colorize](const HighLightDice& hl) - { return colorize(hl.getResultString(), {}, hl.isHighlighted()); }); + [colorize](const HighLightDice& hl) { + return colorize(hl.getResultString(), {}, hl.isHighlighted()); + }); return list.join(","); }); textList.removeAll(QString()); @@ -1746,6 +1741,9 @@ bool ParsingToolBox::readOption(QString& str, ExecutionNode* previous) //, break; case Explode: { + ExecutionNode* limit= nullptr; + auto hasLimit= readParameterNode(str, limit); + auto validatorList= readValidatorList(str); if(nullptr != validatorList) { @@ -1756,6 +1754,11 @@ bool ParsingToolBox::readOption(QString& str, ExecutionNode* previous) //, .arg(validatorList->toString())); } ExplodeDiceNode* explodedNode= new ExplodeDiceNode(); + + if(hasLimit) + { + explodedNode->setLimitNode(limit); + } explodedNode->setValidatorList(validatorList); previous->setNextNode(explodedNode); found= true; @@ -1949,18 +1952,19 @@ ExplodeDiceNode* ParsingToolBox::addExplodeDiceNode(qint64 value, ExecutionNode* } bool ParsingToolBox::readParameterNode(QString& str, ExecutionNode*& node) { - if(str.startsWith("(")) + if(!str.startsWith("(")) + return false; + + str= str.remove(0, 1); + if(readExpression(str, node)) { - str= str.remove(0, 1); - if(readExpression(str, node)) + if(str.startsWith(")")) { - if(str.startsWith(")")) - { - str= str.remove(0, 1); - return true; - } + str= str.remove(0, 1); + return true; } } + return false; } diff --git a/src/tests/dice/tst_dice.cpp b/src/tests/dice/tst_dice.cpp index 9318341..77b4944 100644 --- a/src/tests/dice/tst_dice.cpp +++ b/src/tests/dice/tst_dice.cpp @@ -322,6 +322,7 @@ void TestDice::commandsTest_data() QTest::addRow("cmd12") << "1D100a[>=95]a[>=96]a[>=97]a[>=98]a[>=99]e[>=100]"; QTest::addRow("cmd13") << "3D100"; QTest::addRow("cmd14") << "4k3"; + QTest::addRow("cmd15") << "10D10e[>=6]sc[>=6]"; QTest::addRow("cmd16") << "10D10e10s"; QTest::addRow("cmd17") << "10D10s"; @@ -392,6 +393,7 @@ void TestDice::commandsTest_data() QTest::addRow("cmd90") << "1L[-3,-2,2,3]+10;1L[-3,-2,2,3]"; QTest::addRow("cmd91") << "1d20|3i:[>1]{\"Success\"}{\"Failure\"}"; QTest::addRow("cmd92") << "4d10k3;4d10k3;4d10k3;[$1,$2,$3]s;\"Score @4\""; + QTest::addRow("cmd93") << "4d10e(10)10"; } void TestDice::rangedCommandsTest() -- cgit v1.2.3-70-g09d2