| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 | /* * RNG.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#pragma onceVCMI_LIB_NAMESPACE_BEGINnamespace vstd{class DLL_LINKAGE RNG{public:	virtual ~RNG() = default;	/// Returns random number in range [lower, upper]	virtual int nextInt(int lower, int upper) = 0;	/// Returns random number in range [lower, upper]	virtual int64_t nextInt64(int64_t lower, int64_t upper) = 0;	/// Returns random number in range [lower, upper]	virtual double nextDouble(double lower, double upper) = 0;	/// Returns random number in range [0, upper]	virtual int nextInt(int upper) = 0;	/// Returns random number in range [0, upper]	virtual int64_t nextInt64(int64_t upper) = 0;	/// Returns random number in range [0, upper]	virtual double nextDouble(double upper) = 0;	/// Generates an integer between 0 and the maximum value it can hold.	/// Should be only used for seeding other generators	virtual int nextInt() = 0;	/// Returns integer using binomial distribution	/// returned value is number of successfull coin flips with chance 'coinChance' out of 'coinsCount' attempts	virtual int nextBinomialInt(int coinsCount, double coinChance) = 0;};}namespace RandomGeneratorUtil{	template<typename Container>	auto nextItem(const Container & container, vstd::RNG & rand) -> decltype(std::begin(container))	{		if(container.empty())			throw std::runtime_error("Unable to select random item from empty container!");		return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));	}	template<typename Container>	auto nextItem(Container & container, vstd::RNG & rand) -> decltype(std::begin(container))	{		if(container.empty())			throw std::runtime_error("Unable to select random item from empty container!");		return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));	}	template<typename Container>	size_t nextItemWeighted(Container & container, vstd::RNG & rand)	{		assert(!container.empty());		int64_t totalWeight = std::accumulate(container.begin(), container.end(), 0);		assert(totalWeight > 0);		int64_t roll = rand.nextInt64(0, totalWeight - 1);		for (size_t i = 0; i < container.size(); ++i)		{			int chance = container[i];			if(roll < chance)				return i;			roll -= chance;		}		return container.size() - 1;	}	template<typename Container>	void randomShuffle(Container & container, vstd::RNG & rand)	{		int64_t n = std::distance(container.begin(), container.end());		for(int64_t i = n - 1; i > 0; --i)		{			auto randIndex = rand.nextInt64(0, i);			std::swap(*(container.begin() + i), *(container.begin() + randIndex));		}	}}VCMI_LIB_NAMESPACE_END
 |