C#中如何获取Random当前的种子?

问题描述 投票:0回答:9

在我的游戏中,我将使用随机值来选择玩家从宝箱中获得的奖励。问题是你可以快速保存和快速加载,这意味着他们可以不断重新加载以重新随机化,直到他们得到他们想要的东西。有什么方法可以获取我的

Random
对象的当前种子值,并可能在加载时返回到同一点,以便它们不能滥用随机化?

c# random
9个回答
21
投票

这是不可能的。

相反,您可以使用二进制序列化来序列化

Random
实例。
Random
[Serializable]
,种子和内部状态将持续存在。

但是请注意,保存随机种子可以让你的玩家预测未来,如果你允许在战斗中保存,这将非常有用。

另请注意,用户仍然可以保存、打开宝箱、加载、执行生成随机数的操作,然后从宝箱中获取不同的物品。


12
投票

不确定是否获取种子,但您可以保存为

Random
对象提供的值。请记住,有两个构造函数。第二个是
Random(Int32)
,所以如果您自己设置种子(一个足够简单的值是 Environment.TickCount),您可以在将该值传递给构造函数之前将该值存储在某处。如果您还没有阅读过,请查看 MSDN 文档:https://learn.microsoft.com/en-us/dotnet/api/system.random


4
投票

事实上,

Seed
未存储,因为它与初始化后的算法无关。它的衍生物之一
mj
存储在
SeedArray
中,您可以检查使用反射来比较两个
Random
实例:

int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
mj = MSEED - subtraction;
SeedArray[55]=mj;

因此,您所要做的就是检查

SeedArray
中的最后一个元素(索引 55)。这是唯一使用
Seed
的地方。

[从已删除的问题中移动答案如何确定两个 Random 实例是否具有相同的种子?]


3
投票

您可以将随机奖励计算为以下哈希函数:

  1. 当您开始游戏时分配的一些种子,并保留在已保存游戏中;和
  2. 箱子的一些恒定属性在所有游戏中都是不变的(例如固定的 ID,或者如果它从不移动的话它的位置)。

此方法的优点是,无论您保存和重玩多少次,给定的宝箱在给定的游戏中始终会产生相同的奖励,即使宝箱以不同的顺序打开,或者以不同的顺序触发其他“随机”事件。订单。此外,每个箱子的奖励都独立于其他箱子的奖励,只要散列中使用的箱子的属性是独立的。

在下面的示例中,

GetRewardId
生成奖励ID作为游戏种子与箱子的x坐标异或的散列。它使用
Random
执行哈希,使用哈希输入作为
Random
对象的种子,并将第一个随机生成的数字作为输出。

private static int GetRewardId(int seed, float coord, int numRewards)
{
    int tempSeed = BitConverter.ToInt32(BitConverter.GetBytes(coord), 0) ^ seed;
    return new Random(tempSeed).Next(numRewards);
}

int seed  = new Random().Next();
int numDifferentRewards = 5;
float xCoordinate = chest.Position.X;
int rewardId = GetRewardId(seed, xCoordinate, numDifferentRewards);

如果您的许多箱子可能在 sace 中对齐,您可能需要通过与 y 和/或 z 坐标进行异或来选择不同的属性,或使用其他维度。


1
投票

我可能只是按照 MSDN 使用它:http://msdn.microsoft.com/en-us/library/ctssatww.aspx

Random(seed)

其中种子是我从存储中加载的一些值。


1
投票

不幸的是,在 Microsoft 的参考实现中,无参数 ctor 的种子值甚至没有保存,更不用说公开访问了: http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca

但是,正如您在参考实现中也可以看到的那样,您可以传入的值(可能应该 - 我知道我这样做),就像他们所做的那样,是:

Environment.TickCount

因此,将其保存到一个变量中,然后将该变量传递给带有 arg 的 ctor,现在您就知道了种子。 不是事后,但这应该足以满足您的意图。


0
投票

这仅与切线相关,但如果有人想知道为什么

Random
没有名为
Seed
的属性或名为
GetSeed()
的方法,我愿意打赌这可能是出于安全考虑:您想向外界公开您的“随机”数字生成器的内部工作原理吗?绝对不是!否则,某些客户端代码可能会四处寻找,直到获得您正在使用的值,然后用它们做一些令人讨厌和意想不到的事情。


0
投票

您可以创建自定义 Random 类来获取种子 公共类 DebugRandom { 私人随机随机; 私有 int 种子;

    public static readonly int defaultSeed = Environment.TickCount;

    public DebugRandom(int? seed = null)
    {
        this.seed = seed ?? defaultSeed;
        random = new Random(this.seed);
    }

    public int Seed => seed;

    public int Next()
    {
        return random.Next();
    }

    public int Next(int minValue, int maxValue)
    {
        return random.Next(minValue, maxValue);
    }

    public double NextDouble()
    {
        return random.NextDouble();
    }
}

-3
投票

我建议您生成一个随机数并将其用作真正的随机数生成器的种子数。通过这种方法,您将获得一个实际上是随机数的种子号,您可以保存种子号以供进一步使用。

© www.soinside.com 2019 - 2024. All rights reserved.