简体   繁体   English

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

[英]I can't seem to generate PsuedoRandom numbers based on co-ordinates

I am trying to create an infinite map of 1 and 0's procedurally generated by PRNG but only storing a grid of 7x7 which is viewable. 我试图创建一个由PRNG程序生成的1和0的无限映射,但只存储可查看的7x7网格。 eg on the screen you will see a 7x7 grid which shows part of the map of 1's and 0's and when you push right it then shifts the 1's and 0's across and puts the next row in place. 例如,在屏幕上你会看到一个7x7网格,它显示了1和0的地图的一部分,当你向右推时,然后将1和0移过,并将下一行放在适当的位置。

If you then shift left as it is pseudo randomly generated it regenerates and shows the original. 如果你随后向左移动,因为它是伪随机生成的,它会重新生成并显示原始数据。 You will be able to shift either way and up and down infinitely. 你将能够无限地向上和向下移动。

The problem I have is that the initial map does not look that random and the pattern repeats itself as you scroll right or left and I think it is something to do with how I generate the numbers. 我遇到的问题是初始地图看起来不是随机的,当你向右或向左滚动时,模式会重复,我认为这与我如何生成数字有关。 eg you could start at viewing x=5000 and y= 10000 and therefore it need to generate a unique seed from these two values. 例如,您可以从查看x = 5000和y = 10000开始,因此需要从这两个值生成唯一的种子。

(Complexity is the variable for the size of the viewport) (复杂性是视口大小的变量)

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);
        }
    }
}

This is what I use for left and right movement, 这是我用于左右运动的东西,

    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);
    }
}

To distill it down I need to be able to set 要提炼它,我需要能够设置

Level[x,y]=Returnrandom(offsetx,offsety) 电平[X,Y] = Returnrandom(OFFSETX,OFFSETY)

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

Your problem I think is that you are creating a 'new' random in loops... don't redeclare inside loops as you are... instead declare it at class level and then simply use psuedoRandom.Next eg See this SO post for an example of the issue you are experiencing 我认为你的问题是你在循环中创建一个'新'随机...不要像你那样重新声明内部循环...而是在类级别声明它然后只需使用psuedoRandom.Next例如看到这个SO帖子您遇到的问题的一个示例

instead of re-instantiating a Random() class at every iteration like you are doing: 而不是像你正在做的那样在每次迭代时重新实例化一个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);
    }
}

do something more like 做更像的事情

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

EDIT: As Enigmativity has pointed out in a comment below this post, reinstiating at every iteration is also a waste of time / resources too. 编辑:正如Enigmativity在本文下面的评论中指出的那样,在每次迭代中重新定位也是浪费时间/资源。

PS If you really need to do it then why not use the 'time-dependent default seed value' instead of specifying one? PS如果你真的需要这样做,为什么不使用'时间相关的默认种子值'而不是指定一个?

I'd use SipHash to hash the coordinates: 我使用SipHash来散列坐标:

  • It's relatively simple to implement 实施起来相对简单
  • It takes both a key (seed for your map) and a message (the coordinates) as inputs 它需要一个键(地图的种子)和一个消息(坐标)作为输入
  • You can increase or decrease the number of rounds as a quality/performance trade-off. 您可以增加或减少轮数作为质量/性能权衡。
  • Unlike your code, the results will be reproducible across processes and machines. 与您的代码不同,结果将在流程和机器之间重现。

The SipHash website lists two C# implementations: SipHash网站列出了两个C#实现:

I've play a bit to create rnd(x, y, seed) : 我玩了一下来创建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;
    }
}

It works, but ofc an afwul implementation (because Random is LCG ), it should give a general idea though. 它可以工作,但是一个afwul实现(因为RandomLCG ),它应该给出一个大致的想法。 It's memory efficient (no arrays). 它的内存效率高(没有数组)。 Acceptable compromise is to implement value caching , then while located in certain part of map surrounding values will be taken from cache instead of generating. 可接受的折衷方案是实现值缓存 ,然后当位于地图的某些部分时,周围的值将从缓存中获取而不是生成。

For same x , y and seed you will always get same value (which in turn can be used as a cell seed). 对于相同的xyseed您将始终获得相同的值(反过来可以将其用作单元种子)。

TODO: find a way to make Rnd(x) and Rnd(y) without LCG and highly inefficient initialization (with cycle). TODO:找到一种方法来制作没有LCG的Rnd(x)Rnd(y)以及非常低效的初始化(带循环)。

I solved it with this, after all of you suggested approaches. 在你提出所有建议的方法之后,我解决了这个问题。

    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);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM