c#中的随机加权



我正在用c#创造一款游戏,而这款游戏的关键部分便是随机性。它本质上是一个摔跤模拟器,其中的"动作"是根据许多因素选择的,比如摔跤手的属性和当前的动量。

然后在所有符合这个标准的移动中,选择一个随机的移动来执行,使用随机对象和跳过/采取在LINQ中,但这真的不够。我想做的是权重移动被选中的概率(我已经在移动表中有一列,用于1到100之间的整数)。如何在随机行选择中实现这个权重呢?

这并不太难。我没有代码工作,所以我假设你有对象Move与属性Weight在一个数组和所有权重之和为100.0(真的不重要)。现在按权重降序对数组进行排序,在0到99之间选择一个随机数,然后遍历这些随机数,使随机数递减。当它不再为正时你就停下来,选择当前索引/move

var value = rnd.NextDouble()*100.0;
foreach(var move in moves.OrderByDescending(m => m.Weight))
{
   value -= move.Weight;
   if (value <= 0) return move;
}

当然,你可以缓存排序,甚至选择到一个大数组中,并使用随机索引(为了性能),但我希望原则应该清楚。

正如George建议的那样——这里有一个版本,你可以放弃假设权重之和为100:

double _weightSum;
...
// initialize the Sum somewhere
_weightSum = moves.SumBy(m => m.Weight);
Move GetRandomMove()
{
    var value = rnd.NextDouble()*weightSum;
    foreach(var move in moves.OrderByDescending(m => m.Weight))
    {
       value -= move.Weight;
       if (value <= 0) return move;
    }
}

一些代码将有助于我确切地了解您需要什么,但我建议使用Random . net库函数。一些文档可以在这里找到:

http://msdn.microsoft.com/en-us/library/system.random.aspx

本例生成5个随机整数

Random rand = new Random();
Console.WriteLine("Five random integer values:");
for (int ctr = 0; ctr <= 4; ctr++)
   Console.Write("{0,15:N0}", rand.Next());
Console.WriteLine();

这将与当前时间种子,使其"更随机"。如果需要可重复的测试,可以在测试时使用常量作为种子。

将每个可能移动的总权重相加

每一个除以总数,所以你已经将范围归一化为0..1.

获取该范围内的随机数。为每次移动选择一致的顺序,并选择随机数在其中的顺序。

我想做和Carsten基本相同的事情,但是用Linq。

给定的步数是步数的集合,每个步数的权重都为

public Move PickRandomMove()
{
    var allMovesWeight = moves.Sum(m => m.Weight);
    // pick a unit of weight at random, then shift it along by the weight of the 
    // first move so that there will always be an element in the TakeWhile results
    var randomPick = new Random().Next(0, allMovesWeight) +  moves.First().Weight;
    return moves.TakeWhile(move => (randomPick -= move.Weight) > 0).Last(); 
}

我怀疑有一个更清晰的方式来表达如何TakeWhile是工作的,但希望你得到的想法

最新更新