生成不同的随机坐标

Generate different random coordinates

本文关键字:随机 坐标      更新时间:2023-10-16

所以我用vector<string>做了这个'*'的平方。现在我需要生成六个数字,表示从1到N*N的不同坐标(这是正方形的面积),这样我就可以更改它们。到目前为止,我只有这个

#include <cstdlib>
#include <iostream>
int main(){
    int N = 4, x, y;
    srand(time(NULL));
        for(int i = 0; i < 6; i++){
            //generate 6 random coordinates
            int rnd = rand() % (N*N-1) + 2;
            if(rnd <= N){
                x = rnd;
                y = 0;
            }
            else{ 
                if((x = (rnd % N) - 1) < 0){
                x = rnd / N - 1;
                y = x;
                }
                else y = rnd / N;
            }
            std::cout << "rnd: " << rnd << " x:" << x << " y:" << y << "nn";
        }
}

但我一直得到相同的坐标。我的代码有缺陷还是需要添加一些内容?

您正在做一些奇怪的事情来获得xy。它比你现有的要简单得多:

    for(int i = 0; i < 6; i++){
        // the square is N x N, so you want two numbers from 0 to N-1
        int x = rand() % N;
        int y = rand() % N;
        std::cout << "x:" << x << " y:" << y << "nn";
    }

或者:

    for(int i = 0; i < 6; i++){
        int rnd = rand() % (N*N);
        int x = rnd % N;
        int y = rnd / N;
        std::cout << "rnd: " << rnd << " x:" << x << " y:" << y << "nn";
    }

当然,使用%以这种方式获取随机数是一个糟糕的想法,而rand()的常见实现在将多个值组合到多维空间中的坐标中时,恰好具有非常糟糕的特性:模式很可能会出现。

相反,在将随机值从一个范围操纵到所需范围时需要小心。幸运的是,有人已经为你做了数学运算,你可以通过<random>库来利用它。

#include <random>
std::mt19937 eng; // object which produces random bits
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
eng.seed(seed); // seed the bit generator, replaces srand()
std::uniform_int_distribution<> dist(0, N-1); // encapsulates the correct method of turning
                                              // random bits into random numbers in the range
                                              // [0, N)
for(int i = 0; i < 6; i++) {
  int x = dist(eng); // the distribution internally used the engine like rand()
  int y = dist(eng);
  std::cout << "x:" << x << " y:" << y << "nn";
}

或者:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist(0, N*N - 1);
for(int i = 0; i < 6; i++) {
  int rnd = dist(eng);
  int x = rnd % N; // used of % here is just fine
  int y = rnd / N;
  std::cout << "rnd: " << rnd << " x:" << x << " y:" << y << "nn";
}

这里有一个完整的程序,它在vector<string>中生成一个"*"的正方形,生成坐标并在正方形中标记这些坐标:

http://coliru.stacked-crooked.com/a/e024212ebc951f92

结果看起来像:

**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
x:0 y:7
x:0 y:2
x:6 y:8
x:5 y:0
x:4 y:7
x:0 y:2
***** ****
**********
 *********
**********
**********
**********
**********
 *** *****
****** ***
**********

其他答案讨论srand(time(NULL)) 引起的问题

嗯,

无论两次呼叫之间的时间间隔如何,这都保证适用于随机数的生成。

你可以使用类似的东西

int Min, Max;
random_device rd;   // non-deterministic generator
mt19937 gen(rd());  // to seed mersenne twister.
uniform_int_distribution<> dist(Min,Max); // distribute results between Min and Max inclusive.'

然后生成编号并使用进行分配

int Rand=dist(gen);

别忘了包括

<random>

每次运行时,我都会得到不同的结果。不过,请注意,时间(NULL)每秒只更改一次,因此在同一时间段内运行两次将产生相同的随机种子。

但是,您的代码还有许多其他问题。你的数学错了。

1)

int rnd = rand() % (N*N-1) + 2;

这将始终产生至少为2的结果,因此您永远不会得到1的结果,而代码的其余部分似乎有意引用网格的左上角。所以,一开始,你的随机公式就有偏差。

2)

网格中有N*N个坐标。

rand() % *value*

除以"值"(假定值为正)的余数总是产生0和(值-1)之间的结果,包括0和(1)。毕竟:

0 % 4 = 0
1 % 4 = 1
2 % 4 = 2
3 % 4 = 3
4 % 4 = 0

因此:

rand() % (N*N-1)

这将始终产生一个介于0和N*N-2之间的结果。因此,如果N是4,N*N-1是15,这将始终是0和14之间的结果,包括0和14,或者随机坐标只有15个可能的值,而网格中确实有16个不同的坐标。

结论:

你的方法的总体问题源于人类从1开始,然后从2开始,以此类推的自然倾向之间的脱节;在处理计算机代码和算法时,更自然的做法是从0开始编号,而不是从1开始。

当这种情况发生时,你的整个随机坐标生成变得非常简单:

int rnd = rand() % (N*N);
int x= rnd % N;
int y= rnd / N;

就是这样。根本不需要那个笨拙的if装置。