想想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个对象位于单元格的单元格中三个细胞的距离,等等。下图说明了此示例:
现在的任务是根据此数组中的值计算将新对象置于x / y的可能性。算法应该是这样的:
min
更近,则概率必须为0.0 max
的距离内,则概率必须为1.0 换句话说:如果至少有一个游戏对象已经非常接近,我们就不想要一个新对象了。另一方面,如果最大半径内没有对象,我们在任何情况下都需要一个新对象。或者我们希望放置一个具有概率的新对象,具体取决于接近x / y的其他对象的数量 - 接近的对象越多,它们越接近,我们想要放置新对象的可能性就越小。
我希望我的描述是可以理解的 你能想出一个计算这个概率的优选算法或公式吗?
PS:对不起这个问题的标题,我不知道如何更好地总结我的问题。
答案 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]
上,但是否则它可以朝向您想要的任何目标(见插图),例如:
如果您想尝试各种目标(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())