1

我正在尝试为我编写一个玩骰子游戏(普通 6 面骰子)的短程序。第一卷的数字被添加到分数中。第一次掷出后,如果我掷出 6,则游戏停止并记录分数(不加 6)。如果第一次掷出 6,那很好,它可以像任何其他数字 1 到 5 一样添加。我正在尝试运行这个游戏的一系列迭代,这样我就有一长串的得分前半身像(a胸围是滚动的 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;
}

}
4

3 回答 3

2

你得到13,因为那是正确的结果。一点数学:如果S是代表任何一场比赛得分的随机变量,那么你可以考虑 的概率生成函数 f(z)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

这需要一些思考或熟悉这种结构:右侧的左侧项考虑了在简单的 2 卷游戏中获得 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 + ...

(我用Pari/GP来得到这个。)

那么的系数z^k描述了游戏价值为 的概率k;因此,得分为 1 的概率为 36 分之一,获得 2 的概率为 216 分之 7,以此类推。前 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 的随机数生成存在任何弱点。

于 2011-09-04T19:27:39.543 回答
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;
  }
}
于 2011-09-04T07:04:58.947 回答
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());
  }

}
于 2011-09-04T07:11:53.517 回答