我正在尝试为我编写一个简短的程序来玩骰子游戏(正常的6面骰子)。第一个卷号将添加到乐谱中。在第一次滚动之后,如果我滚动6,则游戏停止并记录得分(不添加6)。如果在第一个掷骰子上滚动6,那很好,并且它像任何其他数字1到5一样被添加。我试图运行这个游戏的一堆迭代,这样我有很长的分数列表(胸围被卷起6)。我将这些分数重新排列为从最小到最大的顺序,然后找到列表的中位数,这是最佳停止的分数。
由于某些原因,我在运行程序时一直保持13,但我知道答案应该是15.在Java中使用Random会对中位数产生某种影响吗?我不完全知道Random如何生成数字以及它是否以平等机会创建它们。还有,那些弹出的东西应该不起作用吗?
import java.util.*;
public class DiceRoller {
private static Random r = new Random();
private static final int games = 10001;
private static int[] totalScores = new int[games];
private static int index = 0;
public static void main(String[] args) {
int score = 0; boolean firstRoll = true;
while (index < games) {
int roll = roll();
if (firstRoll) {
score += roll;
firstRoll = false;
} else {
if (roll == 6) {
totalScores[index] = score;
index++;
score = 0; firstRoll = true;
} else {
score += roll;
}
}
}
System.out.println("The median is " + median() + ".");
}
public static int roll() {
return r.nextInt(6) + 1;
}
public static int median() {
Arrays.sort(totalScores);
int temp = totalScores[games / 2];
return temp;
}
}
答案 0 :(得分:2)
你得到13
,因为这是正确的结果。一点点数学:如果S
是表示其中任何一个游戏得分的随机变量,那么您可以考虑f(z)
的{{3}} S
。根据游戏的描述,该概率生成函数满足等式:
f(z) = (z + z^2 + z^3 + z^4 + z^5 + z^6) / 36 + f(z)(z + z^2 + z^3 + z^4 + z^5) / 6
这需要一些思考,或熟悉这种结构:右侧的左手术语考虑了在简单的双掷游戏中获得1到6的概率;涉及f(z)的右手术语考虑了涉及3个或更多卷的游戏,用最终的前6卷(必须在1到5的范围内)和前面的卷表示它们,其概率我们可以再次使用f
递归表达。
无论如何,在达到这个目标之后,我们可以重新排列以将f
描述为z
的合理函数,然后展开为幂级数,开始:
f(z) = 1/36*z + 7/216*z^2 + 49/1296*z^3 + 343/7776*z^4 + 2401/46656*z^5 + 16807/279936*z^6 + 63217/1679616*z^7 + 388087/10077696*z^8 + 2335585/60466176*z^9 + 13681927/362797056*z^10 + 77103313/2176782336*z^11 + 409031959/13060694016*z^12 + 2371648321/78364164096*z^13 + 13583773735/470184984576*z^14 + ...
(我使用Probability generating function来获取此信息。)
系数z^k
则描述游戏价值为k
的概率;因此,得分为1的概率为1/36,得分为2的概率为216,依此类推。前12个系数的总和是0.472828864487196328...
,而前13个系数的总和是0.5030933144224321950968...
。所以中位数确实是13。
为了提供一个独立的检查,我写了一个快速的Python程序:
from __future__ import division
import random
def roll():
return random.randint(1, 6)
def play():
score = roll()
while True:
throw = roll()
if throw == 6:
break
score += throw
return score
all_scores = sorted(play() for _ in xrange(1000001))
print "median is: ",all_scores[len(all_scores) // 2]
print "fraction of scores <= 12: ",all_scores.index(13) / len(all_scores)
print "fraction of scores <= 13: ",all_scores.index(14) / len(all_scores)
果然,结果如下:
iwasawa:~ mdickinson$ python dice_game.py
median is: 13
fraction of scores <= 12: 0.472811527188
fraction of scores <= 13: 0.502863497137
所以为了回答你的问题,你所看到的结果并不是Java随机数生成中任何弱点的证据。
答案 1 :(得分:1)
随机并非完全随机且存在一些缺陷。但是对于这个用例,您不太可能注意到这种差异。您可以假设每个值1到6的可能性相同。
为了比较,这里是另一种解决方案,它计算总数的出现次数而不是记录每个值。正如你所看到的,即使你有1000多个游戏,这也表现良好。当您有少量结果和大量重复时,这种方法效果最佳。它是自然分类的。
import java.util.Random;
public class DiceRoller {
private static final int MAX_VALUE = 300; // assume at most this total
private static final int GAMES = 10000001;
public static void main(String... args) {
int[] count = new int[MAX_VALUE];
Random rand = new Random();
for (int i = 0; i < GAMES; i++)
count[totalScore(rand)]++;
System.out.println("The median is " + median(count, GAMES) + ".");
}
private static int median(int[] count, int games) {
int findTotal = games/2;
for (int i = 0; i < count.length; i++) {
findTotal -= count[i];
if (findTotal <= 0) return i;
}
throw new AssertionError();
}
private static int totalScore(Random rand) {
int total = rand.nextInt(6) + 1;
for(int n;(n = rand.nextInt(6) + 1) != 6;)
total += n;
return total;
}
}
答案 2 :(得分:0)
以下是一些显示结果分布的代码。它并没有真正回答这个问题,但也许它可以帮助你进行研究。
package so7297660;
import java.util.Random;
public class DiceRoller {
private static final int N = 10000000;
private static final Random r = new Random();
private static final int[] result = new int[100];
public static int roll() {
return r.nextInt(6) + 1;
}
private static int singleGame() {
int score = roll();
while (true) {
int roll = roll();
if (roll == 6) {
return score;
} else {
score += roll;
}
}
}
private static int median() {
int n = 0;
for (int i = 0; i < result.length; i++) {
if (n + result[i] >= N / 2) {
return i;
}
n += result[i];
}
throw new IllegalStateException();
}
public static void main(String[] args) {
for (int i = 0; i < N; i++) {
int score = singleGame();
int index = Math.min(score, result.length - 1);
result[index]++;
}
for (int i = 0; i < result.length; i++) {
System.out.println(i + "\t" + result[i]);
}
System.out.println("median\t" + median());
}
}