对于游戏,我正在尝试确定某个#将在给定的掷骰子#上显示的频率。我知道......这个问题似乎很奇怪。让我试着用实数来解释它。
因此,对于1个芯片,每个数字的频率将是相同的。 1-6将显示相同的次数。
现在有2个骰子,情况会有所不同。我想5,6,7将是最频繁滚动的,而频谱两端的数字将显示较少或根本不显示(在1的情况下)。我想知道如何计算这个列表并以正确的顺序显示它们,从最常见到较不频繁。
有什么想法吗?
@duffymo - 虽然有一些算法来提出它会非常好。似乎上述方式需要大量的手工采摘和数字放置。如果我的死亡数量是动态的,可以说是10,那么我认为手工操作将是无效的和麻烦的。 :)
答案 0 :(得分:11)
两个骰子有6 * 6 = 36种组合。
2 = 1 + 1只能出现一次,因此其频率为1/36。 3 = 1 + 2或2 + 1,因此其频率为2/36 = 1/18。 4 = 1 + 3,2 + 2或3 + 1,因此其频率为3/36 = 1/12。
你可以休息十二点。
任何步步高玩家都清楚这些。
答案 1 :(得分:5)
没有必要使用真正的“算法”或模拟 - 这是基于De Moivre推导出的公式的简单计算:
http://www.mathpages.com/home/kmath093.htm
这不是“钟形曲线”或正态分布。
答案 2 :(得分:3)
粗略草案的递归方式:
public static IEnumerable<KeyValuePair<int, int>> GetFrequenciesByOutcome(int nDice, int nSides)
{
int maxOutcome = (nDice * nSides);
Dictionary<int, int> outcomeCounts = new Dictionary<int, int>();
for(int i = 0; i <= maxOutcome; i++)
outcomeCounts[i] = 0;
foreach(int possibleOutcome in GetAllOutcomes(0, nDice, nSides))
outcomeCounts[possibleOutcome] = outcomeCounts[possibleOutcome] + 1;
return outcomeCounts.Where(kvp => kvp.Value > 0);
}
private static IEnumerable<int> GetAllOutcomes(int currentTotal, int nDice, int nSides)
{
if (nDice == 0) yield return currentTotal;
else
{
for (int i = 1; i <= nSides; i++)
foreach(int outcome in GetAllOutcomes(currentTotal + i, nDice - 1, nSides))
yield return outcome;
}
}
除非我弄错了,否则这应该像[key,frequency]那样吐出KeyValuePairs。
编辑:仅供参考,运行此功能后,它会显示GetFrequenciesByOutcome(2,6)的频率为:
2:1
3:2
4:3
5:4
6:5
7:6
8:5
9:4
10:3
11:2
12:1
答案 3 :(得分:3)
通过移动它的位置来添加先前滚动的频率数组,“边数”,然后您将获得每个数字显示的频率数组。
1, 1, 1, 1, 1, 1 # 6 sides, 1 roll
1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1
+ 1, 1, 1, 1, 1, 1
_______________________________
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 # 6 sides, 2 rolls
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
+ 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1
______________________________________________
1, 3, 6,10,15,21,25,27,27,25,21,15,10, 6, 3, 1 # 6 sides, 3 rolls
这比蛮力模拟要快得多,因为简单的方程是最好的。 这是我的python3实现。
def dice_frequency(sides:int, rolls:int) -> list:
if rolls == 1:
return [1]*sides
prev = dice_frequency(sides, rolls-1)
return [sum(prev[i-j] for j in range(sides) if 0 <= i-j < len(prev))
for i in range(rolls*(sides-1)+1)]
例如,
dice_frequency(6,1) == [1, 1, 1, 1, 1, 1]
dice_frequency(6,2) == [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]
dice_frequency(6,3) == [1, 3, 6, 10, 15, 21, 25, 27, 27, 25, 21, 15, 10, 6, 3, 1]
请注意,您应该使用“目标号码 - 滚动计数”作为列表的索引来获取每个号码的频率。如果您想获得概率,请使用“side number”^'roll count'作为分母。
sides = 6
rolls = 3
freq = dice_frequency(sides,rolls)
freq_sum = sides**rolls
for target in range(rolls,rolls*sides+1):
index = target-rolls
if 0 <= index < len(freq):
print("%2d : %2d, %f" % (target, freq[index], freq[index]/freq_sum))
else:
print("%2d : %2d, %f" % (target, 0, 0.0))
此代码yeilds
3 : 1, 0.004630
4 : 3, 0.013889
5 : 6, 0.027778
6 : 10, 0.046296
7 : 15, 0.069444
8 : 21, 0.097222
9 : 25, 0.115741
10 : 27, 0.125000
11 : 27, 0.125000
12 : 25, 0.115741
13 : 21, 0.097222
14 : 15, 0.069444
15 : 10, 0.046296
16 : 6, 0.027778
17 : 3, 0.013889
18 : 1, 0.004630
答案 4 :(得分:2)
网上有很多关于骰子概率的东西。这是一个帮助我解决项目欧拉问题的链接:
答案 5 :(得分:1)
使用动态函数创建的JavaScript实现:
<script>
var f;
function prob(dice, value)
{
var f_s = 'f = function(dice, value) {var occur = 0; var a = [];';
for (x = 0; x < dice; x++)
{
f_s += 'for (a[' + x + '] = 1; a[' + x + '] <= 6; a[' + x + ']++) {';
}
f_s += 'if (eval(a.join(\'+\')) == value) {occur++;}';
for (x = 0; x < dice; x++)
{
f_s += '}';
}
f_s += 'return occur;}';
eval(f_s);
var occ = f(dice, value);
return [occ, occ + '/' + Math.pow(6, dice), occ / Math.pow(6, dice)];
};
alert(prob(2, 12)); // 2 die, seeking 12
// returns array [1, 1/36, 0.027777777777777776]
</script>
编辑:相当失望没有人指出这一点;必须将6 * dice
替换为Math.pow(6, dice)
。没有更多的错误......
答案 6 :(得分:1)
整洁的事实......
你知道Pascal的三角形是N双面骰子总和的概率分布吗?
1 1 - 1 die, 1 chance at 1, 1 chance at 2
1 2 1 - 2 dice, 1 chance at 2, 2 chances at 3, 1 chance at 4
1 3 3 1 - 3 dice, 1 chance at 3, 3 chances at 4, 3 chances at 5, 1 chance at 6
1 4 6 4 1 - etc.
答案 7 :(得分:0)
似乎有一些神秘的确切围绕“为什么”这是,虽然duffymo已经解释了其中的一部分,但我正在看另一篇帖子说:
应该没有理由为什么5,6和7应该滚动得多[超过2],因为骰子的第一次滚动是来自第二次骰子滚动的独立事件,并且它们都具有相同的概率1- 6被卷起。
对此有一定的吸引力。但这是不正确的......因为第一次滚动会影响机会。推理可能最容易通过一个例子来完成。
说我想弄清楚两个骰子上掷2或7的概率是否更有可能。如果我掷出第一个骰子并获得3,那么我现在有多少机会滚动7个?显然,1比6。我总共2次滚动的几率是多少? 6比0 ...因为没有什么我可以在第二个骰子上滚动以使我的总数为2。
出于这个原因,7非常(最有可能)被卷起......因为无论我在第一个模具上滚动什么,我仍然可以通过在第二个模具上滚动正确的数字来达到正确的总数。 6和8同样略有可能,5和9更不可能,依此类推,直到我们达到2和12,同样不太可能在每36个机会中有1个。
如果你绘制这个(总和与可能性),你会得到一个很好的钟形曲线(或者更确切地说,由于你的实验的离散性,它会产生一个块状的近似)。
答案 8 :(得分:0)
经过大量的互联网搜索和stackoverflow搜索后,我发现Dr. Math在工作函数中解释得很好(另一个答案中的链接的公式不正确)。我把Math博士的公式转换为C#,我的nUnit测试(之前在代码中的其他尝试都失败了)全部通过了。
首先,我必须编写一些辅助函数:
public static int Factorial(this int x)
{
if (x < 0)
{
throw new ArgumentOutOfRangeException("Factorial is undefined on negative numbers");
}
return x <= 1 ? 1 : x * (x-1).Factorial();
}
由于选择数学的方式,我意识到如果我有一个具有下限的重载因子函数,我可以减少计算。达到下限时,此功能可以纾困。
public static int Factorial(this int x, int lower)
{
if (x < 0)
{
throw new ArgumentOutOfRangeException("Factorial is undefined on negative numbers");
}
if ((x <= 1) || (x <= lower))
{
return 1;
}
else
{
return x * (x - 1).Factorial(lower);
}
}
public static int Choose(this int n, int r)
{
return (int)((double)(n.Factorial(Math.Max(n - r, r))) / ((Math.Min(n - r, r)).Factorial()));
}
当这些已经到位时,我能够写出
public static int WaysToGivenSum(int total, int numDice, int sides)
{
int ways = 0;
int upper = (total - numDice) / sides; //we stop on the largest integer less than or equal to this
for (int r = 0; r <= upper; r++)
{
int posNeg = Convert.ToInt32(Math.Pow(-1.0, r)); //even times through the loop are added while odd times through are subtracted
int top = total - (r * sides) - 1;
ways += (posNeg * numDice.Choose(r) * top.Choose(numDice - 1));
}
return ways;
}