我尝试着创造一款带有骰子的游戏,我需要在其中添加一些随机数字(游戏邦注:即模拟骰子的边缘)。我知道如何在1到6之间

#include <cstdlib> 
#include <ctime> 
#include <iostream>

using namespace std;

int main() 
{ 
    srand((unsigned)time(0)); 
    int i;
    i = (rand()%6)+1; 
    cout << i << "\n"; 
}

并不是很好地工作,因为当我运行程序几次,这是我得到的输出:

6
1
1
1
1
1
2
2
2
2
5
2

所以我想要一个每次生成不同随机数的命令,而不是连续5次生成相同的随机数。是否有这样的命令?


当前回答

以下是我的5美分:

// System includes
#include <iostream>
#include <algorithm>
#include <chrono>
#include <random>

// Application includes

// Namespace
using namespace std;

// Constants
#define A_UNUSED(inVariable) (void)inVariable;


int main(int inCounter, char* inArguments[]) {

    A_UNUSED(inCounter);
    A_UNUSED(inArguments);

    std::random_device oRandomDevice;
    mt19937_64 oNumber;
    std::mt19937_64::result_type oSeed;
    std::mt19937_64::result_type oValue1;
    std::mt19937_64::result_type oValue2;

    for (int i = 0; i < 20; i++) {

        oValue1 = (std::mt19937_64::result_type) std::chrono::duration_cast<std::chrono::seconds>(
            std::chrono::system_clock::now().time_since_epoch()
        ).count();
        oValue2 = (std::mt19937_64::result_type) std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::system_clock::now().time_since_epoch()
        ).count();
        oSeed = oRandomDevice() ^ (oValue1 + oValue2);
        oNumber.seed(oSeed);

        cout << "oNumber: " << oNumber << "\n";
        cout << "oNumber.default_seed: " << oNumber.default_seed << "\n";
        cout << "oNumber.initialization_multiplier: " << oNumber.initialization_multiplier << "\n";
        cout << "oNumber.mask_bits: " << oNumber.mask_bits << "\n";
        cout << "oNumber.max(): " << oNumber.max() << "\n";
        cout << "oNumber.min(): " << oNumber.min() << "\n";
        cout << "oNumber.shift_size: " << oNumber.shift_size << "\n";
        cout << "oNumber.state_size: " << oNumber.state_size << "\n";
        cout << "oNumber.tempering_b: " << oNumber.tempering_b << "\n";
        cout << "oNumber.tempering_c: " << oNumber.tempering_c << "\n";
        cout << "oNumber.tempering_d: " << oNumber.tempering_d << "\n";
        cout << "oNumber.tempering_l: " << oNumber.tempering_l << "\n";
        cout << "oNumber.tempering_s: " << oNumber.tempering_s << "\n";
        cout << "oNumber.tempering_t: " << oNumber.tempering_t << "\n";
        cout << "oNumber.tempering_u: " << oNumber.tempering_u << "\n";
        cout << "oNumber.word_size: " << oNumber.word_size << "\n";
        cout << "oNumber.xor_mask: " << oNumber.xor_mask << "\n";
        cout << "oNumber._Max: " << oNumber._Max << "\n";
        cout << "oNumber._Min: " << oNumber._Min << "\n";
    }

    cout << "Random v2" << endl;
    return 0;
}

其他回答

#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    srand(time(NULL));
    int random_number = std::rand(); // rand() return a number between ​0​ and RAND_MAX
    std::cout << random_number;
    return 0;
}

http://en.cppreference.com/w/cpp/numeric/random/rand

这里有一个解决方案。创建一个返回随机数的函数并放置它 在main函数之外,使其具有全局性。希望这能有所帮助

#include <iostream>
#include <cstdlib>
#include <ctime>
int rollDie();
using std::cout;
int main (){
    srand((unsigned)time(0));
    int die1;
    int die2;
    for (int n=10; n>0; n--){
    die1 = rollDie();
    die2 = rollDie();
    cout << die1 << " + " << die2 << " = " << die1 + die2 << "\n";
}
system("pause");
return 0;
}
int rollDie(){
    return (rand()%6)+1;
}

非常固执己见的回答

c++ <random>库违反了软件工程的最佳原则之一:“简单的事情做简单,复杂的事情,不寻常的事情可以更复杂一点。”

相反,他们甚至把简单和常见的用例变得过于复杂,只是因为他们患有文化疾病,害怕像“这还不够普遍”这样的评论。

As a result, now whenever you want a simple random number, you have to look into the documentation, read stack overflow with walls of text, glorifying this terrible design, instead of it just being an easy-to-remember one or 2 liner. (Common Lisp is more pragmatic: (random 5) yields uniformly distributed integers from 0..4 and (random 1.0) yields real numbers between 0.0..1.0. That is the most common use case and it is at your finger tips. If you need more sophisticated stuff, you have to find packages and libraries or do it yourself.)

只需计算一下全球范围内每个人浪费在理解标题及其内容上的时间累积的工时,就可以看到它有多糟糕。

即使我现在在浪费我的时间,写这个答案,你也在浪费时间,阅读它,只是因为他们创造了一个复杂的谜题,这与其他现代令人厌恶的东西相似,比如Vulkan API。

那么,如何应对呢?浪费一次时间,为自己最常见的用例编写一个头文件,然后在需要时重用它。

我知道如何在c++中生成随机数,而不使用任何标头,编译器intrinsic或任何东西。

#include <cstdio> // Just for printf
int main() {
    auto val = new char[0x10000];
    auto num = reinterpret_cast<unsigned long long>(val);
    delete[] val;
    num = num / 0x1000 % 10;
    printf("%llu\n", num);
}

在运行一段时间后,我得到了以下数据:

0: 5268
1: 5284
2: 5279
3: 5242
4: 5191
5: 5135
6: 5183
7: 5236
8: 5372
9: 5343

看起来是随机的。

工作原理:

现代编译器使用ASLR(地址空间布局随机化)防止缓冲区溢出。 你可以不使用任何库生成一些随机数,这只是为了好玩。不要那样使用ASLR。

每次生成不同的随机数,而不是连续六次生成相同的随机数。

用例场景

我把“可预测性”的问题比作一袋六块纸,每个纸上写着一个从0到5的值。每当需要一个新的数值时,就会从袋子里抽出一张纸。如果袋子是空的,那么数字被放回袋子。

根据这个,我可以创建一个算法。

算法

一个包通常是一个集合。我选择了bool[](也称为布尔数组,位平面或位图)来扮演袋子的角色。

我选择bool[]的原因是,每一项的索引已经是每张纸的值。如果论文需要在它们上面写任何东西,那么我将使用Dictionary<string, bool>代替它。布尔值用于跟踪数字是否已经绘制。

一个名为RemainingNumberCount的计数器被初始化为5,当选择一个随机数时,计数器会向下计数。这样,我们就不必在每次想要画一个新数字时,都要计算还剩下多少张纸了。

为了选择下一个随机值,我使用for..循环来扫描索引包,并使用一个计数器来计数,当索引为false时,称为NumberOfMoves。

NumberOfMoves用于选择下一个可用号码。NumberOfMoves首先被设置为0到5之间的随机值,因为有0..我们可以通过袋子的5个可行步骤。在下一次迭代中,NumberOfMoves被设置为0到4之间的随机值,因为现在有0..我们可以用4步穿过袋子。在使用这些数字时,可用的数字会减少,因此我们使用rand() % (RemainingNumberCount + 1)来计算NumberOfMoves的下一个值。

当NumberOfMoves计数器为零时,for..循环应该如下所示:

将当前值设置为与..循环的索引。 将包中的所有数字设置为false。 停止for..循环。

Code

上述解决方案的代码如下:

(将以下三个块依次放入主.cpp文件中)

#include "stdafx.h"
#include <ctime> 
#include <iostream>
#include <string>

class RandomBag {
public:
    int Value = -1;

    RandomBag() {
        ResetBag();

    }

    void NextValue() {
        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        int NumberOfMoves = rand() % (RemainingNumberCount + 1);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            if (BagOfNumbers[i] == 0) {
                NumberOfMoves--;

                if (NumberOfMoves == -1)
                {
                    Value = i;

                    BagOfNumbers[i] = 1;

                    break;

                }

            }



        if (RemainingNumberCount == 0) {
            RemainingNumberCount = 5;

            ResetBag();

        }
        else            
            RemainingNumberCount--; 

    }

    std::string ToString() {
        return std::to_string(Value);

    }

private:
    bool BagOfNumbers[6]; 

    int RemainingNumberCount;

    int NumberOfMoves;

    void ResetBag() {
        RemainingNumberCount = 5;

        NumberOfMoves = rand() % 6;

        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            BagOfNumbers[i] = 0;

    }

};

控制台类

我创建这个Console类是因为它可以很容易地重定向输出。

下面的代码中…

Console::WriteLine("The next value is " + randomBag.ToString());

...可以用……

std::cout << "The next value is " + randomBag.ToString() << std::endl; 

...然后这个Console类可以根据需要删除。

class Console {
public:
    static void WriteLine(std::string s) {
        std::cout << s << std::endl;

    }

};

主要方法

用法示例如下:

int main() {
    srand((unsigned)time(0)); // Initialise random seed based on current time

    RandomBag randomBag;

    Console::WriteLine("First set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nSecond set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nThird set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nProcess complete.\n");

    system("pause");

}

示例输出

当我运行程序时,我得到以下输出:

First set of six...

The next value is 2
The next value is 3
The next value is 4
The next value is 5
The next value is 0
The next value is 1

Second set of six...

The next value is 3
The next value is 4
The next value is 2
The next value is 0
The next value is 1
The next value is 5

Third set of six...

The next value is 4
The next value is 5
The next value is 2
The next value is 0
The next value is 3
The next value is 1

Process complete.

Press any key to continue . . .

关闭声明

该程序是使用Visual Studio 2017编写的,我选择使用. net 4.6.1使其成为Visual c++ Windows控制台应用程序项目。

我在这里没有做任何特别的事情,所以代码应该也适用于早期版本的Visual Studio。