2017-04-18 53 views
-1

我对某段代码有问题,它应该根据预设的难度级别给敌人一个随机的一组物品。我正在使用Bjorne随机函数的修改模板版本。当我用自己原来的版本我仍然有问题:在Switch Switch Cases中使用随机数

Random number generator code from Stroustrup:

template<class T> 
T rand_num(const T & low, const T & high) 
{ 
    static std::default_random_engine re{}; 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

当我测试通过做一个EnemyAI对象,它封装了OffensiveEntity和难易度设定,比方说,1节,它总是将随机数设置为1,并在此情况下始终选择生药水。如果我将第二个if声明设置为if (tempRandom == 1)的条件,它会选择该条。

void EnemyAI::Equip() 
{ 
    m_offensiveEntity->ClearItems(); 

    std::vector<std::shared_ptr<Item>> tempItems; 

    int tempRandom = 0; 

    switch (m_difficultyLevel) 
    { 
    case 0: 
    case 1: 
    { 
     tempRandom = rand_num<int>(1, 4); 
     if ((tempRandom == 1) || (tempRandom == 2) || (tempRandom == 3) || (tempRandom == 4)) 
      tempItems.push_back(CreateTempItem("Health Potion : HP", 3, 3, 
-10, Result::Effect::nothing)); 
     if (tempRandom == 3) 
      tempItems.push_back(CreateTempItem("Wooden Stick : DMG", 5, 2, 10, Result::Effect::nothing, 3, 13, Result::Effect::nothing)); 
     break; 
    } 
    case 2: ... etc 

这个问题的原因是什么?下面是输出:

Health Potion : HP name 
3 durability 
-10 total damage 
3 energy cost 
0 effect 

当在此键入:

int main() 
{ 
    std::shared_ptr<EnemyAI> offensiveEntityInterface = 
     std::make_shared<EnemyAI>(EnemyAI("Dank Memerson", 50, 1)); 

    offensiveEntityInterface->Equip(); 
    for (auto & i : offensiveEntityInterface->GetEquiped()) 
    { 
     std::cout << i->GetName() << " name \n"; 
     std::cout << i->GetHP() << " durability \n"; 
     std::shared_ptr<const Result> tempResult = i->Use(); 
     std::cout << tempResult->m_totalDamage << " total damage \n"; 
     std::cout << tempResult->m_energyCost << " energy cost \n"; 
     std::cout << tempResult->m_effect << " effect \n"; 
    } 
    std::cin.get(); 
    return 0; 
} 

继承人在引擎收录的源代码 https://pastebin.com/F4Q74Gc6

回答

1

您的引擎非种子选手,并因此使用默认值,每次运行程序时都是一样的。为了确保每次运行都不同,您需要将其种子。

一些老式程序员通常建议将当前系统时钟作为整数并将其用作种子,但C++ 11特别建议您使用std::random_device,它将尝试通过读取温度传感器来获取真正的随机数CPU或者通过一些类似的手段,并且如果它无法做到这一点,将回退到伪随机方法(如抓取系统时钟或其他方法)。

template<class T> 
T rand_num(const T & low, const T & high) 
{ 
    static std::default_random_engine re{std::random_device{}()}; 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

此外,您的代码将为您用于生成数字的每种类型创建一个新引擎。就像,如果你调用rand_num<int32_t>,rand_num<int64_t>,rand_num<int16_t>,这是三种不同的引擎,它们将在运行时被分配和维护在堆栈上。除非你觉得你一定要做到这一点,你最好不要写代码,看起来像这样:

template<class T> 
T rand_num(std::default_random_engine & re, const T & low, const T & high) 
{ 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

int main() { 
    std::default_random_engine engine{std::random_device{}()}; 
    /*...*/ 
    int val = rand_num<int>(engine, 1, 4); 
    /*...*/ 
} 

许多C++实现映射std::default_random_enginestd::mt19937,这是一个非常重的物体,包括很多国家的必须在创建任何时候分配和生成。确保你总是重新使用引擎可以节省一些时间。

+0

因此,如果你像第一个例子那样声明默认的随机引擎是静态的,那么你的第二个例子就没有必要了?因为在第二个函数中使用std :: default_random_engine引擎对象与std :: random_device调用该函数会创建与在函数中初始化静态std :: default_random_engine引擎对象并调用该对象完全相同的结果? – Chopdops

+0

@Chopdops这两个版本之间的输出在他们“做什么”方面并没有意义上的不同,也就是说他们都在指定的范围内产生随机数。不同之处在于第一个版本将为函数调用的每个唯一类型创建'std :: default_random_engine'的新实例,而第二个版本将只创建一个实例,而不管您使用多少类型(除非手动创建更多的发动机)。 – Xirema

+0

@Chopdops为什么重要的原因是'引擎'对象构造起来相当昂贵,特别是如果'std :: default_random_engine'映射到'std :: mt19937',这在许多C++实现中是标准的。如果你知道你只会调用'rand_num '并且不会调用该函数的任何其他版本,那么差异并不重要,你可以愉快地使用第一个版本。但是,如果不是这样,那么每次使用类型时都会遭受性能处罚。 – Xirema