我似乎无法根据坐标生成PsuedoRandom数字

时间:2015-09-22 11:14:52

标签: c# seeding procedural-generation

我正在尝试创建由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));
}

4 个答案:

答案 0 :(得分:2)

我认为你的问题是你正在创造一个新的&#39;循环中随机...不要像你一样重新声明内部循环...而是在类级别声明它,然后简单地使用psuedoRandom.Next,例如见this SO post for an example of the issue you are experiencing

而不是像你一样在每次迭代时重新实例化一个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(); 
    }
}

编辑:正如Enigmativity在本文下面的评论中指出的那样,在每次迭代中重新定位也是浪费时间/资源。

P.S。如果你真的需要这样做,那么为什么不使用&#39;时间相关的默认种子值&#39;而不是指定一个?

答案 1 :(得分:0)

I'd use SipHash以对坐标进行哈希处理:

  • 实施相对简单
  • 它既需要一个键(地图的种子)和一个消息(坐标)作为输入
  • 您可以增加或减少轮次数作为质量/性能权衡。
  • 与您的代码不同,结果可以在流程和计算机之间重现。

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

答案 2 :(得分:0)

我发挥了一点作用来创建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;
    }
}

它有效,但是非常实现(因为RandomLCG),它应该给出一个大致的想法。它的内存效率高(没有数组)。可接受的折衷方案是实现值缓存,然后在位于地图周围值的某些部分时,将从缓存中获取而不是生成。

对于相同的xyseed,您将始终获得相同的值(反过来可以将其用作单元种子)。

TODO:找到一种方法,使Rnd(x)Rnd(y)没有LCG,并且初始化效率非常低(带周期)。

答案 3 :(得分:0)

在你提出所有建议的方法之后,我用这个解决了它。

"$(arr[@]}"