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 once
- VCMI_LIB_NAMESPACE_BEGIN
- namespace 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
|