문제

게임의 경우 특정 #이 주어진 주사위에 표시되는 주파수가 표시되는 주파수를 결정하려고합니다. 알아요 ... 그 질문은 이상해 보입니다. 실수로 설명해 드리겠습니다.

따라서 1 다이의 경우 각 숫자의 주파수가 동일합니다. 1-6은 같은 횟수로 나타납니다.

이제 2 개의 주사위의 경우 상황이 다릅니다. 나는 5,6,7이 가장 자주 롤링 될 것이라고 생각하는 반면, 스펙트럼의 양쪽 끝에있는 숫자는 덜 나타나지 않을 것입니다 (1의 경우). 이 목록을 계산하고 가장 빈번한 곳에서 덜 빈번한 순서로 보여주는 방법을 알고 싶습니다.

이견있는 사람?


@duffymo- 알고리즘을 만들어내는 것은 정말 좋을 것입니다. 위의 길은 숫자의 많은 손을 따고 배치해야 할 것 같습니다. 내 다이 카운트가 10까지 역동적이라면, 손으로 그 일을하는 것은 비효율적이고 번거 롭습니다. :)

도움이 되었습니까?

해결책

재귀적인 방법의 대략적인 초안 :

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;
    }
}

내가 착각하지 않는 한, 이것은 [키, 주파수]처럼 구성된 keyvaluepairs를 뱉어야합니다.

편집하다: fyi, 이것을 실행 한 후, 그것은 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

다른 팁

두 주사위에는 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입니다.

나머지는 12 시로 할 수 있습니다.

모든 Backgammon 플레이어는 이것을 잘 알고 있습니다.

실제 "알고리즘"또는 시뮬레이션이 필요하지 않습니다. De Moivre가 도출 한 공식을 기반으로 간단한 계산입니다.

http://www.mathpages.com/home/kmath093.htm

그리고 "벨 곡선"또는 정규 분포가 아닙니다.

위치를 이동하여 이전 롤의 주파수 배열을 추가하면 각 숫자가 표시되는 주파수 배열을 얻게됩니다.

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]

각 숫자의 빈도를 얻기 위해 '대상 번호 - 롤 카운트'를 목록의 색인으로 사용해야합니다. 확률을 얻으려면 '측면 번호'^'롤 카운트'를 분모로 사용하십시오.

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))

이 코드는 예를 들었다

 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

주사위 확률에 대한 온라인에서 많은 것들이 있습니다. 다음은 프로젝트 Euler 질문으로 저를 도와 준 링크입니다.

http://gwydir.demon.co.uk/jo/probability/calcdice.htm

깔끔한 사실 ...

Pascal의 삼각형이 N 2 측 주사위의 합의 확률 분포라는 것을 알고 있습니까?

   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.

동적 함수 생성을 사용한 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). 더 이상 그런 실수가 없습니다 ...

정확히 "왜"라는 신비가있는 것 같고, Duffymo는 그 일부를 설명했지만 다른 게시물을보고 있습니다.

다이의 첫 번째 롤이 다이의 두 번째 롤에서 독립적 인 사건이기 때문에 5, 6 및 7이 더 많이 굴려야하는 이유는 없어 롤.

이것에 대한 호소가 있습니다. 그러나 첫 번째 롤이 기회에 영향을 미치기 때문에 잘못되었습니다. 추론은 아마도 예를 통해 가장 쉽게 수행 될 수 있습니다.

롤링 2 또는 7의 확률이 두 주사위에있을 가능성이 더 높는지 알아 내려고한다고 가정 해 봅시다. 첫 번째 다이를 굴리고 3을 얻는다면, 지금 총 7 명을 굴릴 기회는 무엇입니까? 분명히, 1 in 6. 총 2 명을 굴릴 기회는 무엇입니까? 0 6에서 0 ... 아무것도 없기 때문에 두 번째 다이를 굴릴 수있는 것이 없기 때문에 총 2 명을 두십시오.

이런 이유로, 7은 매우 (가장) 롤링 될 가능성이 높습니다. 첫 번째 다이에서 무엇을 굴려도 두 번째 다이에서 올바른 숫자를 굴려 올바른 총계에 도달 할 수 있기 때문입니다. 6과 8은 2와 12에 도달 할 때까지 36 개 기회 중 1 명 중 1 명에 도달 할 가능성이 약간 낮습니다.

당신이 이것 (합당 대 가능성)을 그릴 경우 (합당 대 가능성) 멋진 벨 곡선 (또는 더 정확하게는 실험의 불연속 특성으로 인해 하나의 차단 된 aproximation)을 얻을 수 있습니다.

인터넷과 stackoverflow에서 많은 검색을 한 후 박사 수학 작업 기능에서 잘 설명합니다 (다른 답변의 링크에는 잘못된 공식이 있습니다). Dr. 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;
  }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top