1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Remove usage of std::function from CRandomGenerator

This commit is contained in:
Ivan Savenko 2024-06-01 13:36:38 +00:00
parent ad9750ed3e
commit 60a51e98de
16 changed files with 61 additions and 102 deletions

View File

@ -24,20 +24,17 @@ class HypotheticBattle;
class RNGStub : public vstd::RNG class RNGStub : public vstd::RNG
{ {
public: public:
vstd::TRandI64 getInt64Range(int64_t lower, int64_t upper) override int nextInt(int lower, int upper) override
{
return [=]()->int64_t
{ {
return (lower + upper) / 2; return (lower + upper) / 2;
};
} }
int64_t nextInt64(int64_t lower, int64_t upper) override
vstd::TRand getDoubleRange(double lower, double upper) override {
{ return (lower + upper) / 2;
return [=]()->double }
double nextDouble(double lower, double upper) override
{ {
return (lower + upper) / 2; return (lower + upper) / 2;
};
} }
}; };

View File

@ -15,18 +15,14 @@ VCMI_LIB_NAMESPACE_BEGIN
namespace vstd namespace vstd
{ {
using TRandI64 = std::function<int64_t()>;
using TRand = std::function<double()>;
class DLL_LINKAGE RNG class DLL_LINKAGE RNG
{ {
public: public:
virtual ~RNG() = default; virtual ~RNG() = default;
virtual TRandI64 getInt64Range(int64_t lower, int64_t upper) = 0; virtual int nextInt(int lower, int upper) = 0;
virtual int64_t nextInt64(int64_t lower, int64_t upper) = 0;
virtual TRand getDoubleRange(double lower, double upper) = 0; virtual double nextDouble(double lower, double upper) = 0;
}; };
} }
@ -39,7 +35,7 @@ namespace RandomGeneratorUtil
if(container.empty()) if(container.empty())
throw std::runtime_error("Unable to select random item from empty container!"); throw std::runtime_error("Unable to select random item from empty container!");
return std::next(container.begin(), rand.getInt64Range(0, container.size() - 1)()); return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
} }
template<typename Container> template<typename Container>
@ -48,7 +44,7 @@ namespace RandomGeneratorUtil
if(container.empty()) if(container.empty())
throw std::runtime_error("Unable to select random item from empty container!"); throw std::runtime_error("Unable to select random item from empty container!");
return std::next(container.begin(), rand.getInt64Range(0, container.size() - 1)()); return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
} }
template<typename Container> template<typename Container>
@ -59,7 +55,7 @@ namespace RandomGeneratorUtil
int64_t totalWeight = std::accumulate(container.begin(), container.end(), 0); int64_t totalWeight = std::accumulate(container.begin(), container.end(), 0);
assert(totalWeight > 0); assert(totalWeight > 0);
int64_t roll = rand.getInt64Range(0, totalWeight - 1)(); int64_t roll = rand.nextInt64(0, totalWeight - 1);
for (size_t i = 0; i < container.size(); ++i) for (size_t i = 0; i < container.size(); ++i)
{ {
@ -77,7 +73,7 @@ namespace RandomGeneratorUtil
for(int64_t i = n-1; i>0; --i) for(int64_t i = n-1; i>0; --i)
{ {
std::swap(container.begin()[i],container.begin()[rand.getInt64Range(0, i)()]); std::swap(container.begin()[i],container.begin()[rand.nextInt64(0, i)]);
} }
} }
} }

View File

@ -35,28 +35,17 @@ void CRandomGenerator::resetSeed()
setSeed(static_cast<int>(threadIdHash * std::time(nullptr))); setSeed(static_cast<int>(threadIdHash * std::time(nullptr)));
} }
TRandI CRandomGenerator::getIntRange(int lower, int upper)
{
if (lower <= upper)
return std::bind(TIntDist(lower, upper), std::ref(rand));
throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper));
}
vstd::TRandI64 CRandomGenerator::getInt64Range(int64_t lower, int64_t upper)
{
if(lower <= upper)
return std::bind(TInt64Dist(lower, upper), std::ref(rand));
throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper));
}
int CRandomGenerator::nextInt(int upper) int CRandomGenerator::nextInt(int upper)
{ {
return getIntRange(0, upper)(); return nextInt(0, upper);
} }
int CRandomGenerator::nextInt(int lower, int upper) int CRandomGenerator::nextInt(int lower, int upper)
{ {
return getIntRange(lower, upper)(); if (lower > upper)
throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper));
return TIntDist(lower, upper)(rand);
} }
int CRandomGenerator::nextInt() int CRandomGenerator::nextInt()
@ -64,28 +53,31 @@ int CRandomGenerator::nextInt()
return TIntDist()(rand); return TIntDist()(rand);
} }
vstd::TRand CRandomGenerator::getDoubleRange(double lower, double upper) int64_t CRandomGenerator::nextInt64(int64_t lower, int64_t upper)
{ {
if(lower <= upper) if (lower > upper)
return std::bind(TRealDist(lower, upper), std::ref(rand));
throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper)); throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper));
return TInt64Dist(lower, upper)(rand);
} }
double CRandomGenerator::nextDouble(double upper) double CRandomGenerator::nextDouble(double upper)
{ {
return getDoubleRange(0, upper)(); return nextDouble(0, upper);
} }
double CRandomGenerator::nextDouble(double lower, double upper) double CRandomGenerator::nextDouble(double lower, double upper)
{ {
return getDoubleRange(lower, upper)(); if(lower > upper)
throw std::runtime_error("Invalid range provided: " + std::to_string(lower) + " ... " + std::to_string(upper));
return TRealDist(lower, upper)(rand);
} }
double CRandomGenerator::nextDouble() //double CRandomGenerator::nextDouble()
{ //{
return TRealDist()(rand); // return TRealDist()(rand);
} //}
CRandomGenerator & CRandomGenerator::getDefault() CRandomGenerator & CRandomGenerator::getDefault()
{ {

View File

@ -15,6 +15,7 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
/// Generator to use for all randomization in game /// Generator to use for all randomization in game
/// minstd_rand is selected due to following reasons: /// minstd_rand is selected due to following reasons:
/// 1. Its randomization quality is below mt_19937 however this is unlikely to be noticeable in game /// 1. Its randomization quality is below mt_19937 however this is unlikely to be noticeable in game
@ -23,12 +24,11 @@ using TGenerator = std::minstd_rand;
using TIntDist = std::uniform_int_distribution<int>; using TIntDist = std::uniform_int_distribution<int>;
using TInt64Dist = std::uniform_int_distribution<int64_t>; using TInt64Dist = std::uniform_int_distribution<int64_t>;
using TRealDist = std::uniform_real_distribution<double>; using TRealDist = std::uniform_real_distribution<double>;
using TRandI = std::function<int()>;
/// The random generator randomly generates integers and real numbers("doubles") between /// The random generator randomly generates integers and real numbers("doubles") between
/// a given range. This is a header only class and mainly a wrapper for /// a given range. This is a header only class and mainly a wrapper for
/// convenient usage of the standard random API. An instance of this RNG is not thread safe. /// convenient usage of the standard random API. An instance of this RNG is not thread safe.
class DLL_LINKAGE CRandomGenerator : public vstd::RNG, boost::noncopyable, public Serializeable class DLL_LINKAGE CRandomGenerator final : public vstd::RNG, boost::noncopyable, public Serializeable
{ {
public: public:
/// Seeds the generator by default with the product of the current time in milliseconds and the /// Seeds the generator by default with the product of the current time in milliseconds and the
@ -44,37 +44,23 @@ public:
/// current thread ID. /// current thread ID.
void resetSeed(); void resetSeed();
/// Generate several integer numbers within the same range.
/// e.g.: auto a = gen.getIntRange(0,10); a(); a(); a();
/// requires: lower <= upper
TRandI getIntRange(int lower, int upper);
vstd::TRandI64 getInt64Range(int64_t lower, int64_t upper) override;
/// Generates an integer between 0 and upper. /// Generates an integer between 0 and upper.
/// requires: 0 <= upper /// requires: 0 <= upper
int nextInt(int upper); int nextInt(int upper);
/// requires: lower <= upper /// requires: lower <= upper
int nextInt(int lower, int upper); int nextInt(int lower, int upper) override;
int64_t nextInt64(int64_t lower, int64_t upper) override;
/// Generates an integer between 0 and the maximum value it can hold. /// Generates an integer between 0 and the maximum value it can hold.
int nextInt(); int nextInt();
/// Generate several double/real numbers within the same range.
/// e.g.: auto a = gen.getDoubleRange(4.5,10.2); a(); a(); a();
/// requires: lower <= upper
vstd::TRand getDoubleRange(double lower, double upper) override;
/// Generates a double between 0 and upper. /// Generates a double between 0 and upper.
/// requires: 0 <= upper /// requires: 0 <= upper
double nextDouble(double upper); double nextDouble(double upper);
/// requires: lower <= upper /// requires: lower <= upper
double nextDouble(double lower, double upper); double nextDouble(double lower, double upper) override;
/// Generates a double between 0.0 and 1.0.
double nextDouble();
/// Gets a globally accessible RNG which will be constructed once per thread. For the /// Gets a globally accessible RNG which will be constructed once per thread. For the
/// seed a combination of the thread ID and current time in milliseconds will be used. /// seed a combination of the thread ID and current time in milliseconds will be used.

View File

@ -212,11 +212,9 @@ void CStack::prepareAttacked(BattleStackAttacked & bsa, vstd::RNG & rand, const
auto resurrectedAdd = static_cast<int32_t>(baseAmount - (resurrectedCount / resurrectFactor)); auto resurrectedAdd = static_cast<int32_t>(baseAmount - (resurrectedCount / resurrectFactor));
auto rangeGen = rand.getInt64Range(0, 99);
for(int32_t i = 0; i < resurrectedAdd; i++) for(int32_t i = 0; i < resurrectedAdd; i++)
{ {
if(resurrectValue > rangeGen()) if(resurrectValue > rand.nextInt(0, 99))
resurrectedCount += 1; resurrectedCount += 1;
} }

View File

@ -662,10 +662,9 @@ int64_t BattleInfo::getActualDamage(const DamageRange & damage, int32_t attacker
int64_t sum = 0; int64_t sum = 0;
auto howManyToAv = std::min<int32_t>(10, attackerCount); auto howManyToAv = std::min<int32_t>(10, attackerCount);
auto rangeGen = rng.getInt64Range(damage.min, damage.max);
for(int32_t g = 0; g < howManyToAv; ++g) for(int32_t g = 0; g < howManyToAv; ++g)
sum += rangeGen(); sum += rng.nextInt64(damage.min, damage.max);
return sum / howManyToAv; return sum / howManyToAv;
} }

View File

@ -63,7 +63,7 @@ VCMI_LIB_NAMESPACE_BEGIN
{ {
const auto & vector = value.Vector(); const auto & vector = value.Vector();
size_t index= rng.getIntRange(0, vector.size()-1)(); size_t index= rng.nextInt64(0, vector.size()-1);
return loadValue(vector[index], rng, variables, 0); return loadValue(vector[index], rng, variables, 0);
} }
if(value.isStruct()) if(value.isStruct())
@ -72,7 +72,7 @@ VCMI_LIB_NAMESPACE_BEGIN
return loadValue(value["amount"], rng, variables, defaultValue); return loadValue(value["amount"], rng, variables, defaultValue);
si32 min = loadValue(value["min"], rng, variables, 0); si32 min = loadValue(value["min"], rng, variables, 0);
si32 max = loadValue(value["max"], rng, variables, 0); si32 max = loadValue(value["max"], rng, variables, 0);
return rng.getIntRange(min, max)(); return rng.nextInt64(min, max);
} }
return defaultValue; return defaultValue;
} }

View File

@ -298,7 +298,7 @@ void Rewardable::Info::configureRewards(
{ {
const JsonNode & preset = object.getPresetVariable("dice", diceID); const JsonNode & preset = object.getPresetVariable("dice", diceID);
if (preset.isNull()) if (preset.isNull())
object.initVariable("dice", diceID, rng.getIntRange(0, 99)()); object.initVariable("dice", diceID, rng.nextInt(0, 99));
else else
object.initVariable("dice", diceID, preset.Integer()); object.initVariable("dice", diceID, preset.Integer());

View File

@ -444,7 +444,7 @@ void ConnectionsPlacer::collectNeighbourZones()
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
{ {
return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE || return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE ||
(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM && zone.getRand().nextDouble() >= 0.5f); (connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM && zone.getRand().nextDouble(0, 1) >= 0.5f);
} }
void ConnectionsPlacer::createBorder() void ConnectionsPlacer::createBorder()

View File

@ -187,7 +187,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner); const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
//check if spell works at all //check if spell works at all
if(env->getRNG()->getInt64Range(0, 99)() >= owner->getLevelPower(schoolLevel)) //power is % chance of success if(env->getRNG()->nextInt(0, 99) >= owner->getLevelPower(schoolLevel)) //power is % chance of success
{ {
InfoWindow iw; InfoWindow iw;
iw.player = parameters.caster->getCasterOwner(); iw.player = parameters.caster->getCasterOwner();
@ -280,7 +280,7 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
{ {
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner); const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
//check if spell works at all //check if spell works at all
if(env->getRNG()->getInt64Range(0, 99)() >= owner->getLevelPower(schoolLevel)) //power is % chance of success if(env->getRNG()->nextInt(0, 99) >= owner->getLevelPower(schoolLevel)) //power is % chance of success
{ {
InfoWindow iw; InfoWindow iw;
iw.player = parameters.caster->getCasterOwner(); iw.player = parameters.caster->getCasterOwner();

View File

@ -377,15 +377,13 @@ void BattleSpellMechanics::beforeCast(BattleSpellCast & sc, vstd::RNG & rng, con
std::vector <const battle::Unit *> resisted; std::vector <const battle::Unit *> resisted;
auto rangeGen = rng.getInt64Range(0, 99);
auto filterResisted = [&, this](const battle::Unit * unit) -> bool auto filterResisted = [&, this](const battle::Unit * unit) -> bool
{ {
if(isNegativeSpell() && isMagicalEffect()) if(isNegativeSpell() && isMagicalEffect())
{ {
//magic resistance //magic resistance
const int prob = std::min(unit->magicResistance(), 100); //probability of resistance in % const int prob = std::min(unit->magicResistance(), 100); //probability of resistance in %
if(rangeGen() < prob) if(rng.nextInt(0, 99) < prob)
return true; return true;
} }
return false; return false;

View File

@ -268,11 +268,9 @@ void BattleCast::cast(ServerCallback * server, Target target)
const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR"; const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
static const auto magicMirrorSelector = Selector::type()(BonusType::MAGIC_MIRROR); static const auto magicMirrorSelector = Selector::type()(BonusType::MAGIC_MIRROR);
auto rangeGen = server->getRNG()->getInt64Range(0, 99);
const int mirrorChance = mainTarget->valOfBonuses(magicMirrorSelector, magicMirrorCacheStr); const int mirrorChance = mainTarget->valOfBonuses(magicMirrorSelector, magicMirrorCacheStr);
if(rangeGen() < mirrorChance) if(server->getRNG()->nextInt(0, 99) < mirrorChance)
{ {
auto mirrorTargets = cb->battleGetUnitsIf([this](const battle::Unit * unit) auto mirrorTargets = cb->battleGetUnitsIf([this](const battle::Unit * unit)
{ {

View File

@ -118,7 +118,7 @@ void Catapult::applyTargeted(ServerCallback * server, const Mechanics * m, const
auto actualTarget = EWallPart::INVALID; auto actualTarget = EWallPart::INVALID;
if ( m->battle()->isWallPartAttackable(desiredTarget) && if ( m->battle()->isWallPartAttackable(desiredTarget) &&
server->getRNG()->getInt64Range(0, 99)() < getCatapultHitChance(desiredTarget)) server->getRNG()->nextInt(0, 99) < getCatapultHitChance(desiredTarget))
{ {
actualTarget = desiredTarget; actualTarget = desiredTarget;
} }
@ -172,7 +172,7 @@ int Catapult::getRandomDamage (ServerCallback * server) const
{ {
std::array<int, 3> damageChances = { noDmg, hit, crit }; //dmgChance[i] - chance for doing i dmg when hit is successful std::array<int, 3> damageChances = { noDmg, hit, crit }; //dmgChance[i] - chance for doing i dmg when hit is successful
int totalChance = std::accumulate(damageChances.begin(), damageChances.end(), 0); int totalChance = std::accumulate(damageChances.begin(), damageChances.end(), 0);
int damageRandom = server->getRNG()->getInt64Range(0, totalChance - 1)(); int damageRandom = server->getRNG()->nextInt(0, totalChance - 1);
int dealtDamage = 0; int dealtDamage = 0;
//calculating dealt damage //calculating dealt damage

View File

@ -1341,7 +1341,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
double chanceToTrigger = attacker->valOfBonuses(BonusType::TRANSMUTATION) / 100.0f; double chanceToTrigger = attacker->valOfBonuses(BonusType::TRANSMUTATION) / 100.0f;
vstd::amin(chanceToTrigger, 1); //cap at 100% vstd::amin(chanceToTrigger, 1); //cap at 100%
if(gameHandler->getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger) if(gameHandler->getRandomGenerator().nextDouble(0, 1) > chanceToTrigger)
return; return;
int bonusAdditionalInfo = attacker->getBonus(Selector::type()(BonusType::TRANSMUTATION))->additionalInfo[0]; int bonusAdditionalInfo = attacker->getBonus(Selector::type()(BonusType::TRANSMUTATION))->additionalInfo[0];
@ -1405,7 +1405,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100% vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
if(gameHandler->getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger) if(gameHandler->getRandomGenerator().nextDouble(0, 1) > chanceToTrigger)
return; return;
BattleStackAttacked bsa; BattleStackAttacked bsa;

View File

@ -18,8 +18,9 @@ namespace vstd
class RNGMock : public RNG class RNGMock : public RNG
{ {
public: public:
MOCK_METHOD2(getInt64Range, TRandI64(int64_t, int64_t)); MOCK_METHOD2(nextInt, int(int lower, int upper));
MOCK_METHOD2(getDoubleRange, TRand(double, double)); MOCK_METHOD2(nextInt64, int64_t(int64_t lower, int64_t upper));
MOCK_METHOD2(nextDouble, double(double lower, double upper));
}; };
} }

View File

@ -101,27 +101,21 @@ void EffectFixture::setUp()
ON_CALL(serverMock, apply(Matcher<CatapultAttack *>(_))).WillByDefault(Invoke(battleFake.get(), &battle::BattleFake::accept<CatapultAttack>)); ON_CALL(serverMock, apply(Matcher<CatapultAttack *>(_))).WillByDefault(Invoke(battleFake.get(), &battle::BattleFake::accept<CatapultAttack>));
} }
static vstd::TRandI64 getInt64RangeDef(int64_t lower, int64_t upper) static int64_t getInt64Range(int64_t lower, int64_t upper)
{
return [=]()->int64_t
{ {
return (lower + upper)/2; return (lower + upper)/2;
};
} }
static vstd::TRand getDoubleRangeDef(double lower, double upper) static double getDoubleRange(double lower, double upper)
{
return [=]()->double
{ {
return (lower + upper)/2; return (lower + upper)/2;
};
} }
void EffectFixture::setupDefaultRNG() void EffectFixture::setupDefaultRNG()
{ {
EXPECT_CALL(serverMock, getRNG()).Times(AtLeast(0)); EXPECT_CALL(serverMock, getRNG()).Times(AtLeast(0));
EXPECT_CALL(rngMock, getInt64Range(_,_)).WillRepeatedly(Invoke(&getInt64RangeDef)); EXPECT_CALL(rngMock, nextInt64(_,_)).WillRepeatedly(Invoke(&getInt64Range));
EXPECT_CALL(rngMock, getDoubleRange(_,_)).WillRepeatedly(Invoke(&getDoubleRangeDef)); EXPECT_CALL(rngMock, nextDouble(_,_)).WillRepeatedly(Invoke(&getDoubleRange));
} }
} }