我知道C#Random类不会产生"真正的随机"数字,但是我想出了这个代码的问题:
public void autoAttack(enemy theEnemy)
{
//Gets the random number
float damage = randomNumber((int)(strength * 1.5), (int)(strength * 2.5));
//Reduces the damage by the enemy's armor
damage *= (100 / (100 + theEnemy.armor));
//Tells the user how much damage they did
Console.WriteLine("You attack the enemy for {0} damage", (int)damage);
//Deals the actual damage
theEnemy.health -= (int)damage;
//Tells the user how much health the enemy has left
Console.WriteLine("The enemy has {0} health left", theEnemy.health);
}
Run Code Online (Sandbox Code Playgroud)
然后我在这里调用函数(为了检查数字是否随机,我调用了5次):
if (thePlayer.input == "fight")
{
Console.WriteLine("you want to fight");
thePlayer.autoAttack(enemy1);
thePlayer.autoAttack(enemy1);
thePlayer.autoAttack(enemy1);
}
Run Code Online (Sandbox Code Playgroud)
但是,当我检查输出时,我得到每个3个函数调用的完全相同的数字.但是,每次运行程序时,我都会得到一个不同的数字(重复3次),如下所示:
You attack the enemy for 30 damage.
The enemy has 70 health left.
You attack the enemy for 30 damage.
The enemy has 40 health left.
You attack the enemy for 30 damage.
The enemy has 10 health left.
Run Code Online (Sandbox Code Playgroud)
然后我将重新/重新调试/运行程序,并获得一个不同的数字而不是30,但它将重复所有3次.
我的问题是:每次调用此函数时,如何确保获得不同的随机数?我一遍又一遍地得到相同的"随机"数字.
这是我使用的随机类调用:
private int randomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 30
我的猜测是每次randomNumber创建一个新实例Random......这反过来会根据当前时间创建一个新的伪随机数生成器......它不会像你想象的那样经常改变.
不要那样做.Random重复使用相同的实例...但不要通过创建静态Random变量来"修复"它.从长远来看,这不会很好,因为Random它不是线程安全的.它在测试中看起来都很好,然后你会在你碰巧不幸的并发后神秘地得到所有的零:(
幸运的是,使用线程本地工作并不是很难,特别是如果你使用的是.NET 4.最终会得到Random每个线程的新实例.
我写过一篇关于这个主题的文章,你可能觉得它很有用,包括这段代码:
using System;
using System.Threading;
public static class RandomProvider
{
private static int seed = Environment.TickCount;
private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>
(() => new Random(Interlocked.Increment(ref seed)));
public static Random GetThreadRandom()
{
return randomWrapper.Value;
}
}
Run Code Online (Sandbox Code Playgroud)
如果你改变你的new Random()呼叫RandomProvider.GetThreadRandom()可能会做你需要的一切(再次,假设.NET 4).这不涉及可测试性,而是一次一步......
你没有告诉我们代码randomNumber.如果它看起来像什么
private int randomNumber(int m, int n) {
Random rg = new Random();
int y = rg.Next();
int z = // some calculations using m and n
return z;
}
Run Code Online (Sandbox Code Playgroud)
那么,那就是你的问题.如果你继续创建新的实例Random,它们有时可能会有相同的种子(默认种子是系统时钟,它具有有限的精度;创建它们足够快并且它们获得相同的种子)然后由此生成器生成的序列将永远是相同的.
要解决此问题,您必须实例化一次实例Random:
private readonly Random rg = new Random();
private int randomNumber(int m, int n) {
int y = this.rg.Next();
int z = // some calculations using m and n
return z;
}
Run Code Online (Sandbox Code Playgroud)
为了澄清另一点,即使你这样做,输出Random仍然不是"真实的"随机.它只是伪随机的.