dynrules
|
00001 /* 00002 * dynrules - Python dynamic rules engine 00003 * 00004 * Authors: Marcus von Appen 00005 * 00006 * This file is distributed under the Public Domain. 00007 */ 00008 00009 #include <stdexcept> 00010 #include "RuleSet.h" 00011 00012 namespace dynrules 00013 { 00014 00015 RuleSet::RuleSet () : 00016 _minweight(0), 00017 _maxweight(0), 00018 _weight(0), 00019 _rules(0) 00020 { 00021 } 00022 00023 RuleSet::RuleSet (double minweight, double maxweight) : 00024 _minweight(0), 00025 _maxweight(0), 00026 _weight(0), 00027 _rules(0) 00028 { 00029 if (minweight > maxweight) 00030 throw std::invalid_argument ("maxweight must not be smaller than minweight"); 00031 this->_minweight = minweight; 00032 this->_maxweight = maxweight; 00033 } 00034 00035 RuleSet::~RuleSet () 00036 { 00037 } 00038 00039 double RuleSet::getMinWeight () const 00040 { 00041 return this->_minweight; 00042 } 00043 00044 void RuleSet::setMinWeight (double minweight) 00045 { 00046 if (minweight > this->_maxweight) 00047 throw std::invalid_argument ("maxweight must not be smaller than minweight"); 00048 this->_minweight = minweight; 00049 } 00050 00051 double RuleSet::getMaxWeight () const 00052 { 00053 return this->_maxweight; 00054 } 00055 00056 void RuleSet::setMaxWeight (double maxweight) 00057 { 00058 if (maxweight < this->_minweight) 00059 throw std::invalid_argument ("maxweight must not be smaller than minweight"); 00060 this->_maxweight = maxweight; 00061 } 00062 00063 double RuleSet::getWeight () const 00064 { 00065 return this->_weight; 00066 } 00067 00068 std::vector<Rule*> RuleSet::getRules () const 00069 { 00070 return this->_rules; 00071 } 00072 00073 void RuleSet::addRule (Rule* rule) 00074 { 00075 if (rule == 0) 00076 throw std::invalid_argument ("rule must not be NULL"); 00077 00078 this->_rules.push_back (rule); 00079 if (rule->getWeight() > this->_maxweight) 00080 rule->setWeight (this->_maxweight); 00081 else if (rule->getWeight () < this->_minweight) 00082 rule->setWeight (this->_minweight); 00083 this->_weight += rule->getWeight (); 00084 } 00085 00086 bool RuleSet::removeRule (Rule* rule) 00087 { 00088 if (rule == 0) 00089 return false; 00090 00091 bool found = false; 00092 std::vector<Rule*>::iterator iter; 00093 for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++) 00094 { 00095 if ((*iter) == rule) 00096 { 00097 found = true; 00098 break; 00099 } 00100 } 00101 if (found) 00102 { 00103 this->_rules.erase (iter); 00104 this->_weight -= (*iter)->getWeight (); 00105 } 00106 return found; 00107 } 00108 00109 Rule *RuleSet::find (int id) 00110 { 00111 std::vector<Rule*>::iterator iter; 00112 for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++) 00113 if ((*iter)->getId () == id) 00114 return *iter; 00115 return 0; 00116 } 00117 00118 void RuleSet::clear () 00119 { 00120 this->_rules.clear(); 00121 this->_weight = 0.f; 00122 } 00123 00124 void RuleSet::updateWeights (void *fitness) 00125 { 00126 /* 00127 * Adapted from Pieter Spronck's algorithm as explained in 00128 * Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting' 00129 */ 00130 Rule *rule; 00131 std::vector<Rule*>::iterator it; 00132 size_t count, usedcount = 0, nonactive; 00133 double totweight = 0, adjustment, compensation, _remainder, weight; 00134 00135 count = this->_rules.size (); 00136 if (count == 0) 00137 return; 00138 00139 for (it = this->_rules.begin (); it != this->_rules.end (); it++) 00140 { 00141 rule = *it; 00142 if (rule->getUsed ()) 00143 usedcount++; 00144 } 00145 if (usedcount == 0 || usedcount == count) 00146 return; 00147 00148 nonactive = count - usedcount; 00149 adjustment = this->calculateAdjustment (fitness); 00150 compensation = (static_cast<double>(-(static_cast<int>(usedcount)) * 00151 adjustment)) / nonactive; 00152 _remainder = 0; 00153 00154 for (it = this->_rules.begin (); it != this->_rules.end (); it++) 00155 { 00156 rule = *it; 00157 00158 weight = rule->getWeight () + 00159 ((rule->getUsed ()) ? adjustment : compensation); 00160 00161 if (weight < this->_minweight) 00162 { 00163 _remainder += (weight - this->_minweight); 00164 rule->setWeight (this->_minweight); 00165 } 00166 else if (weight > this->_maxweight) 00167 { 00168 _remainder += (weight - this->_maxweight); 00169 rule->setWeight (this->_maxweight); 00170 } 00171 else 00172 rule->setWeight (weight); 00173 totweight += rule->getWeight(); 00174 } 00175 00176 this->_weight = totweight; 00177 this->distributeRemainder (_remainder); 00178 00179 totweight = 0; 00180 for (it = this->_rules.begin (); it != this->_rules.end (); it++) 00181 { 00182 rule = *it; 00183 rule->setUsed (false); 00184 totweight += rule->getWeight (); 00185 } 00186 this->_weight = totweight; 00187 } 00188 00189 double RuleSet::calculateAdjustment (void *fitness) 00190 { 00191 return 0.f; 00192 } 00193 00194 void RuleSet::distributeRemainder (double remainder) 00195 { 00196 } 00197 00198 } // namespace