我正在制作一个游戏,其中有人打开胸部,胸部会给他们一个随机奖品。我可以给出的最大值是10,000个箱子中的85,000,000,平均值是8,500,但是我想要一些,所以一些箱子将低于这个值以上,并且能够设置最小损失2,500和最大赢取250,000但仍然得到总价值85,000,000。
我真的很难用我的C#知识为此想出一个算法。
答案 0 :(得分:1)
伪代码算法:
现在尝试在C#中实现它。
答案 1 :(得分:1)
这里有一些OOP。你有Player
课程。其中存储了一些信息 - 他拥有的金额,待开的箱子以及他将要找到的箱子中的金币总量。
public class Player
{
private int gold = 0;
private int goldLeftInChests = 85000000;
private int chestsToOpen = 10000;
private Random random = new Random();
public void OpenChest()
{
if (chestsToOpen == 0)
return; // or whatever you want after 10000 chests.
int goldInChest = CalculateGoldInNextChest();
goldLeftInChests -= goldInChest;
chestsToOpen--;
gold += goldInChest;
}
private int CalculateGoldInNextChest()
{
if (chestsToOpen == 1)
return goldLeftInChests;
var average = goldLeftInChests / chestsToOpen;
return random.Next(average);
}
}
当下一个胸部被打开时,计算胸部的金币并调整玩家数据 - 我们向玩家添加一些金币并减少胸部的金币总量,然后将箱子打开。
计算胸部的黄金非常简单。我们得到平均金额并计算1到平均值之间的数字。第一次这个值总是低于8500.但是下一次平均值会稍微大一些。所以玩家将有机会找到超过8500.如果他再次不走运,平均值将会增长。或者如果palyer获得大量黄金,它将会减少。
更新:正如@Hans指出的那样,我没有计算箱子里金币的最小和最大限制。在@Hans解决方案中也存在一个问题 - 您应该在10000个箱子之间移动黄金很多时间以获得接近250000值的一些箱子。而且你必须填写并保留所有10000个值。我想到的下一个问题是.NET中的随机数字分布。值在我们使用的所有间隔上具有相等的概率。因此,如果我们从2500到250000产生价值,那么我们将获得8500(平均值)的价值的机会就像是12000(8500±6000)对比235500(250000-12000-2500)。这意味着从给定范围生成默认随机数将在开始时为您提供大量数字,然后您将保持在最低边界附近(2500)。所以你需要具有不同分布的随机数 - Gaussian variables。我们仍然希望8500金具有最高概率,而250000具有最低概率。这样的事情:
最后一部分 - 计算。我们只需要更新一种方法:)
private int CalculateGoldInNextChest()
{
const int mean = 8500;
var goldPerChestRange = new Range(2500, 250000);
var averageRange = new Range(mean - 2500, mean + 2500);
if (chestsToOpen == 1)
return goldLeftInChests;
do
{
int goldInChest = (int)random.NextGaussian(mu: mean, sigma: 50000);
int averageLeft = (goldLeftInChests - goldInChest) / (chestsToOpen - 1);
if (goldPerChestRange.Contains(goldInChest) && averageRange.Contains(averageLeft))
return goldInChest;
}
while (true);
}
注意:我使用range来使代码更具可读性。多次运行测试会产生超过200000的最佳值。
答案 2 :(得分:0)
这应该是一个很好的起点。每个胸部随机填充限制,以确保剩余的胸部也可以获得有效值。
Random rand = new Random();
int[] chests = new int[numOffChests];
int remaining = TotalValue;
for(int i = 0; i < numOffChests; i++)
{
int minB = Math.Max(remaining / (numOffChests - i), maxChestValue);
int maxB = Math.Min(remaining - (numOffChests - i * minChestValue), maxChestValue);
int val = rand.Next(minB, maxB);
remaining -= val;
chests[i] = val;
}
答案 3 :(得分:0)
分布必须严重偏离以获得具有该平均值的那个值范围。尝试使用指数公式X=exp(a*U+b)+c
,其中U
在[0,1]
上统一。那么条件是
-2,500 = exp(b)+c
250,000 = exp(a+b)+c
8,500 = integral(exp(a*u+b), u=0..1)
= exp(b)/a*(exp(a)-1)+c
= 252,500/a+c
给出了两个方程式
250,000+2,500*exp(a) = c*(1-exp(a))
8,500 = 252,500/a+c
一些图形和数字解决方案给出了#34;魔法&#34;数字
a = 22.954545,
b = -10.515379,
c = -2500.00002711621
现在根据该公式填充10,000个箱子,计算胸部价格的总和,并以任何你喜欢的模式分配,概率很小。
如果要更频繁地命中上限和下限,请在计算基础上增加界限,如果超出原始界限则剪切计算值。
答案 4 :(得分:0)
我假设概率函数给出了赢/输值V出现的机会。假设V的概率与(250000-V)** 2成正比,从而获得较高奖励的机会较少。
为了简化一些舍入问题,我们还假设输赢是100的倍数。然后您可以进行以下(未经测试的)计算:
int minwin = -2500 ;
int maxwin = 250000;
int chestcount = 10000;
int maxamount = 85000;
// ----------- get probabilities for each win/lose amount to occur in all chests ----------
long probtotal = 0 ;
List<long> prob = new List<long> ;
for (long i=minwin;i<=maxwin;i++) if (i%100==0)
{ long ii=(maxwin-i)*(maxwin-i) ; prob.Add((float)ii) ; probtotal+=ii ; }
for (int i=0;i<prob.Count;i++) prob[i]=prob[i]/(probtotal) ;
for (int i=0;i<prob.Count;i++)
Console.writeLine("Win/lose amount"+((i-minwin)*100).ToString()+" probability="+(proba[i]*100).ToString("0.000")) ;
// Transform "prob" so as to indicate the float count of chest corresponding to each win/lose amount
for (int i=0;i<prob.Count;i++) prob[i]=prob[i]*chestcount ;
// ---------- Set the 10000 chest values starting from the highest win -------------
int chestindex=0 ;
List<int> chestvalues = new List<int>();
float remainder = 0 ;
int totalwin=0 ;
for (int i=0;i<prob.Count;i++)
{
int n = (int)(prob[i]+remainder) ; // only the integer part of the float ;
remainder = prob[i]+remainder-n ;
// set to n chests the win/lose amount
int curwin=(i-minwin)*100 ;
for (int j=0;j<n && chestvalues.count<chestcount;j++) chestvalues.Add(curwin) ;
totalwin+=curwin ;
}
// if stvalues.count lower than chestcount, create missing chestvalues
for (int i=chestvalues.Count;i<chestcount;i++) chestvalues.Add(0) ;
// --------------- due to float computations, we perhaps want to make some adjustments --------------
// i.e. if totalwin>maxamount (not sure if it may happen), decrease some chestvalues
...
// --------------- We have now a list of 10000 chest values to be randomly sorted --------------
Random rnd = new Random();
SortedList<int,int> randomchestvalues = new SortedList<int,int>() ;
for (int i=0;i<chestcount;i++) randomchestvalues.Add(rnd.Next(0,99999999),chestvalues[i]) ;
// display the first chests amounts
for (int i=0;i<chestcount;i++) if (i<234)
{ int chestamount = randomchestvalues.GetByIndex(i) ; Console.WriteLine(i.ToString()+":"+chestamount) ; }
}