سؤال

بالنسبة للعبة، أحاول تحديد التكرار الذي سيظهر فيه # معين عند عدد معين من النرد الذي يتم رميه.أنا أعرف...هذا السؤال يبدو غريبا.اسمحوا لي أن أحاول شرح ذلك بالأرقام الحقيقية.

لذلك، بالنسبة لنرد واحد، سيكون تكرار كل رقم متطابقًا.ستظهر الأرقام من 1 إلى 6 عددًا متساويًا من المرات.

الآن بالنسبة لنردين، تصبح الأمور مختلفة.أتصور أن 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 تنظيم مثل [رئيسي، تردد].

تعديل : في لمعلوماتك، بعد تشغيل هذا، فإنه يدل على الترددات ل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 + 1 أو 2، لذلك ترددها 2/36 = 1/18. 4 = 1 + 3، 2 + 2، أو 3 + 1، لذلك ترددها 3/36 = 1/12.

ويمكنك أن تفعل بقية إلى اثني عشر.

وأي لاعب النرد يعرف جيدا هذه.

وليس هناك "خوارزمية" حقيقية أو محاكاة اللازمة - انها عملية حسابية بسيطة على أساس صيغة التي يجنيها دي 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))

وهذا الرمز 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

وهناك الكثير من الاشياء على الانترنت حول احتمال الزهر. وهنا وصلة واحدة أن ساعدتني مع سؤال مشروع أويلر:

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

وfactoid أنيق ...

هل تعلم أن مثلث باسكال هو التوزيع الاحتمالي للمبالغ 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] منذ لفة الأولى من يموت هو حدث مستقل عن لفة الثانية من يموت وكلا منهم لديهم احتمال متساو من 1- 6 من تتدحرج.

وهناك نداء معينة لذلك. ولكن هذا غير صحيح ... لأن لفة الأولى يؤثر على فرص. يمكن ربما الأكثر بسهولة أن يتم التفكير من خلال مثال.

ويقول أنا أحاول معرفة ما اذا كان من المرجح على اثنين من الزهر احتمال المتداول 2 أو 7. إذا أنا لفة يموت الأول والحصول على 3، ما هي فرصي الآن من تقدم ما مجموعه 7؟ من الواضح، 1 في 6. ما هي فرصي في المتداول ما مجموعه 2؟ 0 في 6 ... لأنه لا يوجد شيء أستطيع لفة على الموت الثاني ليكون مجموع بلدي 2.

لهذا السبب، 7 جدا (أكثر) من المرجح أن يكون لففت ... لأنه لا يهم ما أنا لفة على الموت الأول، لا يزال يمكنني أن تصل إلى ما مجموعه الصحيح من قبل المتداول العدد الصحيح على الموت الثاني. 6 و 8 تتساوى أقل قليلا من المرجح و 5 و 9 أكثر من ذلك، وهلم جرا، حتى نصل إلى 2 و 12، من غير المرجح على قدم المساواة في 1 في 36 فرصة لكل منهما.

إذا كنت مؤامرة هذا (المبلغ مقابل يكيليهود) ستحصل على منحنى الجرس لطيفة (أو بتعبير أدق، وهو ممتلئ الجسم aproximation واحد بسبب طبيعة منفصلة من تجربتك).

وبعد الكثير من البحث على شبكة الإنترنت وستاكوفيرفلوو، وجدت الدكتور الرياضيات يفسر ذلك أيضا في وظيفة عمل (وصلة في جواب آخر لديه صيغة غير صحيحة). I تحويل صيغة الدكتور الرياضيات ل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