我似乎无法基于坐标生成伪随机数。

3
我正在尝试使用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);
    }
}

为了简化需求,我需要能够设置以下内容:
Level[x,y]=Returnrandom(offsetx,offsety)
其中的html标签需要保留。
int RandomReturn(int x, int y){
    psuedoRandom = new System.Random(Whatseedshouldiuse);   
    return (psuedoRandom.Next (0,2));
}

有没有所需地图的最大尺寸,例如1024 x 1024个条目? - Codor
不,我正在尝试使其看起来是无限的。例如,您可以从查看坐标10000、445554开始,这也将完全随机生成。 - Munkybunky
如果(randomseed)为真或假... 如果为假,那么levelseed是什么? - Paul Zahra
3
@Munkybunky,我认为你的问题在于你正在循环中创建一个“新”的随机数……不要像你这样在循环内重新声明它……相反,在类级别上声明它,然后只需使用psuedoRandom.Next。 - Paul Zahra
@PaulZahra 如果seed为false,则使用用户可以输入的单词的哈希码。我一直在使用“Kurt”作为实验的种子。我正在循环内创建新的种子,以确保当用户滚动时,如果他们滚回到相同的位置,他们会得到相同的模式。例如,如果在200,200位置设置为1,然后用户向右滚动50,然后再向左滚动50,它需要使用伪随机生成器重新生成1。 - Munkybunky
显示剩余8条评论
4个回答

2
我认为你的问题是在循环中创建了一个“新”的随机数...不要在循环中重新声明,而是在类级别上声明,然后简单地使用psuedoRandom.Next,例如,请参见此SO帖子以查看你正在遇到的问题的示例 与其像你现在所做的那样在每次迭代中重新实例化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. 如果你确实需要这样做,为什么不使用“时间依赖的默认种子值”而不是指定一个呢?


另外,您可能应该指出调用new Random(someSeedValue)是浪费时间的。如果您创建一个Random的单一实例,那么只需调用new Random()即可。 - Enigmativity
如果是静态的话,比如没有移动,我认为这个方法可以奏效。例如生成一个5x5的网格,在每一行上都使用上述方法生成10001,利用x和y坐标进行移动。你向左移动时,从新的坐标生成随机数,第二列移动到第一列,然后你就会得到一个不同的第一列,可能会被填满1。 - Munkybunky
我认为我需要的是一种基于坐标值一致生成随机数的方法。因此,如果我引用地图上的 x 和 y 偏移量,我将始终得到相同的结果。 - Munkybunky
@Enigmativity 我认为我有两个问题,1是使用gethashcode,2是从x和y中选择哪个种子值更合适? - Munkybunky
@Munkybunky 只是一个想法,为什么不将 x = 1 和 y = 2 连接起来得到 "12",然后转换为整数 = 12,并将其作为种子使用,即对于给定的坐标和 'random',这将是可重现的。 - Paul Zahra
显示剩余2条评论

0

0

在你们提出的各种方法之后,我用这个方案解决了它。

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

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,您将始终获得相同的值(这反过来可以用作单元种子)。

待办事项:找到一种方法使Rnd(x)Rnd(y)不使用LCG和高度低效的初始化(带有循环)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接