玄不救非,氪不改命 如何分清遊戲中的“真隨機”和“偽隨機”?
“一定不是我非,一定是遊戲有問題”
很久以前流傳著這樣一則笑話:一個身患重病的人決定去動手術。在手術之前,他問醫生:“這起手術的成功率是多少?”醫生回答他:“只有1%。”他很驚慌,但是醫生說:“沒事的,在你之前我已經治死過99個人了。”
這是一則嘲笑那些不懂“概率”的人的笑話,卻講出了“真隨機”和“偽隨機”之間的區別。
在四月末的時候,我曾寫過一篇《你打遊戲靠的是技術,還是運氣?》,其中就提及了“偽隨機”這個概念。當時受限於篇幅,沒有詳細展開解釋“偽隨機”的概念。前不久,在因國際邀請賽而備受關注的Dota2在最近一次的更新中,有這麼一條更新內容:“落空的負面效果和下坡攻擊的落空效果現在都採用偽隨機觸發”。
那麼到底什麼是“偽隨機”呢?以及和“偽隨機”對應的“真隨機”又是什麼概念?
在討論真隨機和偽隨機之前,先排除另一個容易搞混的錯誤答案:贗隨機數。
贗隨機數演算法(Pseudo-Random Number Generator,簡稱PRNG)是計算機的一個術語——當然,它也可以被叫做“偽隨機數演算法”,只是為了方便與遊戲中的“偽隨機數”進行區分,本文中統一稱作“贗隨機數演算法”。眾所周知,計算機程式是由無數“0”和“1”兩種狀態構成的,如果一個狀態不是“0”,那就必定是“1”,頗有種非黑即白的味道。
因此,在計算機程式中,不存在“不確定”的數字,只有確定的“1”和“0”。基於這種特性,計算機無法生成“真正的(不確定的)隨機數”。那麼在計算機中,需要生成或是使用到隨機數的時候怎麼辦呢?通常是利用計算機抓取一些數值,然後將這些數值輸入至一個複雜演算法(常用的演算法是同餘法和梅森旋轉演算法,有興趣的讀者可以自行查詢,這裡就不展開講了)當中,通過一系列運算得出一個數字,這就是平常說的贗隨機數了。
只要最初輸入的數值(初值)不變,那麼輸出的值都會是同一個值,這就證明了這個數並不隨機,只是看起來隨機而已。換句話說,只要這個隨機數是由確定演算法生成的,那就是贗隨機數。所以下一次在和朋友聊天時提到真隨機數、偽隨機數時,如果有人插嘴:“計算機只能生成偽隨機數,所以根本沒有什麼真隨機”,那你就可以霸氣側漏地說他是“雲玩家”了。
回到正題。在遊戲當中我們一直提到的“真隨機”和“偽隨機”,到底是什麼意思?
我們通常說的真隨機又名“純隨機”(True Random Distribution),就是我們平常一直說的那種、一般意義上的“隨機”。在真隨機中,每一個事件都是相互獨立、服從真隨機分佈的,不受其他事件的發生而改變。比方說某款遊戲為了吸引使用者,擁有這麼一個隨機抽卡系統:每次抽卡時,都有1%的機率抽出SSR卡片,這個概率服從真隨機分佈。
回到我們最開始說的那個“治死99個”的笑話:我們一眼就能看出這個笑話的不合理性。但在抽卡遊戲中,我們的大腦瞬間失去理智。有相當一部分玩家認為:我連抽100次,總能抽到這張卡吧!
實際上,連抽100次卻抽不出1%的SSR卡的機率是為(1-0.01)^100=36.6%,甚至還稍稍超過了1/3。將連抽數字上升至300,也仍有4.9%的機率。換句話說,假設有10000個玩家連抽100次,就有約3660個玩家抽不出這張SSR;10000個玩家連抽300次,也仍有約490個玩家抽不出這張SSR——這對玩家的遊戲體驗來說可以說是毀滅性的打擊。
儘管純隨機在數學上是無罪的,在程式碼中更是明明白白、清清楚楚,但玩家抽不出卡可不會回想到初高中的數學課本,而是首先懷疑機率是否被策劃運營篡改、這背後又是否有骯髒的PY交易……
當然不僅僅是在抽卡系統當中如此。在一些競技性比較強的遊戲中(比如《War3》、《Dota2》之中——《英雄聯盟》幾乎完全摘除了隨機系統,不在此列),連續數次的“走運”極大影響遊戲的競技性和觀賞性。
比方說《Dota中》最著名的概率英雄虛空假面的技能“回到過去”:使虛空假面有25%機率完全躲避一次傷害。受限於War3引擎,這個技能採用的是真隨機概率,在某個極端情況下(通常見於精彩集錦中),虛空假面能夠保持很低的血量承受多次傷害卻不死、最終反殺對手。這種帶給敵方極差遊戲體驗的系統,因此也進入了設計師們“整治範圍”之中。
為了避免極差的遊戲體驗帶來的玩家數量流失,設計者們提出了“偽隨機”的概念:在不確定性的隨機事件當中,通過一系列演算法使隨機事件均勻分佈在多次事件當中,儘可能減少或消除極端情況的發生,以提高玩家的遊戲體驗。
在設計師們的努力下,“偽隨機”應運而生,這裡的偽隨機就和上文的贗隨機數演算法(PRNG)意義不同了。
製造“偽隨機”的方法有很多,在《War3》、《Dota2》這類遊戲當中普遍使用的是“偽隨機分佈”(Pseudo Random Distribution,簡稱PRD)處理概率。
就拿《Dota2》中最強大的暴擊技能“恩賜解脫”來舉例:幻影刺客有15%的機率造成200%/325%/450%致命一擊傷害。在PRD機制下,幻影刺客的攻擊實際上並不是每一刀都有15%的暴擊率。
根據PRD機制的公式P(N)=N*C可得出15%機率的C值為3.22%,即幻影刺客的第一次攻擊暴擊概率為3.22%;如果第一刀沒有暴擊,則第二刀的暴擊率提升至2倍,即6.44%;如果仍舊沒有暴擊,則提升至3倍的9.66%,以此類推。
如果繼續推算,可得在第32刀時暴擊機率會達到100%,最可能觸發暴擊的次數是第6刀,平均觸發刀數是6.67刀等等……
同樣,在連續觸發暴擊時,下一刀的暴擊機率會減少。RPD機制使競技遊戲中連續觸發或不觸發技能的機率降低,避免了運氣成分過度干擾戰鬥結果,大幅提升了玩家的遊戲體驗,但不影響這些隨機事件的正反饋:TI6決賽的“打我五下暈三下”,可是令全球人民集體沸騰了呢!
除了偽隨機分佈RPD之外,還有兩種常見的偽隨機:洗牌演算法和組合隨機。洗牌演算法最常見的用法,是在各大音樂播放器中的“隨機播放”之中。在隨機播放時,如果採用真隨機,會導致一首歌無論如何都播放不出,或是同一首歌連續播放數次(有興趣的讀者可以計算一下這些概率)。為了解決這個問題,播放器採用的解決方案即是洗牌演算法:將一個包含所有歌曲的陣列像洗牌一樣打亂,然後依次播放這個亂序陣列。
至於組合隨機,這是一種廣泛應用於各個遊戲的做法:在抽獎的時候進行兩次、或是更多次的判斷,一次不隨機,而剩下的判斷則是真隨機。比如說,你會在第X次抽卡時抽到SSR是確定的,但抽中的SSR具體是哪張卡,則是隨機的——這就是廣大手遊中的“低保”系統了。
在一堆資料之中想要分清“真隨機”和“偽隨機”似乎並不是那麼容易。那麼接下來為大家介紹兩個例子,有助於更好理解什麼是“真隨機”和“偽隨機”:
真隨機:有一天,小明在的班級上舉辦了一次抽獎活動。這個班級有40個學生,所以為了公平起見,保證每個學生都有1/40的機率中獎,老師準備了40個相同的紙盒,每個紙盒中都有40張紙條,有1張紙條是中獎紙條。這樣一來,每個學生都有1/40的機率中獎,但每個學生是否中獎並不受其他學生的影響。在極端情況下,這個班上可能40個學生都能中獎。這就是真隨機。
偽隨機:小明班上舉辦了抽獎活動。為了公平起見,老師準備了1個紙盒,紙盒中有40張紙條,只有1張紙條是中獎紙條。這樣一來,每個學生都有1/40的機率中獎——但是顯而易見,這個班上有且僅有一名學生能夠中獎。一名學生在中獎後,餘下的所有學生中獎機率都會減少至0。這就是偽隨機。
作者:雲玩家hotspot
來源:機核
原地址:https://www.gcores.com/articles/114836
相關文章
- CSS中如何實現偽隨機?CSS隨機
- 非酋的福音?談一談遊戲內的偽隨機機制以及實現遊戲隨機
- matlab中的偽隨機數原理Matlab隨機
- 偽隨機數是什麼?偽隨機數生成方法有哪些?隨機
- 當隨機不夠隨機:一個線上撲克遊戲的教訓隨機遊戲
- [Z]Oracle 的隨機數、隨機日期和時間、隨機字串Oracle隨機字串
- 從oracle表中隨機取記錄,產生隨機數和隨機字串Oracle隨機字串
- 利用偽隨機碼降低EMI隨機
- 卡牌遊戲中的隨機性(上)遊戲隨機
- C語言中的例子--偽隨機數C語言隨機
- 偽隨機數 pseudo random number隨機random
- python中如何隨機分配Python隨機
- Linux Shell 生成隨機數和隨機字串Linux隨機字串
- 50%暴擊等於4下必暴 遊戲中的偽隨機你知道多少?遊戲隨機
- Python中如何生成隨機數?Python隨機
- Python如何隨機生成1到100的隨機數?Python隨機
- 隨機之美,隨機森林隨機森林
- 熵不起得隨機數熵隨機
- (轉)Oracle的隨機數、隨機日期和時間、隨機字串及造資料匿名過程Oracle隨機字串
- 偽隨機數C語言程式設計隨機C語言程式設計
- 隨機森林和機器學習隨機森林機器學習
- 隨機範圍小數和隨機範圍整數隨機
- Swift 中隨機數的使用Swift隨機
- python生成隨機數、隨機字串Python隨機字串
- 帝國CMS萬能標籤呼叫隨機文章的方法(按表隨機和按照本欄目隨機)隨機
- 預設的 rand.Intn () 生成的是偽隨機數隨機
- 遊戲設計思考:隨機性遊戲設計隨機
- [隨機數詳解]生成一個隨機數,生成指定範圍的隨機數及隨機陣列去重隨機陣列
- 區塊鏈中的隨機數區塊鏈隨機
- GoLang 中的隨機數 tipsGolang隨機
- 讓人沉浸遊戲的魅力機制:隨機與策略遊戲隨機
- 隨機與和未知的互動隨機
- 隨機題隨機
- 隨機排序隨機排序
- 隨機數隨機
- 卡牌遊戲中的隨機性(下):使用標誌性元素遊戲隨機
- 從Linux核心中獲取真隨機數Linux隨機
- C++ 中隨機函式 rand() 和 srand() 的用法C++隨機函式