10 連抽保底的概率模型
網游里有很多抽卡、開箱子之類的賭性玩法,在最開始,游戲設計者實現的時候,僅僅給這些抽取概率簡單的設置了一個值。比如抽卡抽出橙卡的概率是 10% ,那么就是說,玩家每次抽一張卡,有 90% 的可能是白卡,10% 的可能是橙卡。
但大 R 玩家是大爺,需要小心伺候。如果感受不好,人跑了就虧大了。概率這個東西靠改進偽隨機數發生器是解決不了體驗問題的,大爺要是連抽 20 張都出不來橙卡,那是要怒刪游戲的。
連抽 20 張 10% 概率橙卡一張都抽不到的機會多不?一張抽不中的概率是 0.9 ,20 張都抽不中的概率是 0.9 ^20 = 12.2% 。這可不算小數字啊。平均 8 個大 R 就會碰到一次,一下子趕跑了 1/8 的金主,這個責任小策劃可擔當不起。
所以、一般網游都會用各種規則來避免玩家出現連抽不中的尷尬。例如,我忘記是誰發明的 10 連抽規則:如果你購買一個大包連抽 10 次,我在規則上就保證里面一定至少有一張橙卡。實現它應該并不困難,按常規概率生成 10 張的卡包,如果里面沒有橙卡,那么我加一張即可。
但如果我想把 10 抽保底的規則惠及日常抽卡的玩家該怎么做呢?
就是說,我希望任何玩家任何時候,接連抽了 10 張卡,我都想保證這 10 張卡里至少有一張橙卡。
首先,要說明的一點:如果你同時想保證橙卡掉落率是 10% ,也就是在極大范圍內,比如系統投放了一萬張卡片中,其中要有一千張橙卡。那么同時保證每 10 張卡里有至少一張橙卡的話,結果一定是完全不隨機的,也就是必須每抽 9 張白卡,必出一張橙卡。
所以、如果即想要隨機(出橙卡的概率穩定),又想有 10 張出一張的保底,那么橙卡投放量是一定超過 1/10 的。
我們之前的游戲用了個很粗暴的方案:記錄玩家已經連續幾次沒有抽中,如果連續次數超過 9 ,就必給他一張橙卡。為什么我說這個方案粗暴,因為它其實破壞了抽卡的自然體驗。雖然玩家的確更高興了,但是概率卻很不自然。不自然的方案(其實是生硬的打了個補丁)實現起來還容易出錯,我們前段時間就因為實現 bug 多發放了很多稀有物品,這個 bug 就不展開說了。
下面來看看,為什么這么做不自然。
假設橙卡的掉率是 10% ,那么你在獲得一張橙卡后,再抽下一張橙卡的概率就是 0.1 。下一張是白卡,再下一張是橙卡的概率是 0.9 * 0.1 ,下兩張是白卡,第三張是橙卡的概率是 0.9^2 * 0.1 ……
后續有 10 張及 10 張以上的概率總共有多少呢?我算了一下,大約是 35% 左右。
我們把抽到兩張橙卡之間會抽取到的白卡張數排成一個數列的話,這個數列的值的范圍是 0 到正無窮。是的,非洲酋長可能永遠抽不到橙卡。當然這只是理論值。
如果你讀過大學,學的是理工科,沒有逃課的話,就應該知道,這個數列是大致符合 指數分布 的。指數分布正是用來表示獨立隨機事件發生的時間間隔的。
當我們把這個數列中大于 9 的數字都強行改成 9 ,那么 9 的出現頻率就陡然跳變,這是極不自然的。(分布不平滑)
從一致分布的隨機數,轉換為指數分布的隨機數非常簡單。
讓我們回答前面的問題,如果我希望獲得一個大約每 10 張卡里出一張橙卡的隨機數列,除了每次 random 一個 [0,10) 的整數,判斷證書是不是 0 以外,還有一個方法。那就是每次抽到一個橙卡后,都從一個指數分布的隨機數列中取一個值出來,作為接下來會抽取到白卡的張數。按這個張數去發放白卡,等計數器減到 0 ,就發一張橙卡給玩家。這個白卡張數的數值范圍是 [0, inf) 。
用 lua 實現的話,大概是這樣的:
math.floor(math.log(1-math.random()) * (-rate)) 其中 rate = 10 。
好了,如果我們想加上 10 張保底,又想讓間隔大致符合指數分布怎么辦?簡單:
function erand(rate) while true do local p = math.floor(math.log(1-math.random()) * (-rate)) if p < rate then return p end end end
讓產生出來的數字小于 10 的時候重來一次就好了。如果你擔心這里死循環(實際并不會),也可以加上循環上限:
function erand(rate) for i = 1, 100 do -- 100 可以隨便寫 local p = math.floor(math.log(1-math.random()) * (-rate)) if p < rate then return p end end return rate-1 end
當然,一旦加上了 10 張保底,單張出橙卡的概率就大大增加了,增加到多少呢?大約是 21%。如果你希望保持 10% 左右的投放率,那么保底張數大約應該設置在 23 張左右。
ps. 今天在公司群里討論這個問題時,雷先生提了這么一個問題,說是可以用來做數值策劃的面試題:
已知橙卡的抽取率是 10% ,抽一次卡是 1 塊錢;而 10 連抽的包可以幫你按同樣概率連抽 10 次,但如果沒有抽到橙卡的話,系統會補償一張橙卡給你,換掉 10 張白卡中的一張。
假設白色一文不值,只有橙卡值錢。
那么請問:這個 10 連抽的包到底價值多少?
來自:http://blog.codingnow.com/2017/01/exponential_distribution.html