這個轉盤公平嗎

先抽人,再轉盤

這個轉盤的運作順序是:

  1. 按下「開始」的那一瞬間,就用加權隨機抽出中獎者
  2. 反推「要讓那一格停在指針下,轉盤該轉到哪個角度」
  3. 播 6 秒的減速動畫,停在那個角度

也就是說,動畫只是演出來的,結果在動畫開始前就決定了。

聽起來像作弊,其實相反 —— 這是比較公平的做法。

為什麼不讓轉盤自由旋轉

直覺上「隨機給一個力道讓它自由停下」比較公平,但實際上不是:

轉盤最後停在哪,取決於起始角度 + 隨機力道 + 減速曲線三者的組合。 這三個東西都不是均勻分布的:

三個偏差疊起來,結果就是某些格子比較容易停。而最糟的是: 這種偏差完全看不出來。畫面上轉盤在轉、看起來很隨機,但跑一萬次就會看到分布不平。

先抽再轉的做法把「隨機」壓縮成一行程式:

let r = Math.random() * 總權重;
for (…) { r -= 這個人的權重; if (r < 0) return 這個人; }

這一行可以直接被驗證,動畫怎麼寫都不會影響它。

怎麼驗證

這個工具的抽選函式有自動化測試,每次改版都會跑:

最後一條特別重要:如果動畫算錯,現場會看到指針明明停在張三,跳出來的名字卻是李四。 那在尾牙舞台上是無法解釋的。

隨機來源是什麼

Math.random(),也就是瀏覽器內建的偽隨機數產生器。

⚠️ 誠實說明它的性質:這是偽隨機,不是密碼學等級的亂數。 對抽獎來說綽綽有餘(沒有人能預測或操縱它),但它不適合用在需要防止有心人破解的場合 (例如線上博弈)。尾牙抽獎用它是完全合理的。

還有一道守衛

動畫是非同步的,而瀏覽器會完全暫停背景分頁的動畫(實測:分頁隱藏時 1 秒 0 幀)。 主持人切去看投影片再切回來,中獎結果才會補寫入 —— 而那時候狀態可能已經變了。

所以結果寫進名單之前會重新確認兩件事:這個獎項還有名額、這個人還有資格。 不確認的話會出現「3 個名額卻列出 4 位中獎者」或「一人只中一次卻中了兩次」。 這兩個在畫面上都很明顯,但開發時測不到 —— 它們是實際踩到之後才補上的守衛。

現場操作的注意事項見尾牙現場的實務

下載這一頁的 .md 原始檔 用編輯器打開它,就是一份現成的範例文件。

← 回手冊目錄