精華區beta C_Chat 關於我們 聯絡資訊
※ 引述《OrO3 (OrO3)》之銘言: : 雖然現在的可以把亂數做到很像是真實的亂數 : 但函式庫的底層其實是依照公式以及表格,去計算出下一個數字的 : 在早期的賭場的吃角子老虎 : 用的就是很脆弱的亂數 : 那時候有兩個數學家到賭場去 : 盯著吃角子老虎很久,算出機器出的亂數的規律 : 然後數學家看準時機下了注,贏了大筆獎金 : 我忘記這個故事的後續如何 : 印象中是那兩個數學家,被賭場當成是作弊,趕出去了 : 獎金當然也被沒收了 : 不知道大家會怎麼想這件事 : 這算是利用bug作弊嗎? : 說起來,像FGO的轉蛋遊戲,也是機率遊戲 : 如果有辦法透過大量收集數據 : 反推出,幾點幾分幾秒會出SSR : 導致100次單抽,抽出五十幾隻五星 : 你會覺得這算是作弊嗎? : PS. 以FGO的程式品質,我是真的覺得有可能反推的出來 其實很多人誤以為亂數為了不被發現規律就是得要把函數寫的非常複雜 或是參數給得非常多 卻往往忽略了記憶體(空間)成本以及速度(時間)成本 其實只要簡單的函式就能夠產生夠亂的值 而其實有些玩家宣稱能在亂數函式中找出規律值往往只是一時間的湊巧 許多像這種拿時間函數,或是拿你的身分證字號,抑或是拿隔壁老王的出生年月日 ...等等當參數去對應UR,SSR,特定的強角,SSR安部奈奈,甚至是垃圾 這種x對應於y的方式 我們統稱叫hash 換數學式子上,就是在非無限大的集合X與Y使得 f(x) = y (對於所有 x 屬於 X, y 屬於 Y) 根據鴿籠原理,若N(X) > N(Y) 一定會有兩個x1與x2以上使得 x1!=x2 f(x1) = f(x2) 這叫做碰撞 當然會有一些函式 (前提是 N(X) <= N(Y) ) 會讓碰撞機率最小 這叫做"perfect hash function" 其實wiki上有列出其中一個perfect hash function f(x) =( kx mod p ) mod N(Y) 其中p是一個極大的質數, k 只是一個參數 但是最後不論你的f(x)怎麼設 還是免不了生日問題 也就是在1~d中任意取(f(x))n個整數(n<=d)使得某兩個整數以上一樣的機率為 1-(1-1/d)*(1-2/d)* ... *(1-n-1/d) 趨近於 1-e^(-n*(n-1)/(2*d)) -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.236.35.20 ※ 文章網址: https://www.ptt.cc/bbs/C_Chat/M.1508154435.A.E23.html
chuckni: 快推 10/16 19:47
mark0912n: 有些狀況是妳知道了也沒辦法 10/16 19:49
fuhu66: 猛 10/16 19:49
mark0912n: 比如說就算你知道下期的發票中獎號碼 你也很難得到... 10/16 19:49
Xavy: 你說這麼多也沒說結論,是說辛酸的喔? 10/16 19:50
OrO3: https://www.youtube.com/watch?v=Nehvzf9esQs 看這個 10/16 19:57
bach8517: 生日哥問題? 10/16 19:57
pinacolada: 安部菜々 10/16 19:57
OrO3: 如果成寫程式的人沒有「故意」去搞hash的話,程式碼說不定只 10/16 19:58
OrO3: 是這樣而已: 10/16 19:58
OrO3: int rand = 用秒當seed產生亂數 % 100; 10/16 19:59
OrO3: if(rand == 0) 抽中ssr; 10/16 20:00
OrO3: (下略 10/16 20:00
LayerZ: 你這樣中獎率1%喔 10/16 20:01
OrO3: 那你只要是著去取得 精準到秒的時間、抽中的東西。就能試著 10/16 20:01
OrO3: 去反推他會抽中什麼。 10/16 20:01
lay10521: 但是首先 你要先知道他是怎麼寫的阿 10/16 20:02
noob9527: 現在簡單的rand()都到毫秒了 亂數分佈也都很平均吧 10/16 20:02
OrO3: 對啊,ssr是1%。 說不定程式是一開始就依照卡池去找,那就要 10/16 20:02
OrO3: 試著去猜寫法。 10/16 20:03
noob9527: 你可以算出來沒錯 但是你要毫秒的準確度加上網路無延遲 10/16 20:03
OrO3: noob9527 你是不是沒看影片?同分同秒抽中的東西一樣喔 10/16 20:03
LayerZ: 首先,這種影片只能當謠言看... 10/16 20:04
LayerZ: 除非你能重現,就算抽到的不是ssr也沒差 10/16 20:04
LayerZ: 不能重線都是屁 10/16 20:04
OrO3: 那下次我抽卡的時候來驗證看看 10/16 20:04
LayerZ: 我記得當初吵很大了XDD 10/16 20:05
OrO3: 所以吵過之後,有人去試過了嗎? 10/16 20:05
LayerZ: 結論是不行,你可以試試看 10/16 20:06
OrO3: 有人試過的話,直接告訴我結論就好,這影片是不是真的? 10/16 20:06
OrO3: 了解 10/16 20:06
mark0912n: 就像我說的 就算你知道發票中獎號碼 你能中嗎 XD 10/16 20:06
OrO3: 如果程式真的拿秒數當SEED的話,你可以算出幾點幾分可以抽中 10/16 20:08
OrO3: ssr。 10/16 20:08
jim924211: 影片那個還是運氣成分偏重吧 10/16 20:09
jim924211: 就算知道方法,但目前物理上的差距就在那邊 10/16 20:10
OrO3: 我覺得比較可能是造假或是後來這個問題被修掉,機率的話太低 10/16 20:10
jim924211: 除非寫程式的人太爛,倒是有可能就是了 10/16 20:11
noob9527: 影片運氣成分+1 而且中間也有不一致的結果 10/16 20:11
jim924211: 我覺得可能是程式編寫的問題 很有可能他亂數寫得不好 10/16 20:11
OrO3: 其實一般程式設計師不會在那種地方搞hash,比較有可能是在初 10/16 20:12
OrO3: 始化亂數的時候,用秒去指定了seed 10/16 20:12
OrO3: 不然一般亂數的函式庫,預設上不必特別去動他就能生出隨機的 10/16 20:13
OrO3: 數字出來。 10/16 20:13
jim924211: 不過要是工程師整個Team中有內鬼 10/16 20:14
jim924211: 利用職務之便洗帳號賣掉這樣的話……… 10/16 20:14
jim924211: 不過當然啦,這只是陰謀論罷了XDD 10/16 20:14
jim924211: 實際上應該如OrO3大說的差不多 10/16 20:15
noob9527: 簡單說就是要作牌反而出包才有可能 10/16 20:16
lay10521: 一般人應該不會這樣做 但如果是FGO一開始這樣搞 我覺得 10/16 20:16
lay10521: 合理 10/16 20:16
jim924211: Fgo工程師的技術力真的很讓人質疑XD 10/16 20:17
noob9527: 像某些廠商會要求程式滿XX抽之後 機率才從0%>X% 10/16 20:18
jim924211: 不過樓上那樣就違反日本的轉蛋法了吧@@ 10/16 20:19
noob9527: 或是手動平均分散 1小時內就只會抽出X個大獎 10/16 20:20
LayerZ: 你想太多了,廠商只會給好處不會給壞處 10/16 20:25
LayerZ: 除非你是搞博弈的 10/16 20:26
LayerZ: ssr放著又不會增值,玩家要抽就給你抽好嗎,反正機率已經 10/16 20:26
LayerZ: 低到吃定你了 10/16 20:26
medama: 以前三國無雙某代刷傭兵就是這樣啊 用開機時間當亂數計算 10/16 20:31
LiNcUtT: 我覺得亂數用XxHash做很不錯,夠快又夠亂 10/16 20:33
kokal: goo.gl/EC2tHt 可能的原因之一 10/16 20:50
kokal: 各個thread建一個random會出現thread間比較並非random 10/16 20:52
LiNcUtT: 種子變動後取的第一個亂數,沒做好的話會有規律性 10/16 20:53
LiNcUtT: 順帶一提,unity應該已改用xxHash算法,效率亂度兼具 10/16 20:56
有人說用秒當亂數種子所產生的亂數很容易被察覺 那我們來看C的亂數 以下是用C的rand以秒當種子隨機5000次取0~4所得的機率,原始碼以及結果如下 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #define TIMES 5000 int main(){ int result[5]={0}; int i; unsigned seed; seed = (unsigned)time(NULL); srand(seed); for(i=0; i<TIMES; ++i) result[rand()%5]++; printf("0: %f\n1: %f\n2: %f\n3: %f\n4: %f" ,(double)(result[0])/TIMES ,(double)(result[1])/TIMES ,(double)(result[2])/TIMES ,(double)(result[3])/TIMES ,(double)(result[4])/TIMES); return 0; } 0: 0.201800 1: 0.188200 2: 0.205600 3: 0.203400 4: 0.201000 你會發現誤差只在0.001~3附近,也就是5000次大夠只有1至2次偏向某個數字 然後觀察rand的原始碼,你會發現 for (i = 1; i < kc; ++i) { /* This does: state[i] = (16807 * state[i - 1]) % 2147483647; but avoids overflowing 31 bits. */ long int hi = word / 127773; long int lo = word % 127773; word = 16807 * lo - 2836 * hi; if (word < 0) word += 2147483647; *++dst = word; } 原始碼只是某些對於質數的四則運算 算是一個有意點複雜的perfect hash function 雖然對於某些種子會產生意料的規律性,但是對於產生隨機而言綽綽有餘 ※ 編輯: jpopaholic (223.138.208.152), 10/16/2017 21:08:40
kokal: http://cyan4973.github.io/xxHash/ 中沒看到unity XDD 10/16 21:07
OrO3: seed = (unsigned)time(NULL); srand(seed); 你把這一行移到 10/16 21:13
OrO3: 回圈內,你就會知道我在說的是什麼狀況了。 10/16 21:13
OrO3: 當然,那個寫法是錯的,如果是寫成抽卡的亂數,就會變成,同 10/16 21:14
OrO3: 分同秒按下抽牌,不管是誰,抽到的卡都會是一樣的,就如同影 10/16 21:15
OrO3: 片那樣。 10/16 21:15
jpopaholic: 那叫錯誤程式寫法,跟rand()很爛無關 10/16 21:15
OrO3: 我看完那個影片,就可以假設有seed = (unsigned)time(NULL); 10/16 21:16
LiNcUtT: 我猜的,因為我用作者提供的code去run過 10/16 21:16
OrO3: 這一行,那麼,就可以更進一步嘗試算出哪個時間點可以抽到好 10/16 21:17
OrO3: 牌 10/16 21:17
LiNcUtT: unity5.5的random跑出來的結果跟xxhash幾乎一模一樣 10/16 21:17
OrO3: 那我跟jpopaholic在講的就是不同的事情了,這邊有誰講rand很 10/16 21:19
OrO3: 爛啊? 10/16 21:19
LiNcUtT: 之前無聊跑來玩的結果 https://i.imgur.com/Tg4hI3f.png 10/16 21:26
alex912888: Pokémon這種單機遊戲,遇到timer0太多組的版本時還是 10/17 14:40
alex912888: 難以控制亂數,連線遊戲還有延遲或修改等問題,即使真 10/17 14:40
alex912888: 的知道怎麼寫,要操作恐怕還是很難 10/17 14:40