鱿鱼游戏第 7 集模拟

Squid game Episode 7 with simulation

昨晚看了电视剧《鱿鱼游戏》第七集。这集在桥上有一个二项分布的游戏。

具体有16名球员和一座桥,有18副眼镜(一副纯玻璃和一副安全玻璃)。如果一个球员碰巧选择了纯玻璃,那么玻璃就无法承受球员的重量并且玻璃碎了。下一位玩家的优势是 he/she 从最后一位玩家的位置开始并继续二项式 search.At 最后 3 位玩家碰巧过桥。

所以我在想:就像,我口袋里有 16 欧元,我用 p = 1/2 玩正面或反面游戏。每次我都赌人头。如果抛硬币是正面,那么我赚 0,如果是反面,我损失 1 欧元。连续或不连续击中 18 次正面并且口袋里剩下 3 欧元的概率是多少。

我试图在 R 中模拟这个问题:

squid_bridge = function(a,n,p) {
  players = a
  while (position > 0 & position < n) {
    jump  =  sample(c(0,1),1,prob=c(1-p,p))
    position = position + jump
  }
  if (position == 0) 
    return(1) 
  else 
    return(0)
}   

n = 18
trials = 100000
a = 16
p = 1/2
set.seed(1)
simlist = replicate(trials, squid_bridge(a, n, p))

好像不行。有帮助吗?

以下是我认为您可以在 R 中为游戏建模的方式。第一个版本与您所拥有的相似:有 50% 的机会猜对,如果猜对是正确的,玩家前进一张牌。否则他们不这样做,玩家人数减1。如果玩家人数达到0,或者他们前进到最后,游戏结束。这显示在 squid_bridge1().

squid_bridge1 <- function(players, n, prob) {
  if (players == 0 | n == 18) {
    # All players have died or we have reached the end
    return(players)
  }
  
  jump <- rbinom(1, 1, prob)
  
  if (jump == 0) {
    # Player died
    return(squid_bridge1(players - 1, n, prob))
  }

  if (jump == 1 & n < 18) {
    # Player lives and advances 1 space
    return(squid_bridge1(players, n + 1, prob))
  } 
}

然而,这并不能准确描述游戏,因为错误的猜测会给其余玩家提供额外的信息。如果玩家选错了,下一次猜对的概率不是50%,而是100%。然而,在那之后,正确猜测的概率下降到 50%。这可以用另一个参数来解释,以跟踪先前猜测的正确性。

squid_bridge2 <- function(players, n, prob, previous) {
  if (players == 0 | n == 18) {
    # The game ends if there are no players or they have reached the end
    return(players)
  }
  
  if (previous == 0) {
    # The previous guess was wrong, but now the players know where to go next
    return(squid_bridge2(players, n + 1, prob, previous = 1))
  }
  
  jump <- rbinom(1, 1, prob)
  
  if (jump == 0) {
    # Player died
    return(squid_bridge2(players - 1, n, prob, previous = 0))
  }
  
  if (jump == 1 & n < 18) {
    # Move is correct. Advance 1 space
    return(squid_bridge2(players, n + 1, prob, previous = 1))
  } 
}

但是,有一个问题。节目中并没有那么简单,玩家摔倒的原因不是猜测错误(被推、故意跳等)。我不知道做这样的事情的合理概率是多少,但它可能很低,比如说 10%。

not_stupid <- function() {
  x <- runif(1, 0, 1)
  if (x <= 0.1) {
    return(FALSE)
  } else {
    return(TRUE)
  }
}

由于情绪会在每次移动前激增,我们将在每次移动前对此进行测试。

squid_bridge3 <- function(players, n, prob, previous) {
  if (players == 0 | n == 18) {
    # The game is over because there are no players left or they reached the end
    return(players)
  }
        
  if (previous == 0) {
    # The previous guess was wrong, but now the players know where to go next
    return(squid_bridge3(players, n + 1, prob, previous = 1))
  }
  
  if (!not_stupid()) {
    return(squid_bridge3(players - 1, n, prob, previous = 1))
  }
  
  jump <- rbinom(1, 1, prob)
  
  if (jump == 0) {
    # Player died because of either choosing wrong or a self-inflicted loss
    return(squid_bridge3(players - 1, n, prob, previous = 0))
  }
  
  if (jump == 1 & n < 18) {
    # Move is correct. Advance 1 space
    return(squid_bridge3(players, n + 1, prob, previous = 1))
  } 
}

然后运行一些模拟:

set.seed(123)
trials <- 10000
players <- 16
squid1 <- replicate(trials, squid_bridge1(players, 0, 0.5))
squid2 <- replicate(trials, squid_bridge2(players, 0, 0.5, 1))
squid3 <- replicate(trials, squid_bridge3(16, 0, 0.5, 1))

df <- tibble(squid1 = squid1,
             squid2 = squid2,
             squid3 = squid3) %>%
  pivot_longer(cols = c(squid1, squid2, squid3))

ggplot(data = df,
       aes(x = value)) +
  geom_histogram(bins = 10,
                 binwidth = 1,
                 fill = "cornflowerblue",
                 color = "black") +
  facet_wrap(~name,
             nrow = 3) +
  xlab("# of players to make it to the end") +
  scale_x_continuous(breaks = seq(0, 16, by = 1),
                     labels = seq(0, 16, by = 1))

如下图所示,第一种情况严重偏左。由于玩家基本上是在“盲目猜测”每个板块,因此不太可能有人能走到最后。然而,在考虑到从错误猜测中获得的信息后,平均大约有 7 名玩家成功。通过添加因其他原因掉落的随机机会,分布向左倾斜了一些。

  • 第一种情况的平均值:1.45
  • 第二种情况的平均值:7.01
  • 第三种情况的平均值:4.99

要回答 只有 3 名玩家成功的概率问题,最后一个案例我得到 ~ 10.8%

编辑: 根据要求,这里是生成图表的代码。我还修复了存在命名问题的各种函数(创建它们时使用了几个不同的名称)。看起来它导致了第三个函数的一个小错误,但我已经完全修复了它。

○△□

##########
# Game ○ △ □ 
##########
squidd7<-function(N_Fields,N_Players,p_new_field){
  Players<-data.frame(id = 1:N_Players, alive=rep(1,N_Players),Field=0)
  
    for(i in 1:N_Players){
      while (Players[i,"alive"]==TRUE && max(Players$Field)< N_Fields) { 
        Players[i,"Field"]=Players[i,"Field"]+1  # Jump onto the next Field
        Players[i,"alive"]=rbinom(1,1,p_new_field)# Fall or repeat
      }
      Players[i+1,"Field"]=Players[i,"Field"] # next player starts where prior player died
    }
  Players<-Players[1:N_Players,] # cosmetic because i do i+1 in the prior line
  # Print me some messages
  if(!any(Players$alive>0)){
      cat("Players loose!")
    } else {
    cat(" \n After", max(Players$Field),"goal was reached! ")
    cat("Players",Players[Players$alive==1,"id"], "survive")
    }
  
  return(Players)
}


squidd7(18,16,0.5)

###########
# simulation ○ △ □
###########
results<-data.frame(matrix(0, nrow = 100, ncol = 20))
for(x in 1:ncol(results)){
     for (i in 1:nrow(results)) {
    Players<-squidd7(x+7,16,0.5)
    results[i,x]<-sum(Players$alive)
  }
}
###########
## Results ○○□□○ △ □
sdt<-apply(results,2,sd) # standart devation 
mn<-apply(results,2,mean) # ○ △ □

boxplot(results,xlab ="n Steps ",names = 8:27,ylab="N Survivors of 16 ")
points(mn,type="l")
points(sdt,type="l")

colors<-colorRampPalette(c(rgb(0,1,0,0.4),
                           rgb(1,1,0,0.4),
                           rgb(1,0,0,0.4)), alpha = TRUE)(21)


plot(density(results$X1),type="n",xlim=c(-1,17),ylim=c(0,0.30),
     main="○ △ □ ",
     sub="○ △ □ ○ △ □ ○ △ □",
     xlab="number of survivors")
for( i in 1:21){
polygon(density(results[,i]),col= colors[i])
}
legend(15,0.31,title="Steps",legend=8:28,fill=colors,border = NA,
       y.intersp = 0.5,
       cex = 0.8, text.font = 0.3)

这是 R 中的一个 Monte Carlo 实验,返回失败次数的分布。

apply(apply(matrix(rgeom(16*1e6,.5)+1,nc=16),1,cumsum)>18,1,mean)
#with details:
#rgeom(16*1e6,.5)+1 for 16 x 10⁶ geometric simulations when
#the outcome is the number of attempts till "success",
# "success" included
#,1,cumsum) for the number of steps till 16th "success"
#)>18 for counting the cases when a player manages to X the bridge
#1,mean) for finding the probability of each of the players to X

不是一个二项式实验,而是一个截断的负二项式实验,因为每个玩家的新步数是一个几何 Geom(1/2) 变量,除非 18已经采取了步骤。因此,平均幸存者人数为

sum(1-pnbinom(size=1:16,q=17:2,prob=.5))
#Explanation:
#pnbinom is the Negative Binomial cdf
#with size the number of "successes"
#q the integer at which the cdf is computed
#prob is the Negative Binomial probability parameter
#Because nbinom() is calibrated as the number of attempts
#before "success", rather than until "success", the value of
#q decreases by one for each player in the game

其值为 7.000076,而不是 16-18/2=7!

如果我理解正确,我相信其他答案会使模拟复杂化。

我们可以模拟大小为 18 的二项式分布的平局。每个 1 都会杀死一个人(假设还有人要杀死)。因此,我们可以通过从玩家数量中减去抽取的 1 的数量来计算幸存者数量,截断为 0(任何负结果都计为 0,通过 pmax())。

set.seed(47)
n_sim = 1e4
survivors = pmax(0, 16 - rbinom(n_sim, size = 18, prob = 0.5))
mean(survivors)
# [1] 7.009

随着 n_sim 的增加,平均值似乎接近西安 7.000076 的答案。在 500M 模拟(使用此方法仍然运行得相当快!)时,我们得到的平均值为 7.000073。

绘制这些结果,它们看起来与 cazman 的 squid2 场景基本相同。

ggplot(data.frame(survivors), aes(x = survivors)) + geom_bar() +
  scale_y_continuous(limits = c(0, 6000))

很好模拟这个游戏。你将需要 50%/50% 的机会 16 次。这意味着你所需要的代码是 50% 的机会不输,运行 它是你输了的 16 倍,它会做一个 -1 形式的变量 18。这将创造一个完美的鱿鱼游戏桥[数字娱乐] =10=]