计算具有最小/最大边界的范围内的概率值

时间:2014-05-28 12:39:47

标签: algorithm

想想2D网格,例如大小为1000x1000个单元格,用作游戏中关卡的地图。此映射在运行时期间动态填充游戏对象。现在我们需要计算将新对象放入此网格中给定x / y位置的概率。

我已经拥有的是一个int数组,它以x / y的形式保存与单元格距离很近的游戏对象的数量。此数组的索引表示到给定单元格的单元格距离,并且数组中的每个值都表示该距离处网格中的游戏对象数。例如,数组可能如下所示:

0, 0, 1, 2, 0, 3, 1, 0, 4, 0, 1

这意味着0个对象位于x / y本身的网格单元格中,0个对象位于直接相邻单元格中,1个对象位于距离为2个单元格的单元格中,2个对象位于单元格的单元格中三个细胞的距离,等等。下图说明了此示例:

enter image description here

现在的任务是根据此数组中的值计算将新对象置于x / y的可能性。算法应该是这样的:

  • 如果至少有一个对象已经比min更近,则概率必须为0.0
  • 如果没有对象在max的距离内,则概率必须为1.0
  • 否则概率取决于接近x / y的对象数量以及数量。

换句话说:如果至少有一个游戏对象已经非常接近,我们就不想要一个新对象了。另一方面,如果最大半径内没有对象,我们在任何情况下都需要一个新对象。或者我们希望放置一个具有概率的新对象,具体取决于接近x / y的其他对象的数量 - 接近的对象越多,它们越接近,我们想要放置新对象的可能性就越小。

我希望我的描述是可以理解的 你能想出一个计算这个概率的优选算法或公式吗?

PS:对不起这个问题的标题,我不知道如何更好地总结我的问题。

5 个答案:

答案 0 :(得分:3)

我考虑的一种方法是计算人口密度"为那个广场。人口密度越低,将物品放在那里的概率就越高。

正如您所说,如果(x,y)处有商品,则您无法在此处放置商品。因此,考虑人口密度为1.0。

在下一个级别,有8个可能的邻居。该级别的人口密度为n/8,其中n是该级别的项目数。因此,如果有3个对象与(x,y)相邻,则该级别的密度为3/8。除以(distance+1)

对所有级别执行相同操作。也就是说,计算每个级别的密度,除以(distance+1),并对结果求和。每个级别的除数为(distance*8)。所以你的除数是8,16,24等。

计算结果后,您可能希望稍微调整数字来调整概率。也就是说,如果你拿出0.5的总和,那个空间可能会非常拥挤。您不希望使用(1-density)作为生成项目的概率。但是我上面概述的方法应该给你一个数字,这可以简化问题。

所以算法看起来像:

total_density = 0;
for i = 0; i < max; ++i
    if (i == 0)
        local_density = counts[i]
    else
        local_density = counts[i]/(i*8);  // density at that level
    total_density = total_density + (local_density/(i+1))

如果将局部密度除以(i+1)过度夸大距离的影响,请考虑使用log(i+1)sqrt(i+1)之类的内容。我发现在距离是一个因素但不是线性的其他情况下有用。

答案 1 :(得分:2)

假设您的数组名称是距离。

double getProbability()
{
    for(int i=0 ; i<min ; i++)
    {
        if(distances[i]!=0) return 0;
    }

    int s = 0;
    bool b = true;
    for(int i=min ; i<max ; i++)
    {
        b = b && (distances[i]==0)
        s+= distances[i]/(i+1);
    }
    if(b) return 1;

    for(int i=0 ; i<distances.Count() ; i++)
    {
        s+= distances[i]/(i+1);
    }
    else return (float)s/totalObjectNum;
}

答案 2 :(得分:2)

该方法计算距离中的那些对象的加权和&gt; min和&lt; = max。 并行计算上限(称为normWeight),该上限仅取决于最大值

如果至少一个物体在距离上> min和&lt; = max然后 对于外环上的1个对象,最接近1的概率为1-(1 / normWeight)。 最小概率为1 - ((normWeight-1)/ normWeight)。例如。对于 外圈上最多1个物体。

可以通过计算变量delta的不同值来修改加权和的计算。

float calculateProbabilty()
{
    vector<int> numObjects; // [i] := number of objects in a distance i
    fill numObjects ....

    // given:
    int min = ...;
    int max = ...; // must be >= min


    bool anyObjectCloserThanMin = false;
    bool anyObjectCloserThanMax = false;

    // calculate a weighted sum

    float sumOfWeights  = 0.0;
    float normWeight    = 0.0;

    for (int distance=0; distance <= max; distance++)
    {
        // calculate a delta-value for increasing sumOfWeights depending on distance
        // the closer the object the higher the delta
        // e.g.: 
        float delta = (float)(max + 1 - distance);
        normWeight += delta;

        if (numObjects[distance] > 0 && distance < min)
        {
            anyObjectCloserThanMin = true;
            break;
        }

        if (numObjects[distance] > 0)
        {
            anyObjectCloserThanMax = true;
            sumOfWeights += (float)numObjects[distance] * delta;
        }
    }

    float probability = 0.0;

    if (anyObjectCloserThanMin)
    {
        // if at least one object is already closer than min, then the probability must be 0.0
        probability = 0.0;
    }
    else if (!anyObjectCloserThanMax)
    {
        //  if no object is within a distance of max, then the probability must be 1.0
        probability = 1.0;
    }
    else
    {
        // else the probability depends on how many objects are close to x/y

        // in this scenario normWeight defines an upper limited beyond that 
        // the probability becomes 0
        if (sumOfWeights >= normWeight)
        {
            probability = 0.0;
        }
        else
        {
            probability = 1. - (sumOfWeights / normWeight);
            // The probability closest to 1 would be 1-(1/normWeight) for 1 object on the outer ring.
            // The minimal probability would be 1-((normWeight-1)/normWeight). E.g. for
            // max-1 objects on the outer ring.
        }
    }

    return probability;
}

答案 3 :(得分:1)

一个简单的方法可能是:

1 /(加上[min,max]中所有邻居的数量除以它们与x / y + 1的距离加权)。

通过加权,我的意思是那些与x / y的距离较小的邻居的数量乘以一个更大的因子,即那些不那么接近的那些邻居。例如,你可以使用(max + 1)-distance。

答案 4 :(得分:1)

请注意,一旦您计算了对象密度(请参阅&#34; population density&#34;或&#34; weighted sum of those objects in a distance&#34;在之前的答案中),您仍然需要将此值转换为插入新对象的概率(在其他答案中未如此全面地处理)

需要为所有可能的物体密度值定义概率函数(PDF),即在闭合间隔[0, 1]上,但是否则它可以朝向您想要的任何目标(见插图),例如:

  • 将当前对象密度移向所需的最大对象密度
  • 保持插入常数的整体概率,同时考虑本地对象密度

insertion probability density functions

如果您想尝试各种目标(PDF函数形状 - 线性,二次,夸张,圆形部分......),您可能希望查看factory method pattern所以你可以在调用相同的方法名称时在实现之间切换,但我想在我的例子中保持简单,所以我只实现了第一个目标(在python中)

def object_density(objects, min, max):
    # choose your favourite algorithm, e.g.:
    #  Compute the density for each level of distance
    #  and then averages the levels, i.e. distance 2 object is
    #  exactly 8 times less significant from distance 1 object.
    #  Returns float between 0 and 1 (inclusive) for valid inputs.
    levels = [objects[d] / (d * 8) for d in range(min, max + 1)]
    return sum(levels) / len(levels)

def probability_from_density(desired_max_density, density):
    # play with PDF functions, e.g.
    #  a simple linear function
    #   f(x) = a*x + b
    #  where we know 2 points [0, 1] and [desired_max_density, 0], so:
    #      1 = 0 + b
    #      0 = a*desired_max_density + b
    #  Returns float betwen 0 and 1 (inclusive) for valid inputs.
    if density >= desired_max_density:
      return 0.0
    a = -1 / desired_max_density
    b = 1
    return a * density + b

def main():
    # distance 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    objects = [0, 0, 1, 2, 0, 3, 1, 0, 4, 0, 1]
    min = 2
    max = 5
    desired_max_density = 0.1

    if sum(objects[:min]):  # when an object is below min distance
      return 0.0 
    density = object_density(objects, min, max)  # 0,0552
    probability = probability_from_density(desired_max_density, density)  # 0,4479
    return probability

print(main())