我似乎不能基于坐标生成伪随机数

本文关键字:坐标 随机数 不能 于坐标 | 更新日期: 2023-09-27 18:14:08

我试图创建由PRNG程序生成的1和0的无限地图,但只存储7x7的网格,这是可见的。例如,在屏幕上,你将看到一个7x7的网格,其中显示了1和0的地图的一部分,当你向右推时,它会移动1和0,并将下一行放置到位。

如果你然后左移,因为它是伪随机生成的,它会重新生成并显示原始的。你可以无限地上下移动。

我所遇到的问题是,最初的地图看起来并不那么随机,当你向左或向右滚动时,模式会重复,我认为这与我如何生成数字有关。例如,你可以从查看x=5000和y= 10000开始,因此它需要从这两个值生成一个唯一的种子。

(复杂度是视口大小的变量)

void CreateMap(){
    if(complexity%2==0) {
        complexity--;
    }
    if (randomseed) {
        levelseed=Time.time.ToString();
    }
    psuedoRandom = new System.Random(levelseed.GetHashCode());
    offsetx=psuedoRandom.Next();
    offsety=psuedoRandom.Next();
    levellocation=psuedoRandom.Next();
    level = new int[complexity,complexity];
    middle=complexity/2;
    for (int x=0;x<complexity;x++){
        for (int y=0;y<complexity;y++){
            int hashme=levellocation+offsetx+x*offsety+y;
            psuedoRandom = new System.Random(hashme.GetHashCode());
            level[x,y]=psuedoRandom.Next(0,2);
        }
    }
}

这是我用来左右移动的,

    void MoveRight(){
    offsetx++;
    for (int x=0;x<complexity-1;x++){
        for (int y=0;y<complexity;y++){
            level[x,y]=level[x+1,y];
        }
    }
    for (int y=0;y<complexity;y++){
        psuedoRandom = new System.Random(levellocation+offsetx*y);
        level[complexity-1,y]=psuedoRandom.Next(0,2);
    }
}
void MoveLeft(){
    offsetx--;
    for (int x=complexity-1;x>0;x--){
        for (int y=0;y<complexity;y++){
            level[x,y]=level[x-1,y];
        }
    }
    for (int y=0;y<complexity;y++){
        psuedoRandom = new System.Random(levellocation+offsetx*y);
        level[0,y]=psuedoRandom.Next(0,2);
    }
}

我需要设置

水平(x, y) = Returnrandom (offsetx offsety)

int RandomReturn(int x, int y){
    psuedoRandom = new System.Random(Whatseedshouldiuse);   
    return (psuedoRandom.Next (0,2));
}

我似乎不能基于坐标生成伪随机数

我认为你的问题是你正在创建一个'新的'随机循环…不要像现在这样重新声明内部循环……而是在类级别声明它,然后简单地使用psuedoRandom。下一个例子,请看这篇关于你正在经历的问题的例子

而不是在每次迭代时重新实例化Random()类:

for (int x=0;x<complexity;x++){
    for (int y=0;y<complexity;y++){
        int hashme=levellocation+offsetx+x*offsety+y;
        psuedoRandom = new System.Random(hashme.GetHashCode());
        level[x,y]=psuedoRandom.Next(0,2);
    }
}

更像

for (int x=0;x<complexity;x++){
    for (int y=0;y<complexity;y++){
        // Give me the next random integer
        moreRandom = psuedoRandom.Next(); 
    }
}

EDIT:正如Enigmativity在这篇文章下面的评论中指出的那样,在每次迭代中重新设置也是浪费时间/资源。

注:如果你真的需要这样做,那么为什么不使用"与时间相关的默认种子值"而不是指定一个呢?

我将使用SipHash来散列坐标:

    实现起来相对简单
  • 它接受一个键(地图的种子)和一个消息(坐标)作为输入
  • 你可以增加或减少回合数作为质量/性能权衡。
  • 不像你的代码,结果可以跨进程和机器重现。

SipHash网站列出了两个c#实现:

  • https://github.com/tanglebones/ch-siphash
  • https://github.com/BrandonHaynes/siphash-csharp

我已经玩了一点创建rnd(x, y, seed):

class Program
{
    const int Min = -1000; // define the starting point
    static void Main(string[] args)
    {
        for (int x = 0; x < 10; x++)
        {
            for (int y = 0; y < 10; y++)
                Console.Write((RND(x, y, 123) % 100).ToString().PadLeft(4));
            Console.WriteLine();
        }
        Console.ReadKey();
    }
    static int RND(int x, int y, int seed)
    {
        var rndX = new Random(seed);
        var rndY = new Random(seed + 123); // a bit different
        // because Random is LCG we can only move forward
        for (int i = Min; i < x - 1; i++)
            rndX.Next();
        for (int i = Min; i < y - 1; i++)
            rndY.Next();
        // return some f(x, y, seed) = function(rnd(x, seed), rnd(y, seed))
        return rndX.Next() + rndY.Next() << 1;
    }
}

它可以工作,但如果一个完整的实现(因为Random是LCG),它应该给出一个总的想法。它的内存效率(没有数组)。可接受的折衷方案是实现值缓存,然后当位于映射周围的某些部分的值将从缓存中取出,而不是生成。

对于相同的x, yseed,您将始终获得相同的值(反过来可以用作细胞种子)。

TODO:找到一种方法使Rnd(x)Rnd(y)没有LCG和低效的初始化(循环)。

我用这个解决了这个问题,在你们所有的建议之后。

    void Drawmap(){
    for (int x=0;x<complexity;x++){
        for (int y=0;y<complexity;y++){
            psuedoRandom = new System.Random((x+offsetx)*(y+offsety));
            level[x,y]=psuedoRandom.Next (0,2);
        }
    }