C# 如何围绕Random.Next()限制进行设计?

C# 如何围绕Random.Next()限制进行设计?,c#,unity3d,C#,Unity3d,假设我有一个具有10个属性的对象,所有属性都是基于System.Random的算法使用预先确定的种子随机生成的,例如: System.Random randomNumber = new System.Random(seed); int prop0 = randomNumber.Next(x0, y0); int prop1 = randomNumber.Next(x1, y1); //... int prop9 = randomNumber.Next(x9, y9); 这一切都很好,直到我决定

假设我有一个具有10个属性的对象,所有属性都是基于
System.Random
的算法使用预先确定的种子随机生成的,例如:

System.Random randomNumber = new System.Random(seed);
int prop0 = randomNumber.Next(x0, y0);
int prop1 = randomNumber.Next(x1, y1);
//...
int prop9 = randomNumber.Next(x9, y9);
这一切都很好,直到我决定删除1个属性。假设它是我调用
Next()
的第一个属性,现在所有结果都会因调用顺序的改变而改变

  • 如果要维护其他属性的结果,该怎么办

  • 我是否只生成第一个属性并丢弃它

  • 我以后应该如何最好地解决这个问题,以便更轻松地更新我的属性列表?


您可以丢弃第一个随机生成的数字,而不是生成和丢弃第一个属性


我无法想象你会取得什么成就。如果所有属性都是随机生成的整数,为什么不将它们一起保存在
列表

类型的属性中?如果要保留单个对象的值,那么最好的选择可能是在源中包含这些值。这将使这些值独立于任何其他值(例如,不同的RNG实现)

如果您为许多对象生成值(并且预生成不是选项),那么您肯定必须放弃第一个值。 也许编写一个工厂函数来跟踪所有更改是最好的主意

如果您预见到这是许多对象类的一个问题,那么您可能需要实现一个更通用的解决方案:例如,将
字段
映射到
下一次调用的次数

但是这有点太多了,imho。

最明显的解决方案是生成随机值,但忽略它的结果

另一个选择是完全摆脱
随机
,使用不同的随机生成算法。我想象的是函数
f(seed,value)
,它基于
seed
value
返回“伪随机”值,但它是可重复的

这样,每个属性都将有与其关联的
,并且它的随机等价物将独立于其他值的随机等价物

我当时做的算法可以用作这样的函数。如果只使用x值,将最后一行从
更改为
,并将
更改为
,而不是将
0
更改为
3
,则可以像这样使用它:

int prop0 = RandomX.Generate(seed, 0x45F6C854, x0, y0);
int prop1 = RandomX.Generate(seed, 0x96F4DC41, x1, y1);
//...
int prop9 = RandomX.Generate(seed, 0xFE840301, x9, y9);
因此,如果删除或添加属性,它不会影响其他属性。如果您在代码中生成所有的数字,这也会起作用,因此您不必对每个值的生成进行监视

或者你可以用类似的东西

int prop0 = RandomX.Generate(globalSeed, objectSeed, propertySeed, from, to);
3个种子的组合将在
的范围内产生“伪随机”值<代码>至

生成算法可能类似于:

public static uint bitRotate(uint x)
{
    const int bits = 16;
    return (x << bits) | (x >> (32 - bits));
}

public static UInt32 Generate(int seed1, int seed2, int seed3)
{
    // simple "hashing" algorithm
    UInt32 num = 1;
    for (uint i = 0; i < 16; i++)
    {
        // multiply by prime numbers
        num = num * 119 + (uint)seed1;
        num = bitRotate(num);
        num = num * 541 + (uint)seed2;
        num = bitRotate(num);
        num = num * 809 + (uint)seed3;
        num = bitRotate(num);
        num = num * 673 + (uint)i; // not sure if necessary
        num = bitRotate(num);
    }
    return num;
}
公共静态uint位旋转(uint x)
{
常数int位=16;
返回(x>(32位));
}
公共静态UInt32生成(int-seed1、int-seed2、int-seed3)
{
//简单的“散列”算法
UInt32 num=1;
对于(uint i=0;i<16;i++)
{
//乘素数
num=num*119+(uint)种子1;
num=位旋转(num);
num=num*541+(uint)种子2;
num=位旋转(num);
num=num*809+(uint)种子3;
num=位旋转(num);
num=num*673+(uint)i;//不确定是否需要
num=位旋转(num);
}
返回num;
}

只需将full
uint
范围编号转换为
from
<代码>到范围。

我很难想象你想做什么。这些属性看起来像什么?你如何分配他们的价值?“由于调用顺序改变而导致的结果变化”是什么意思?请阅读并展示你的代码。是的,想象你期望发生的事情真的很复杂。当您删除一个属性时,您预计会发生什么情况?如果我删除
Next()
的第一行,之后所有的值都会移动(我知道这是一个没有上下文的混淆词)。我希望能够运行这个程序,并获得与prop1-9相同的结果。当然,只有一种可能的解决方案(运行
Next()
但放弃它),但我想设计我的程序来期望它,所以我不会到处乱扔
Next()
。你的算法看起来很酷,让我想起了xxhash(我用它来散列种子,以避免在第1-n个种子上重复模式)。但我不确定你的算法在第1个种子上的随机性有多大?你说的“第1个种子”是什么意思?我的意思是有2级随机性。(1) 就使用单个种子和获取第1个
Next()
而言。(2) 使用1-n作为种子值,并为每个种子值取1st
Next()
。我更大的要求包括两者。所以我最终做了
System.Random(散列(种子))
作为
System.Random
不符合第二个要求。无论如何,我认为这不是我最初问题的重点。你能解释一下RandomX.Generate(seed,0x45F6C854,x0,y0)
,或者它与类似的散列函数有何不同?@bitinn如果你不确定,你不应该接受这个答案。这可能会阻止其他人尝试回答。