【问题标题】:Magic The Gathering Card Draw Probability Function In CC语言中的魔术聚会卡抽奖概率函数
【发布时间】:2017-05-05 23:52:54
【问题描述】:

我目前正在编写一个函数,它会询问您的牌组大小、该牌组中某张特定牌的副本数量、您的初始手牌规模、您调度的牌数量(我们正在设置调度的牌除了抽牌,然后将重新调度的牌洗回),以及你想在哪轮抽到那张牌。

本质上,我将不抽牌的所有概率相乘(然后用 1 减去该概率)来得出在特定回合中抽到特定牌的概率。到目前为止,我的函数如下所示:

void card_probability() {

    int total;
    int numCopies;
    int n;
    int m;
    int turn;
    double initial_draw_prob;
    double mulligan_prob;
    double draw_prob;
    double neg_probability;
    double probability;

    printf("Enter how many total cards there are in the deck: ");
    scanf("%d", &total);

    printf("Enter how many copies of the card that you are looking for are 
    in the deck: ");
    scanf("%d", &numCopies);

    printf("Enter your initial hand size: ");
    scanf("%d", &n);

    printf("Enter how many cards you are mulliganing: ");
    scanf("%d", &m);

    printf("Enter what turn you want to draw the card by: ");
    scanf("%d", &turn);

    initial_draw_prob = ((total - numCopies) / total);

    //for loop{}

    mulligan_prob = ((total - numCopies - n) / (total - n));

    //for loop{}

    draw_prob = ((total - numCopies - n - m) / (total - n - m));

    //for loop{}

    neg_probability = initial_draw_prob * mulligan_prob * draw_prob;
    probability = 1 - neg_probability


    printf("The probability of drawing at least one of the cards by turn %d 
    given you mulliganed %d cards is %lf", turn, m, probability);

}

int main(){
card_probability();

return 0;
}

我在设置这些 for 循环以使其正常工作时遇到问题。基本上发生的是三个不同的概率部分:

1.) 在你的第一手牌中没有抽到想要的牌的概率 (total - numCopies) / (total) 是第一次抽牌时没有抽到那张牌的概率。然后,例如,如果您总共抽了 7 张牌,您将继续将概率相乘,直到得到 (total - numCopies - 7) / (total - 7) 项。

2.) 调度指定金额后不抽牌的概率。

3.) 在指定的回合没有抽到牌的概率。

谁能帮我设置这些 for 循环?我无法得到正确的增量。我在纸上进行了数学计算,牌组大小为 10,我想要 2 张牌,手牌大小为 2,调度 1,选择 3 轮,我有 16.66% 的几率不抽牌 =>大约 83% 的人在第 3 回合抽牌。

【问题讨论】:

  • 为什么你的标题里是C语言,而你的标签里是C++?你用的是哪个?例如,如果您使用 C++,则应使用 std::string 表示文本,使用 std::vector 而不是数组。
  • 我正在使用 C。我已经编辑了标签。感谢您的关注!
  • 更喜欢使用fscanf而不是dangerous scanf
  • @ThomasMatthews - 你的建议有缺陷。 fscanf() 的安全性不亚于scanf()。造成这两种危险的因素与格式字符串和后续参数之间可能的不匹配有关,或者在读取字符串时缓冲区溢出(将多个字符读取到大小不足的缓冲区)。
  • 你的论文计算是incorrect

标签: c


【解决方案1】:

那么,当您查看循环时,为什么不直接减少一个额外的值呢?

所以

int current_total = total;
for( int i = 0; i < opening_hand_size; i++)
{
  prob = prob * (( current_total - num_copies) / current_total) ;
  current_total--;
} 

【讨论】:

    【解决方案2】:

    首先,我们需要一张牌不在n 牌中的概率公式。

    P[Not found after n draws] 
    = (deck_size - num_copies - 0) / (deck_size - 0)
    * (deck_size - num_copies - 1) / (deck_size - 1)
    ...
    * (deck_size - num_copies - (n-2)) / (deck_size - (n-2))
    * (deck_size - num_copies - (n-1)) / (deck_size - (n-1))
    

    在 C 中,可以这样实现:

    unsigned deck_size  = ...;
    unsigned num_copies = ...;
    unsigned num_draws  = ...;
    float p = 1;
    while (num_draws--) {
       p *= (float)(deck_size - num_copies - num_draws) / (float)(deck_size - num_draws);
    }
    

    unsigned deck_size  = ...;
    unsigned num_copies = ...;
    unsigned num_draws  = ...;
    float p = 1;
    while (num_draws--) {
       p *= (float)(deck_size - num_copies) / (float)deck_size;
       --deck_size;
    }
    

    其余的都可以由此构建。

    #include <stdio.h>
    
    float p_not_in(int deck_size, int num_draws, int num_copies) {
       float p = 1;
       while (num_draws--) {
          p *= (float)(deck_size - num_copies) / (float)deck_size;
          --deck_size;
       }
    
       return p;
    }
    
    int main() {
       unsigned deck_size          = ...;
       unsigned max_mulligans      = ...;
       unsigned draw_on_first_turn = ...;  // boolean
       unsigned max_turns          = ...;
       unsigned num_copies         = ...;
    
       float p = 1;
    
       unsigned starting_hand_size = 7;
       unsigned mulligans_taken = 0;
       while (1) {
          p *= p_not_in(deck_size, starting_hand_size, num_copies);
          deck_size -= starting_hand_size;
          printf("Chance found after %u mulligans: %.0f%%\n", mulligans_taken, (1-p)*100);
          if (mulligans_taken == max_mulligans)
             break;
    
          deck_size += starting_hand_size;
          --starting_hand_size;
          ++mulligans_taken;
       }
    
       for (unsigned turn_num = 1; turn_num <= max_turns; ++turn_num) {
          if (turn_num > 1 || draw_on_first_turn) {
             p *= (float)(deck_size - num_copies) / (float)deck_size;
             --deck_size;
          }
    
          printf("Chance found no later than turn %u: %.0f%%\n", turn_num, (1-p)*100);
       }
    
       return 0;
    }
    

    测试:

    unsigned deck_size          = 60;
    unsigned max_mulligans      = 2;
    unsigned draw_on_first_turn = 1;  // boolean
    unsigned max_turns          = 3;
    unsigned num_copies         = 4;
    

    输出:

    $ gcc -Wall -Wextra -pedantic -std=c99 -o prob prob.c && prob
    Chance found after 0 mulligans: 40%
    Chance found after 1 mulligans: 61%
    Chance found after 2 mulligans: 73%
    Chance found no later than turn 1: 75%
    Chance found no later than turn 2: 77%
    Chance found no later than turn 3: 78%
    

    让我们通过实验得到结果来验证:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use List::Util qw( shuffle );
    
    {
       my $num_trials = 10_000;
       my ($deck_size, $max_mulligans, $draw_on_first_turn, $max_turns, $num_copies) = @ARGV;
    
       my @counts;
       TRIAL:
       for (1..$num_trials) {
          my $i = 0;
          my @deck = shuffle(
             ( 0 ) x ( $deck_size - $num_copies ),
             ( 1 ) x $num_copies,
          );
    
          my $starting_hand_size = 7;
          my $mulligans_taken = 0;
          while (1) {
             my @hand = splice(@deck, 0, $starting_hand_size);
             next TRIAL if grep { $_ } @hand;
    
             ++$counts[$i++];
             last if $mulligans_taken == $max_mulligans;
    
             @deck = shuffle(@deck, @hand);
             --$starting_hand_size;
             ++$mulligans_taken;
          }
    
          for my $turn_num (1..$max_turns) {
             next TRIAL if ($turn_num > 1 || $draw_on_first_turn) && shift(@deck);
             ++$counts[$i++];
          }
       }
    
       printf("%.0f%%\n", (1 - $_/$num_trials)*100) for @counts;
    }
    

    输出:

    $ verify 60 2 1 3 4
    40%
    61%
    73%
    75%
    77%
    78%
    

    看准!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-10
      • 2010-10-22
      • 2020-11-21
      • 1970-01-01
      • 2022-09-24
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多