From 6fcb5ca46927f7baab744e117af9eb1ce5b74838 Mon Sep 17 00:00:00 2001 From: Renaud Guezennec Date: Sun, 9 Feb 2025 06:05:05 +0100 Subject: [Dice] add functions: floor, ceil, round --- HelpMe.md | 37 +++++++++++- README.md | 2 +- src/libparser/CMakeLists.txt | 2 + src/libparser/include/diceparser/parsingtoolbox.h | 9 ++- src/libparser/node/roundnode.cpp | 71 +++++++++++++++++++++++ src/libparser/node/roundnode.h | 31 ++++++++++ src/libparser/parsingtoolbox.cpp | 57 ++++++++++++++++-- src/tests/dice/tst_dice.cpp | 2 + 8 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 src/libparser/node/roundnode.cpp create mode 100644 src/libparser/node/roundnode.h diff --git a/HelpMe.md b/HelpMe.md index 6c75022..251f61a 100644 --- a/HelpMe.md +++ b/HelpMe.md @@ -429,7 +429,7 @@ Merge operator is used for gathering several dice rolls from different die type This command merges together the result from the d6 and the d8. Then, it applied the k operator on both result to keep the best. Be careful, this operator merges the instruction list. Instruction reference (such as $1 etc..) won't work after merge operator. -### Spead +### Spread It makes exploded dice as new dice. The operator is trigged by *y*. @@ -439,7 +439,7 @@ The operator is trigged by *y*. ``` First Result: `10 [6, 4], 3, 3, 2` -Result after spead: `6, 4, 3, 2` +Result after spread: `6, 4, 3, 2` Final result: `6+4+3 = 13` ### All the same @@ -657,6 +657,39 @@ Output: Attention! Be careful, `repeat` works badly with multiple instruction commands + +### Floor + +* 15/7 = 2.14286 +* Floor(15/7) = 2 + +The command: + +> 15/7;**floor($1)**;ceil($1);round($1) + +> result: 2.14286,**2**,3,2 + +### Ceil + +* 15/7 = 2.14286 +* Ceil(15/7) = 3 + +The command: + +> 15/7;floor($1);**ceil($1)**;round($1) + +> result: 2.14286,2, **3** ,2 + +### Round + +* 15/7 = 2.14286 +* Round(15/7) = 2 + +The command: + +> 15/7;floor($1);ceil($1);**round($1)** + +> result: 2.14286,2,3, **2** ## The output DiceParser provides features to let you control the command output. diff --git a/README.md b/README.md index dfec679..9ff7af2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Logo](https://invent.kde.org/rolisteam/rolisteam/-/raw/master/resources/rolistheme/1000-rolisteam.png)](http://www.rolisteam.org) +[![Logo](https://invent.kde.org/rolisteam/rolisteam/-/raw/master/resources/logo/1000-rolisteam.png)](http://www.rolisteam.org) # DiceParser diff --git a/src/libparser/CMakeLists.txt b/src/libparser/CMakeLists.txt index 80b9a25..7937506 100644 --- a/src/libparser/CMakeLists.txt +++ b/src/libparser/CMakeLists.txt @@ -67,6 +67,8 @@ SET( dice_sources ${CMAKE_CURRENT_SOURCE_DIR}/node/repeaternode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/node/switchcasenode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/node/replacevaluenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/roundnode.cpp + ) include(install_helper OPTIONAL RESULT_VARIABLE installFound) diff --git a/src/libparser/include/diceparser/parsingtoolbox.h b/src/libparser/include/diceparser/parsingtoolbox.h index 8cd9c25..2700ae4 100644 --- a/src/libparser/include/diceparser/parsingtoolbox.h +++ b/src/libparser/include/diceparser/parsingtoolbox.h @@ -36,6 +36,7 @@ #include class Range; class RepeaterNode; +class RoundNode; class DiceAlias; class ExplodeDiceNode; class SwitchCaseNode; @@ -92,7 +93,10 @@ public: enum Function { - REPEAT + REPEAT, + FLOOR, + CEIL, + ROUND }; enum OptionOperator { @@ -167,7 +171,8 @@ public: static void readSubtitutionParameters(SubtituteInfo& info, QString& rest); static bool readPainterParameter(PainterNode* painter, QString& str); static bool readComma(QString& str); - bool readReaperArguments(RepeaterNode* node, QString& source); + bool readRepeaterArguments(RepeaterNode* node, QString& source); + bool readRoundArguments(RoundNode* node, QString& source); bool readExpression(QString& str, ExecutionNode*& node); bool readInstructionOperator(QChar c); bool readNode(QString& str, ExecutionNode*& node); diff --git a/src/libparser/node/roundnode.cpp b/src/libparser/node/roundnode.cpp new file mode 100644 index 0000000..8f825f5 --- /dev/null +++ b/src/libparser/node/roundnode.cpp @@ -0,0 +1,71 @@ +#include "roundnode.h" + +#include + +RoundNode::RoundNode(Mode mode) : m_scalarResult(new ScalarResult), m_mode(mode) {} + +void RoundNode::run(ExecutionNode* previous) +{ + m_previousNode= previous; + + if(m_cmd == nullptr) + return; + + m_cmd->execute(this); + auto internal= ParsingToolBox::getLeafNode(m_cmd); + if(!internal) + return; + + auto endResult= internal->getResult(); + + auto scalar= endResult->getResult(Dice::RESULT_TYPE::SCALAR).toDouble(); + + int resVal; + switch(m_mode) + { + case FLOOR: + resVal= std::floor(scalar); + break; + case CEIL: + resVal= std::ceil(scalar); + break; + case ROUND: + resVal= std::round(scalar); + break; + } + + m_scalarResult->setValue(resVal); + m_result= m_scalarResult.get(); +} + +QString RoundNode::toString(bool withLabel) const +{ + + return withLabel ? QString("%1 [label=\"RoundNode\"]").arg(m_id) : m_id; +} + +qint64 RoundNode::getPriority() const +{ + qint64 priority= 0; + if(nullptr != m_nextNode) + { + priority= m_nextNode->getPriority(); + } + + return priority; +} + +ExecutionNode* RoundNode::getCopy() const +{ + RoundNode* node= new RoundNode(m_mode); + if(nullptr != m_nextNode) + { + node->setNextNode(m_nextNode->getCopy()); + } + return node; +} + +void RoundNode::setCommand(ExecutionNode* cmd) +{ + m_cmd= cmd; +} diff --git a/src/libparser/node/roundnode.h b/src/libparser/node/roundnode.h new file mode 100644 index 0000000..0bf49b7 --- /dev/null +++ b/src/libparser/node/roundnode.h @@ -0,0 +1,31 @@ +#ifndef ROUNDNODE_H +#define ROUNDNODE_H + +#include "executionnode.h" +#include "scalarresult.h" + +class RoundNode : public ExecutionNode +{ +public: + enum Mode { + FLOOR, + CEIL, + ROUND + }; + RoundNode(Mode mode); + + // ExecutionNode interface +public: + void run(ExecutionNode *previous); + QString toString(bool withLabel) const; + qint64 getPriority() const; + ExecutionNode *getCopy() const; + void setCommand(ExecutionNode* cmd); + +private: + std::unique_ptr m_scalarResult; + ExecutionNode* m_cmd= nullptr; + Mode m_mode{ROUND}; +}; + +#endif // ROUNDNODE_H diff --git a/src/libparser/parsingtoolbox.cpp b/src/libparser/parsingtoolbox.cpp index a7b089d..b0d41a7 100644 --- a/src/libparser/parsingtoolbox.cpp +++ b/src/libparser/parsingtoolbox.cpp @@ -61,6 +61,7 @@ #include "node/variablenode.h" #include "operationcondition.h" #include "range.h" +#include "roundnode.h" #include "validatorlist.h" QHash ParsingToolBox::m_variableHash; @@ -118,6 +119,9 @@ ParsingToolBox::ParsingToolBox() m_OptionOp.insert(QStringLiteral("T"), TransformOption); m_functionMap.insert({QStringLiteral("repeat"), REPEAT}); + m_functionMap.insert({QStringLiteral("floor"), FLOOR}); + m_functionMap.insert({QStringLiteral("ceil"), CEIL}); + m_functionMap.insert({QStringLiteral("round"), ROUND}); m_nodeActionMap.insert(QStringLiteral("@"), JumpBackward); @@ -1438,7 +1442,7 @@ void ParsingToolBox::readSubtitutionParameters(SubtituteInfo& info, QString& res info.setLength(info.length() + sizeS - rest.size()); } -bool ParsingToolBox::readReaperArguments(RepeaterNode* node, QString& source) +bool ParsingToolBox::readRepeaterArguments(RepeaterNode* node, QString& source) { if(!readOpenParentheses(source)) return false; @@ -1466,6 +1470,26 @@ bool ParsingToolBox::readReaperArguments(RepeaterNode* node, QString& source) return false; } + +bool ParsingToolBox::readRoundArguments(RoundNode* node, QString& source) +{ + if(!readOpenParentheses(source)) + return false; + + ExecutionNode* startNode= nullptr; + auto instruction= readExpression(source, startNode); + if(startNode == nullptr || !instruction) + { + m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE, QObject::tr("Can read the paramater for Round Function.")); + return false; + } + + if(!readCloseParentheses(source)) + return false; + + node->setCommand(startNode); + return true; +} bool ParsingToolBox::readExpression(QString& str, ExecutionNode*& node) { ExecutionNode* operandNode= nullptr; @@ -2338,12 +2362,39 @@ bool ParsingToolBox::readFunction(QString& str, ExecutionNode*& node) case REPEAT: { auto repeaterNode= new RepeaterNode(); - if(ParsingToolBox::readReaperArguments(repeaterNode, str)) + if(ParsingToolBox::readRepeaterArguments(repeaterNode, str)) { node= repeaterNode; } } break; + case FLOOR: + { + auto roundNode= new RoundNode(RoundNode::FLOOR); + if(ParsingToolBox::readRoundArguments(roundNode, str)) + { + node= roundNode; + } + } + break; + case CEIL: + { + auto roundNode= new RoundNode(RoundNode::CEIL); + if(ParsingToolBox::readRoundArguments(roundNode, str)) + { + node= roundNode; + } + } + break; + case ROUND: + { + auto roundNode= new RoundNode(RoundNode::ROUND); + if(ParsingToolBox::readRoundArguments(roundNode, str)) + { + node= roundNode; + } + } + break; } } } @@ -2410,7 +2461,6 @@ std::vector ParsingToolBox::readInstructionList(QString& str, bo std::vector startNodes; - bool hasInstruction= false; bool readInstruction= true; while(readInstruction) { @@ -2418,7 +2468,6 @@ std::vector ParsingToolBox::readInstructionList(QString& str, bo bool keepParsing= readExpression(str, startNode); if(nullptr != startNode) { - hasInstruction= true; startNodes.push_back(startNode); auto latest= startNode; if(keepParsing) diff --git a/src/tests/dice/tst_dice.cpp b/src/tests/dice/tst_dice.cpp index d6b9de3..0332504 100644 --- a/src/tests/dice/tst_dice.cpp +++ b/src/tests/dice/tst_dice.cpp @@ -399,6 +399,8 @@ void TestDice::commandsTest_data() 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"; + QTest::addRow("cmd94") << "15/7;floor($1);ceil($1);round($1)"; + QTest::addRow("cmd94") << "15/7;floor(15/7);ceil(15/7);round(15/7)"; } void TestDice::rangedCommandsTest() -- cgit v1.2.3-70-g09d2