File indexing completed on 2024-05-12 05:39:27
0001 /*************************************************************************** 0002 * Copyright (C) 2014 by Renaud Guezennec * 0003 * https://rolisteam.org/contact * 0004 * * 0005 * This file is part of DiceParser * 0006 * * 0007 * DiceParser is free software; you can redistribute it and/or modify * 0008 * it under the terms of the GNU General Public License as published by * 0009 * the Free Software Foundation; either version 2 of the License, or * 0010 * (at your option) any later version. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, * 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0015 * GNU General Public License for more details. * 0016 * * 0017 * You should have received a copy of the GNU General Public License * 0018 * along with this program; if not, write to the * 0019 * Free Software Foundation, Inc., * 0020 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0021 ***************************************************************************/ 0022 #include "groupnode.h" 0023 #include "result/diceresult.h" 0024 //------------------------------- 0025 int DieGroup::getSum() const 0026 { 0027 int sum= 0; 0028 for(int i : *this) 0029 { 0030 sum+= i; 0031 } 0032 return sum; 0033 } 0034 0035 void DieGroup::removeValue(DieGroup i) 0036 { 0037 for(auto x : i) 0038 { 0039 removeOne(x); 0040 } 0041 } 0042 0043 int DieGroup::getLost() const 0044 { 0045 return getSum() - m_exceptedValue; 0046 } 0047 0048 qint64 DieGroup::getExceptedValue() const 0049 { 0050 return m_exceptedValue; 0051 } 0052 0053 void DieGroup::setExceptedValue(qint64 exceptedValue) 0054 { 0055 m_exceptedValue= exceptedValue; 0056 } 0057 0058 //--------------------- 0059 GroupNode::GroupNode(bool complexOutput) 0060 : m_scalarResult(new ScalarResult), m_stringResult(new StringResult), m_complexOutput(complexOutput) 0061 { 0062 } 0063 0064 void GroupNode::run(ExecutionNode* previous) 0065 { 0066 if(m_complexOutput) 0067 m_result= m_stringResult; 0068 else 0069 m_result= m_scalarResult; 0070 0071 m_previousNode= previous; 0072 if(nullptr != previous) 0073 { 0074 m_result->setPrevious(previous->getResult()); 0075 Result* tmpResult= previous->getResult(); 0076 if(nullptr != tmpResult) 0077 { 0078 DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult); 0079 if(nullptr != dice) 0080 { 0081 auto list= dice->getResultList(); 0082 DieGroup allResult; 0083 for(auto& die : list) 0084 { 0085 allResult << die->getListValue(); 0086 } 0087 std::sort(allResult.begin(), allResult.end(), std::greater<qint64>()); 0088 if(allResult.getSum() > m_groupValue) 0089 { 0090 auto copy= allResult; 0091 auto const die= getGroup(allResult); 0092 0093 for(auto list : die) 0094 { 0095 for(auto val : list) 0096 { 0097 copy.removeOne(val); 0098 } 0099 } 0100 m_scalarResult->setValue(die.size()); 0101 QStringList list; 0102 for(auto group : die) 0103 { 0104 QStringList values; 0105 std::transform(group.begin(), group.end(), std::back_inserter(values), 0106 [](qint64 val) { return QString::number(val); }); 0107 list << QStringLiteral("{%1}").arg(values.join(",")); 0108 } 0109 QStringList unused; 0110 std::transform(copy.begin(), copy.end(), std::back_inserter(unused), 0111 [](qint64 val) { return QString::number(val); }); 0112 if(!unused.isEmpty()) 0113 m_stringResult->addText( 0114 QStringLiteral("%1 (%2 - [%3])").arg(die.size()).arg(list.join(",")).arg(unused.join(","))); 0115 else 0116 m_stringResult->addText(QStringLiteral("%1 (%2)").arg(die.size()).arg(list.join(","))); 0117 } 0118 else 0119 { 0120 m_scalarResult->setValue(0); 0121 } 0122 } 0123 } 0124 } 0125 if(nullptr != m_nextNode) 0126 { 0127 m_nextNode->run(this); 0128 } 0129 } 0130 0131 QString GroupNode::toString(bool withLabel) const 0132 { 0133 if(withLabel) 0134 { 0135 return QString("%1 [label=\"SplitNode Node\"]").arg(m_id); 0136 } 0137 else 0138 { 0139 return m_id; 0140 } 0141 } 0142 qint64 GroupNode::getPriority() const 0143 { 0144 qint64 priority= 0; 0145 if(nullptr != m_nextNode) 0146 { 0147 priority= m_nextNode->getPriority(); 0148 } 0149 return priority; 0150 } 0151 ExecutionNode* GroupNode::getCopy() const 0152 { 0153 GroupNode* node= new GroupNode(m_complexOutput); 0154 if(nullptr != m_nextNode) 0155 { 0156 node->setNextNode(m_nextNode->getCopy()); 0157 } 0158 return node; 0159 } 0160 0161 int GroupNode::getGroupValue() const 0162 { 0163 return m_groupValue; 0164 } 0165 0166 void GroupNode::setGroupValue(qint64 groupValue) 0167 { 0168 m_groupValue= groupValue; 0169 } 0170 0171 bool GroupNode::composeWithPrevious(DieGroup previous, qint64 first, qint64 current, DieGroup& addValue) 0172 { 0173 if(previous.getSum() + first + current == m_groupValue) 0174 { 0175 addValue.append(previous); 0176 addValue.append(first); 0177 addValue.append(current); 0178 return true; 0179 } 0180 0181 if(previous.isEmpty()) 0182 return false; 0183 0184 int maxComboLength= previous.size(); 0185 bool hasReachMax= false; 0186 0187 QList<DieGroup> possibleUnion; 0188 for(auto va : previous) 0189 { 0190 DieGroup dieG; 0191 dieG.append(va); 0192 possibleUnion.append(dieG); 0193 } 0194 0195 while(!hasReachMax) 0196 { 0197 auto tmpValues= previous; 0198 QList<DieGroup> possibleTmp; 0199 for(auto& diaG : possibleUnion) 0200 { 0201 if(tmpValues.isEmpty()) 0202 break; 0203 tmpValues.removeValue(diaG); 0204 0205 for(auto& value : tmpValues) 0206 { 0207 DieGroup dia; 0208 dia.append(diaG); 0209 dia.append(value); 0210 if(dia.size() >= maxComboLength - 1) 0211 hasReachMax= true; 0212 else 0213 possibleTmp.append(dia); 0214 } 0215 } 0216 if(possibleTmp.isEmpty()) 0217 hasReachMax= true; 0218 else 0219 { 0220 possibleTmp.append(possibleUnion); 0221 possibleUnion= possibleTmp; 0222 } 0223 } 0224 std::sort(possibleUnion.begin(), possibleUnion.end(), 0225 [=](const DieGroup& a, const DieGroup& b) { return a.getLost() > b.getLost(); }); 0226 bool found= false; 0227 for(int i= 0; (!found && i < possibleUnion.size()); ++i) 0228 { 0229 auto& value= possibleUnion.at(i); 0230 if(value.getSum() + current + first >= m_groupValue) 0231 { 0232 addValue << value << current << first; 0233 found= true; 0234 } 0235 } 0236 return found; 0237 } 0238 0239 QList<DieGroup> GroupNode::getGroup(DieGroup values) 0240 { 0241 if(values.isEmpty()) 0242 return {}; 0243 0244 auto first= values.takeFirst(); 0245 0246 QList<DieGroup> result; 0247 QMap<qint64, DieGroup> loseMap; 0248 if(first >= m_groupValue) 0249 { 0250 DieGroup group; 0251 group << first; 0252 loseMap[0]= group; 0253 } 0254 else 0255 { 0256 auto it= values.rbegin(); 0257 bool foundPerfect= false; 0258 qint64 cumuledValue= 0; 0259 DieGroup previousValue; 0260 while((values.rend() != it) && !foundPerfect) 0261 { 0262 if(first + *it == m_groupValue) 0263 { 0264 foundPerfect= true; 0265 DieGroup group; 0266 group << first << *it; 0267 loseMap[0]= group; 0268 } 0269 else if(first + *it > m_groupValue) 0270 { 0271 DieGroup group; 0272 group << first << *it; 0273 loseMap[first + *it - m_groupValue]= group; 0274 } 0275 else if(first + *it + cumuledValue == m_groupValue) 0276 { 0277 DieGroup group; 0278 group << first << *it << previousValue; 0279 foundPerfect= true; 0280 loseMap[0]= group; 0281 } 0282 else if(first + *it + cumuledValue > m_groupValue) 0283 { 0284 DieGroup group; 0285 group.setExceptedValue(m_groupValue); 0286 auto b= composeWithPrevious(previousValue, first, *it, group); 0287 if(b) 0288 loseMap[group.getLost()]= group; 0289 } 0290 previousValue << *it; 0291 cumuledValue+= *it; 0292 ++it; 0293 } 0294 } 0295 if(!loseMap.isEmpty()) 0296 { 0297 DieGroup die= loseMap.first(); 0298 result.append(die); 0299 DieGroup valueToRemove= die; 0300 if(!valueToRemove.isEmpty()) 0301 { 0302 valueToRemove.removeFirst(); 0303 values.removeValue(valueToRemove); 0304 0305 if(values.getSum() >= m_groupValue) 0306 { 0307 result.append(getGroup(values)); 0308 } 0309 } 0310 } 0311 return result; 0312 }