一個理科直男如何看《魷魚遊戲》

語言: CN / TW / HK

前言

我一向不怎麼喜歡看棒子片。

但是十一期間卻瘋狂的追著一部劇:《魷魚遊戲》。

這片子在全網實在是太火了,火到全球播放量1.11億次,成為奈飛收視率最高的全球非英語原創劇。

魷魚遊戲具有很強的現實社會的隱喻,加上各種有意思的遊戲機制和刺激人心臟的畫面,成功吸引了很多人的追捧。甚至包括劇中的各種道具。。

比如我看完竟然去某寶買了同款椪糖:

除了盒子和針還有一絲還原度以外,這糖餅的質量真不咋地。厚的來簡直拿針沒法戳。我試了下,然後變成了這樣。。。

不光是很難撥出來,味道也完全不行。一個平均賣十幾塊,可想而知毛利有多高。

當然我這篇文章不是為了吐槽椪糖的。

我不知道大家在看這劇時候有沒有這樣想過:如果我是一個參賽者,存活的機率有多大?

估計看過劇的小夥伴都會說,百分百GG。那你知道每個遊戲的生存機率有多大麼,這篇文章我就從理性&歸納的角度分析下每個遊戲的生存機率。

開始正文。

這劇一共6個遊戲,分別是:木頭人,椪糖,拔河,彈珠,玻璃橋和魷魚遊戲。

木頭人這個遊戲,其實要過並不難,主要還在於大家的心理素質和第一次面對大規模屠殺時的恐懼心理,可以肯定的是遊戲在場地右邊的的玩家肯定存活機率大點,因為那個娃娃是從左邊轉頭的,也就是說右邊的人會比左邊的人多出來大概1秒多的時間進行奔跑。

但總體來說,這個沒法用數學來歸納出。我們暫且用劇中的存活概率來計算

木頭人存活概率為:(456-255)/456=44.08%

第二個遊戲椪糖遊戲,由於每個人拿到的圖形不一樣,解題思路也不一樣,這遊戲預設可以採用“作弊”手段,可以用火溶解,可以用舔狗大法。還涉及到一點臨場的反應。同樣的也無法用數學歸納來進行得出,我們同樣用遊戲中的存活概率參考。

第一個遊戲結束後,大家進行了投票決定回家,然後重新決定來參賽的人有187人,第二個遊戲中有79人淘汰,我們可以得出:

椪糖遊戲存活概率為:(187-79)/187=57.75%

第三個遊戲拔河和和第四個遊戲彈珠很簡單,都是淘汰一半的人,存活概率都為50%。

第5個遊戲是重點,玻璃橋。

18對玻璃,每對玻璃只有一塊玻璃能承受人的重量,當你踩到易碎玻璃的時候,玻璃破裂,人就會摔下去GG。16個人挨個過。

當然,在得知遊戲規則的前提下,我們可以很輕易的得出,最後一個人生還的概率是最大的。那每個序號的人生存的概率是多少呢,這個遊戲生還多少人的概率為最大呢。

我於是為玻璃橋寫了一段程式,去模擬1億次。次數足夠多,概率這個東西才有意義。

程式用java寫,花了20分鐘就寫出來了。程式碼如下:

public class SquidGame {

    public static void main(String[] args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Map<Integer,Integer> map = new HashMap<>();

        //迴圈總次數,也就是總模擬次數
        int loopCount = 100000000;
        //橋上一共有幾步
        int stepNum = 18;
        //遊戲參與者一共有幾人
        int peopleNum = 16;
        //每一步有多少塊玻璃
        int grassNumPerStep = 2;

        //中間變數,每一次迴圈的生存者個數
        int surviveNum = 0;
        for (int i = 0; i < loopCount; i++) {
            surviveNum = calcSurvive(stepNum, peopleNum, grassNumPerStep);
            if (map.containsKey(surviveNum)){
                map.put(surviveNum, map.get(surviveNum) + 1);
            }else{
                map.put(surviveNum, 1);
            }
        }
        stopWatch.stop();
        System.out.println(StrUtil.format("玻璃橋步數:{}", stepNum));
        System.out.println(StrUtil.format("參與遊戲的人數:{}", peopleNum));
        System.out.println(StrUtil.format("每一步塊玻璃塊數:{}", grassNumPerStep));
        System.out.println(StrUtil.format("模擬共耗時:{}秒", stopWatch.getTotalTimeSeconds()));
        System.out.println("*******************************************");
        System.out.println(StrUtil.format("魷魚遊戲第5關玻璃橋模擬{}次的結果如下:", loopCount));
        for (int i = 0; i <= peopleNum; i++) {
            System.out.println(StrUtil.format("倖存者個數為{}的次數:{}", i, ObjectUtil.isNull(map.get(i))?0:map.get(i)));
        }

        int maxRateSurviveNum = map.entrySet().stream().max(Map.Entry.comparingByValue()).get().getKey();
        System.out.println("*******************************************");
        System.out.println(StrUtil.format("最終結論:存活{}人的概率為最大", maxRateSurviveNum));
        System.out.println("*******************************************");
        System.out.println();

        System.out.println("每個序號的人存活概率如下:");
        for (int i = peopleNum,j = 1; i >= 1 && j <= peopleNum; i--, j++) {
            int count = 0;
            for (int x = i; x <= peopleNum; x++) {
                count += map.get(x);
            }
            BigDecimal surviveRatePercent = new BigDecimal(count).divide(new BigDecimal(loopCount), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            System.out.println(StrUtil.format("抽到序號為[{}]的玩家生存機率為:{}%", j, surviveRatePercent.toString()));
        }
    }

    public static Integer calcSurvive(int stepNum, int peopleNum, int grassNumPerStep){
        //目前倖存者
        int survive = peopleNum;
        //當前嘗試玻璃步數序號
        int currentStep = 1;
        //目前嘗試的步數還剩幾塊玻璃
        int currentGrassNum = grassNumPerStep;
        while(true){
            if (currentStep <= stepNum && survive > 0){
                //1.每一步的生存概率和每一步有幾塊玻璃有關,如果每一步有2塊玻璃,
                //  死亡概率那就是50%,有3塊玻璃,死亡概率就是66.6%,以此類推
                //2.如果死亡,survive就會減1,同時當前步數的玻璃數目也要減1。
                //  當然如果是按劇中的設定,每一步只有2塊玻璃,那麼這一步,死亡一次後,下一個人必定成功
                //3.如果當前步數此人存活,survive不變,那麼currentStep就會加1,同時下一步的玻璃塊數重置為設定值
                if (new Random().nextInt(1000) > 1000/currentGrassNum){
                    survive--;
                    currentGrassNum--;
                } else{
                    currentStep++;
                    currentGrassNum = grassNumPerStep;
                }
            } else{
                //當前步數等於最後一步 或者 沒有生存者 的情況下,那麼遊戲結束
                break;
            }
        }
        return survive;
    }
}

程式用劇中的人數16人,走18步玻璃,每步2塊玻璃(還有這玩意麼?後續我要加大難度的)的引數玩了1億次。結果如下:

可以看到,存活7人的概率為最大。而且整個存活分佈是一個典型的正態分佈圖:

而每個序號的玩家分佈前幾位基本無生還希望,而後4位基本可以無憂。抽到16序號的人,有高達99.94%的存活率,這個遊戲說到底還是一個拼人品的遊戲啊。

當然這個模擬的前提是:每個人都按照遊戲規則去進行。而且排除了前面一個人過去了,後面一個人不記得是哪塊玻璃這種情況。

我在網上搜索了下,有很多討論就是關於玻璃橋過法的帖子,有說人架在2根鐵橫樑之間過的。有說16個人團結在一起的,手拉著手,讓最前面一個人去試玻璃的,還有說把衣服都脫下來,打包成一個大布球后面拖根布條,用力去砸前面一個玻璃的。

五花八門。

當然這些方法從理論上確實行的通,但是人家vip喝著小酒,大老遠跑過來,能看著你們玩團隊協作,急中生智?遊戲的解釋權還是在官方這裡的。所以這些就不要想了。

僅僅是從數學的期望上來說,玻璃橋這個遊戲,其實最終能存活的應該在6到8個人。而劇中最終存活的只有3個。

難道說這屆正好是低於期望值的麼?

如果按照遊戲的標準規則來走,在前面的人每個人至少得有一次嘗試未知的2塊玻璃的機會,而劇中很多次出現了人性扭曲的一面,被推下去的,同歸於盡的都有,這樣從整個參與者團體的角度去考慮,就白白少了幾次嘗試的機會。而少了幾次嘗試的機會,會直接拉低整個團體的期望。這就是最終只存活下來3個人的原因。

在程式中,我設定了這樣一個引數:grassNumPerStep,每一步有多少塊玻璃。劇中的設定是2。那麼如果我加大難度,把2塊玻璃改成3塊玻璃呢,那結果又是如何呢?(聽著就覺得更加絕望)

從2塊改成3塊玻璃,看起來好像只是每一步的概率從50%降低到33.3%。

但是還隱藏著一個條件:2塊玻璃的時候,前面一個人無論猜對還是猜錯 ,那後面的人一定可以成功的進一步。而3塊玻璃的時候,當前面一個人猜錯失敗的時候,你這時依然有50%的機率猜錯。這個情況就複雜多了。

3塊玻璃繼續模擬一億次的結果:

僅僅是增加一塊玻璃,存活率就如下降的如此厲害,連抽到16號籤的幸運兒也只能有不到24%的生還率。估計這種設定,也就沒人蔘加第六個遊戲了吧。。。

最後一個遊戲,無非就是在目前的存活者當中,決出1個出來。其實整個遊戲不用算都知道拿到錢的就是1/n的機會。也就是說,無論你之前如何動腦子,作弊,推測,坑蒙拐騙,哪怕你混到最後一關了,最後的存活都要依靠人類最原始的蠻力和暴力去解決問題。

這部片子有很強的對映社會的寓意,希望在當下這個浮躁且物慾橫流的社會,大家都能腳踏實地的過日子,不要想著一夜暴富。活著且持之以恆的努力,才是提高幸福感的唯一途徑。