Community程式設計與開發github.com

Chibuchibs/free-claude-skills

捕捉看似公平卻不盡然的洗牌、隨機選取與機率問題,並正確測試分佈。當程式碼進行陣列洗牌、隨機化測驗答案或選項、選取隨機子集、指派機率、產生戰利品或獎勵,或當有人說結果「感覺有鬼」、「總是選同一個」,或詢問如何洗牌或隨機化某物時,使用此技能。

free-claude-skills 是什麼?

此技能旨在偵測並修正常見的隨機化瑕疵,特別是 JavaScript 中使用 `Array.sort(() => Math.random() - 0.5)` 進行洗牌的錯誤。這種寫法因為違反排序比較器的穩定性需求,會產生偏斜的排列,導致機率分佈不均,例如在測驗選項中正確答案落在不同位置的機率從 18.8% 到 28.3% 不等。 它提供 Fisher-Yates 正確洗牌演算法的標準實作,並強調不要對所有 `Math.random() - 0.5` 模式進行全域取代,以免誤傷物理模擬中的合法雜訊。同時教導如何透過統計計數來測試分佈是否均勻(超過約 3 個百分點的差異即表示有偏差),並注意測試用的亂數產生器本身是否可靠。 此外,該技能也提醒檢查顯示給使用者的機率(如百分比、進度條)是否與實際程式擲骰結果一致,並驗證遊戲中聲稱的目標(如「3 of 5」中的 5)是否真實可達,避免介面承諾實際上幾乎永不發生的事件。支援平台為 Claude Code、Cursor、Codex 等 AI 代理工具。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Chibuchibs/free-claude-skills/tree/HEAD/skills/randomness-correctness

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

那不是真正的洗牌

JavaScript 中最常見的隨機化錯誤:

const shuffled = items.sort(() => Math.random() - 0.5);   // 錯誤

它看起來沒問題,而且隨處可見。但這不是洗牌。排序比較函數期望的是一致的,而這個不是,因此引擎的排序會產生偏斜的排列。

針對四個測驗選項的實測結果:

位置正確答案落在該位置的機率
028.3%
128.2%
224.7%
318.8%

均勻分配應該是每個位置 25%。實際上,總是猜第一個選項比隨機猜測還要好——一個注意到這個問題的玩家就會佔有優勢,而這個測驗就在不知不覺中變得不再公平。

修正方法

Fisher–Yates 演算法,寫成一個輔助函式,只做一次洗牌:

function shuffle(a) {
  const out = [...a];
  for (let i = out.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [out[i], out[j]] = [out[j], out[i]];
  }
  return out;
}

然後替換所有出問題的地方。這個錯誤通常不只出現一次——某個程式碼庫甚至出現在十一個地方:洗牌測驗選項、挑選哪些題目出現、選擇提供哪些道具、排序菜單選項。每個地方都稍微偏斜了結果。

不要用模式匹配進行全面取代。 (Math.random() - 0.5) 也可能合理出現在物理模擬的雜訊和抖動中:

velocity += (Math.random() - 0.5) * 0.012;   // 這個請留著

檢查每個匹配項,確定它真的是排序比較函數。

測試分佈

不要用肉眼判斷隨機性。用計數的:

const pos = [0,0,0,0], N = 200000;
for (let i = 0; i < N; i++) {
  const order = shuffle(['a','b','c','d'].map((t,i) => [t,i]));
  pos[order.findIndex(o => o[1] === 0)]++;
}
pos.forEach((c,i) => console.log(i, (c/N*100).toFixed(1) + '%'));

若各位置之間的分佈超過約 3 個百分點,表示有偏差。

使用一個正規的亂數產生器來做測試。 一個自製的線性同餘產生器(LCG)會產生 1-2 個百分點的「誤差」,看起來像真的錯誤,但其實是測試本身的問題。Math.random() 均勻度足夠用來檢查分佈——把自訂產生器留到你需要可重現的亂數種子時再用,並且要另外驗證它。

檢查你顯示給人們的機率

如果你在任何地方顯示機率——百分比、進度條、成功機率——請確認它們與程式實際擲骰的結果一致。用數十萬次模擬與實際擲骰比對:

cred   0  顯示 5.0%/40.0%/55.0%   實際 5.0%/40.0%/55.0%
cred 100  顯示 40.0%/40.0%/20.0%  實際 40.0%/40.1%/20.0%

最大誤差低於 0.5 個百分點,表示顯示沒有騙人。一個顯示的機率卻與實際結果不符,比什麼都不顯示更糟糕,因為人們會根據那個機率做決策。

順便檢查一下

確認一個聲稱的目標是否真的可以達到。一個計數器顯示「3 of 5」告訴玩家目標是 5;但如果 5 只有 0.17% 的機率出現,那麼這個介面就在承諾一個實際上幾乎永遠不會發生的事。為你顯示的每一個里程碑計算真實的機率。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相關技能