mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-18 08:28:32 +01:00
Core/Utils: Moved rng functions to separate header and added utility functions to select a random element from a container where each element can have different chance of being selected
(cherry picked from commitae20b2ab56) (cherry picked from commit921d893c2a) (cherry picked from commit9ab10d6e68) (cherry picked from commit00c878e73a) (cherry picked from commitff9c999334) (cherry picked from commitbc94bacce4) (cherry picked from commitd5b0ffbe9b)
This commit is contained in:
@@ -83,10 +83,16 @@
|
||||
# define ATTR_NORETURN __attribute__((__noreturn__))
|
||||
# define ATTR_PRINTF(F, V) __attribute__ ((__format__ (__printf__, F, V)))
|
||||
# define ATTR_DEPRECATED __attribute__((__deprecated__))
|
||||
# define TRINITY_CONSTEXPR constexpr
|
||||
#else //COMPILER != COMPILER_GNU
|
||||
# define ATTR_NORETURN
|
||||
# define ATTR_PRINTF(F, V)
|
||||
# define ATTR_DEPRECATED
|
||||
#if _MSC_VER >= 1900
|
||||
# define TRINITY_CONSTEXPR constexpr
|
||||
#else
|
||||
# define TRINITY_CONSTEXPR
|
||||
#endif
|
||||
#endif //COMPILER == COMPILER_GNU
|
||||
|
||||
#define UI64FMTD "%" PRIu64
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
#define TRINITY_CONTAINERS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Random.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
//! Because circular includes are bad
|
||||
extern uint32 urand(uint32 min, uint32 max);
|
||||
#include <vector>
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
@@ -57,14 +58,64 @@ 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, 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 weights Chances of each element to be selected, must be in the same order as elements in container.
|
||||
* Caller is responsible for checking that sum of all weights is greater than 0.
|
||||
*
|
||||
* Note: container cannot be empty
|
||||
*/
|
||||
template <class C>
|
||||
typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, std::vector<double> weights)
|
||||
{
|
||||
Trinity::discrete_distribution_param<uint32> ddParam(weights.begin(), weights.end());
|
||||
std::discrete_distribution<uint32> dd(ddParam);
|
||||
typename C::const_iterator it = container.begin();
|
||||
std::advance(it, dd(SFMTEngine::Instance()));
|
||||
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, expected to take an element of the container and returning a double
|
||||
*
|
||||
* Note: container cannot be empty
|
||||
*/
|
||||
template <class C, class Fn>
|
||||
typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor)
|
||||
{
|
||||
std::vector<double> weights;
|
||||
weights.reserve(container.size());
|
||||
double weightSum = 0.0;
|
||||
for (auto itr = container.begin(); itr != container.end(); ++itr)
|
||||
{
|
||||
double weight = weightExtractor(*itr);
|
||||
weights.push_back(weight);
|
||||
weightSum += weight;
|
||||
}
|
||||
if (weightSum <= 0.0)
|
||||
weights.assign(container.size(), 1.0);
|
||||
|
||||
return SelectRandomWeightedContainerElement(container, weights);
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
|
||||
*
|
||||
83
src/common/Utilities/Random.cpp
Normal file
83
src/common/Utilities/Random.cpp
Normal file
@@ -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;
|
||||
}
|
||||
95
src/common/Utilities/Random.h
Normal file
95
src/common/Utilities/Random.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 <limits>
|
||||
#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;
|
||||
|
||||
static TRINITY_CONSTEXPR result_type min() { return std::numeric_limits<result_type>::min(); }
|
||||
static TRINITY_CONSTEXPR result_type max() { return std::numeric_limits<result_type>::max(); }
|
||||
result_type operator()() const { return rand32(); }
|
||||
|
||||
static SFMTEngine& Instance();
|
||||
};
|
||||
|
||||
// Ugly, horrible, i don't even..., hack for VS2013 to work around missing discrete_distribution(iterator, iterator) constructor
|
||||
namespace Trinity
|
||||
{
|
||||
#if COMPILER == COMPILER_MICROSOFT && _MSC_VER <= 1800
|
||||
template<typename T>
|
||||
struct discrete_distribution_param : public std::discrete_distribution<T>::param_type
|
||||
{
|
||||
typedef typename std::discrete_distribution<T>::param_type base;
|
||||
|
||||
template<typename InIt>
|
||||
discrete_distribution_param(InIt begin, InIt end) : base(_Noinit())
|
||||
{
|
||||
this->_Pvec.assign(begin, end);
|
||||
this->_Init();
|
||||
}
|
||||
};
|
||||
#else
|
||||
template<typename T>
|
||||
using discrete_distribution_param = typename std::discrete_distribution<T>::param_type;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // Random_h__
|
||||
@@ -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>
|
||||
|
||||
#if COMPILER == COMPILER_GNU
|
||||
#include <sys/socket.h>
|
||||
@@ -31,61 +29,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];
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include "Random.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
@@ -77,39 +78,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
|
||||
|
||||
Reference in New Issue
Block a user