用Python計(jì)算明日方舟2021龍門幸運(yùn)墻期望
按照去年的慣例,方舟今年春節(jié)的時(shí)候也整了個(gè)紅包盲盒。

比起去年簡(jiǎn)單粗暴的直接送,今年的盲盒實(shí)際上增加了兩層隱性的保底機(jī)制:第一層是每天有兩次機(jī)會(huì)而非一次,兩次嘗試取收益更高的結(jié)果;第二層是如果不幸成為了開(kāi)出小紅包的天選之人,第二天追加一次開(kāi)包機(jī)會(huì)。
這種保底機(jī)制使得在今年的活動(dòng)里玩家?guī)缀醪豢赡艹缘阶畲蟮哪菍拥捅#?.025×10^31分之1),但是也使得用純數(shù)學(xué)方式計(jì)算期望變得極其復(fù)雜。但是作為一個(gè)高數(shù)掛過(guò)一次的人我也不可能硬算啦……因此這次我使用暴力美學(xué),用計(jì)算機(jī)跑他個(gè)幾百萬(wàn)次,跑出來(lái)的結(jié)論就可以近似看作期望了。順便為了測(cè)試一下 B 站新搞的代碼塊好不好用,我這次在文中把代碼貼出來(lái)試試看。
1. 基礎(chǔ)檔位
首先可以看出玉有六個(gè)檔位:2/3/4/5/6/800??梢杂?2.5 種方式確定檔位:設(shè)置好每個(gè)檔位對(duì)應(yīng)的玉的數(shù)量,對(duì)檔位進(jìn)行隨機(jī),隨后將檔位換算成對(duì)應(yīng)玉的數(shù)量;直接對(duì)六個(gè)玉的數(shù)量進(jìn)行隨機(jī)抽??;或者對(duì) 2-8 進(jìn)行隨機(jī),如果出現(xiàn) 7 則舍去該結(jié)果再次隨機(jī)直到出現(xiàn)到幾個(gè)數(shù)字中的一個(gè)為止,最后再將結(jié)果乘以 100。第一和二種方式本質(zhì)上沒(méi)什么區(qū)別,但第三種因?yàn)橛竦臄?shù)量沒(méi)有 700 這個(gè)檔位,這么做的話稍微有點(diǎn)點(diǎn)傻……
我選擇的是第一種方式,用字典記錄六個(gè)檔位對(duì)應(yīng)的獎(jiǎng)勵(lì),然后對(duì)檔位進(jìn)行隨機(jī)抽取。
2. 流程
每一天的流程很簡(jiǎn)單:開(kāi)第一個(gè)包→開(kāi)第二個(gè)包→根據(jù)前一天的開(kāi)包情況決定有沒(méi)有第三個(gè)包→取最大值→進(jìn)入下一天。
但是實(shí)現(xiàn)“開(kāi)第三個(gè)包”的方式有很多。最笨的實(shí)現(xiàn)當(dāng)然可以根據(jù)鷹語(yǔ)的描述,用 400 與前一天的結(jié)果進(jìn)行比較來(lái)決定第三個(gè)包是否存在,但是我選擇了一種對(duì)人類比較友好的方式:立一個(gè)“需要抽第三次”的 flag,該 flag 在第一天的默認(rèn)值是 False,在隨后每天兩次抽取結(jié)束后將會(huì)檢查 flag 的狀態(tài),如果為真,則抽取第三次;如果為價(jià),則認(rèn)為第三次抽取到的玉數(shù)量為 0。執(zhí)行完這一分枝后將再次判斷今天的收獲,如果小于 400,則將 flag 反轉(zhuǎn)為真,反之則翻轉(zhuǎn)為假,進(jìn)入第二天。
代碼如下:
3. 計(jì)算期望并輸出
計(jì)算期望就是總共獲得的玉除以總嘗試次數(shù)這個(gè)沒(méi)什么好說(shuō)的,主要核心在怎么寫(xiě)流程……因此直接上代碼。
4. 輸出每次嘗試獲得的玉總數(shù)和對(duì)應(yīng)頻數(shù)
在腳本的一開(kāi)始我定義了一個(gè)名為all_results
的空列表來(lái)存儲(chǔ)每次嘗試(跑完 14 天后的總數(shù))的結(jié)果。在 Python 當(dāng)中可以直接調(diào)用min
和max
函數(shù)對(duì)整個(gè)列表中的數(shù)據(jù)進(jìn)行取最大值和最小值操作,也可以在導(dǎo)入 collections.Counter 模組之后很方便的統(tǒng)計(jì)頻數(shù)。(注意:Counter()的結(jié)果不能直接拿來(lái)用)
因?yàn)槲倚枰?jì)算頻數(shù),所以我需要這個(gè)列表。如果沒(méi)有這個(gè)需求的話,直接存儲(chǔ)上一次嘗試的結(jié)果,然后把這一次嘗試的結(jié)果和上一次進(jìn)行兩兩比較,然后舍棄掉不要的那個(gè)結(jié)果。這樣可以占用更少的系統(tǒng)資源。(但是都用 python 了……)
因?yàn)槲业?python3.9 好像裝不上 matplotlib,我也懶得折騰,所以就把文件導(dǎo)出成了 csv 之后扔進(jìn)了 SPSS。
5. 完整代碼和結(jié)果
把其他框架部分補(bǔ)充完整之后,試著跑他個(gè)十遍的一百萬(wàn)次。

我也嘗試了一下跑一億次,好家伙給我跑了一個(gè)小時(shí)……

把解釋器換成 pypy 之后,總運(yùn)行時(shí)間得到了驚人的提升。

就當(dāng)我直呼pypy yes的時(shí)候我發(fā)現(xiàn)哪里不對(duì)勁,仔細(xì)一看發(fā)現(xiàn)小數(shù)點(diǎn)后的結(jié)果全被舍掉了……
pypy:別扯什么準(zhǔn)確了,你就說(shuō)我算得快不快吧!
但是至少?gòu)倪@一億多次結(jié)果可以看出來(lái),想要吃到 2800 的天選保底,難度還真挺大……
像極了大學(xué)期末考老師拼命撈人的樣子。
代碼全文如下: