diff options
-rw-r--r-- | src/common/Utilities/Containers.h (renamed from src/server/shared/Containers.h) | 49 | ||||
-rw-r--r-- | src/common/Utilities/Random.cpp | 83 | ||||
-rw-r--r-- | src/common/Utilities/Random.h | 72 | ||||
-rw-r--r-- | src/common/Utilities/Util.cpp | 57 | ||||
-rw-r--r-- | src/common/Utilities/Util.h | 34 |
5 files changed, 200 insertions, 95 deletions
diff --git a/src/server/shared/Containers.h b/src/common/Utilities/Containers.h index 685acea05e3..df97e342932 100644 --- a/src/server/shared/Containers.h +++ b/src/common/Utilities/Containers.h @@ -19,10 +19,10 @@ #define TRINITY_CONTAINERS_H #include "Define.h" +#include "Random.h" +#include <functional> #include <list> - -//! Because circular includes are bad -extern uint32 urand(uint32 min, uint32 max); +#include <vector> namespace Trinity { @@ -57,14 +57,53 @@ namespace Trinity list = listCopy; } - /* Select a random element from a container. Note: make sure you explicitly empty check the container */ - template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container) + /* + * Select a random element from a container. + * + * Note: container cannot be empty + */ + template <class C> + typename C::value_type const& SelectRandomContainerElement(C const& container) { typename C::const_iterator it = container.begin(); std::advance(it, urand(0, uint32(container.size()) - 1)); return *it; } + /* + * Select a random element from a container where each element has a different chance to be selected. + * + * @param container Container to select an element from + * @param weightExtractor Function retrieving chance of each element in container + * + * Note: container cannot be empty + */ + template <class C> + typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, std::function<double(typename C::value_type const&)> weightExtractor) + { + std::vector<double> weights; + weights.reserve(container.size()); + std::transform(container.begin(), container.end(), std::back_inserter(weights), weightExtractor); + return SelectRandomWeightedContainerElement(container, weights); + } + + /* + * Select a random element from a container where each element has a different chance to be selected. + * + * @param container Container to select an element from + * @param weights Chances of each element to be selected, must be in the same order as elements in container + * + * Note: container cannot be empty + */ + template <class C> + typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, std::vector<double> weights) + { + std::discrete_distribution<uint32> dd(weights.begin(), weights.end()); + typename C::const_iterator it = container.begin(); + std::advance(it, dd(SFMTEngine::Instance())); + return it; + } + /** * @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2) * diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp new file mode 100644 index 00000000000..cc013110b01 --- /dev/null +++ b/src/common/Utilities/Random.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "Random.h" +#include "Common.h" +#include "Errors.h" +#include "SFMT.h" +#include <boost/thread/tss.hpp> + +static boost::thread_specific_ptr<SFMTRand> sfmtRand; + +static SFMTRand* GetRng() +{ + SFMTRand* rand = sfmtRand.get(); + + if (!rand) + { + rand = new SFMTRand(); + sfmtRand.reset(rand); + } + + return rand; +} + +int32 irand(int32 min, int32 max) +{ + ASSERT(max >= min); + return int32(GetRng()->IRandom(min, max)); +} + +uint32 urand(uint32 min, uint32 max) +{ + ASSERT(max >= min); + return GetRng()->URandom(min, max); +} + +uint32 urandms(uint32 min, uint32 max) +{ + ASSERT(max >= min); + ASSERT(INT_MAX / IN_MILLISECONDS >= max); + return GetRng()->URandom(min * IN_MILLISECONDS, max * IN_MILLISECONDS); +} + +float frand(float min, float max) +{ + ASSERT(max >= min); + return float(GetRng()->Random() * (max - min) + min); +} + +uint32 rand32() +{ + return GetRng()->BRandom(); +} + +double rand_norm() +{ + return GetRng()->Random(); +} + +double rand_chance() +{ + return GetRng()->Random() * 100.0; +} + +SFMTEngine& SFMTEngine::Instance() +{ + static SFMTEngine engine; + return engine; +} diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h new file mode 100644 index 00000000000..c919c28bcc8 --- /dev/null +++ b/src/common/Utilities/Random.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Random_h__ +#define Random_h__ + +#include "Define.h" +#include <random> + +/* Return a random number in the range min..max. */ +int32 irand(int32 min, int32 max); + +/* Return a random number in the range min..max (inclusive). */ +uint32 urand(uint32 min, uint32 max); + +/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */ +uint32 urandms(uint32 min, uint32 max); + +/* Return a random number in the range 0 .. UINT32_MAX. */ +uint32 rand32(); + +/* Return a random number in the range min..max */ +float frand(float min, float max); + +/* Return a random double from 0.0 to 1.0 (exclusive). */ +double rand_norm(); + +/* Return a random double from 0.0 to 100.0 (exclusive). */ +double rand_chance(); + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_f(float chance) +{ + return chance > rand_chance(); +} + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_i(int chance) +{ + return chance > irand(0, 99); +} + +/* +* SFMT wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms +*/ +class SFMTEngine +{ +public: + typedef uint32 result_type; + + result_type min() const { return std::numeric_limits<result_type>::min(); } + result_type max() const { return std::numeric_limits<result_type>::max(); } + result_type operator()() const { return rand32(); } + + static SFMTEngine& Instance(); +}; + +#endif // Random_h__ diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 0488978ae17..21ccb37d6e7 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -20,10 +20,8 @@ #include "Common.h" #include "CompilerDefs.h" #include "utf8.h" -#include "SFMT.h" #include "Errors.h" // for ASSERT #include <stdarg.h> -#include <boost/thread/tss.hpp> #include <boost/algorithm/string/case_conv.hpp> #if COMPILER == COMPILER_GNU @@ -32,61 +30,6 @@ #include <arpa/inet.h> #endif -static boost::thread_specific_ptr<SFMTRand> sfmtRand; - -static SFMTRand* GetRng() -{ - SFMTRand* rand = sfmtRand.get(); - - if (!rand) - { - rand = new SFMTRand(); - sfmtRand.reset(rand); - } - - return rand; -} - -int32 irand(int32 min, int32 max) -{ - ASSERT(max >= min); - return int32(GetRng()->IRandom(min, max)); -} - -uint32 urand(uint32 min, uint32 max) -{ - ASSERT(max >= min); - return GetRng()->URandom(min, max); -} - -uint32 urandms(uint32 min, uint32 max) -{ - ASSERT(max >= min); - ASSERT(INT_MAX/IN_MILLISECONDS >= max); - return GetRng()->URandom(min * IN_MILLISECONDS, max * IN_MILLISECONDS); -} - -float frand(float min, float max) -{ - ASSERT(max >= min); - return float(GetRng()->Random() * (max - min) + min); -} - -uint32 rand32() -{ - return GetRng()->BRandom(); -} - -double rand_norm() -{ - return GetRng()->Random(); -} - -double rand_chance() -{ - return GetRng()->Random() * 100.0; -} - Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve) { m_str = new char[src.length() + 1]; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 468b0201680..4126dc40f56 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -21,6 +21,7 @@ #include "Define.h" #include "Errors.h" +#include "Random.h" #include <algorithm> #include <string> @@ -78,39 +79,6 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hou uint32 TimeStringToSecs(const std::string& timestring); std::string TimeToTimestampStr(time_t t); -/* Return a random number in the range min..max. */ -int32 irand(int32 min, int32 max); - -/* Return a random number in the range min..max (inclusive). */ -uint32 urand(uint32 min, uint32 max); - -/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */ -uint32 urandms(uint32 min, uint32 max); - -/* Return a random number in the range 0 .. UINT32_MAX. */ -uint32 rand32(); - -/* Return a random number in the range min..max */ -float frand(float min, float max); - -/* Return a random double from 0.0 to 1.0 (exclusive). */ -double rand_norm(); - -/* Return a random double from 0.0 to 100.0 (exclusive). */ -double rand_chance(); - -/* Return true if a random roll fits in the specified chance (range 0-100). */ -inline bool roll_chance_f(float chance) -{ - return chance > rand_chance(); -} - -/* Return true if a random roll fits in the specified chance (range 0-100). */ -inline bool roll_chance_i(int chance) -{ - return chance > irand(0, 99); -} - inline void ApplyPercentModFloatVar(float& var, float val, bool apply) { if (val == -100.0f) // prevent set var to zero |