ランダム選択ツール
抽選、選択、ピックのための公平なランダム選択ツール
ランダム抽選とは?
ランダムピッカーは、候補リストから人が選ばずに 1 つの項目をランダムに決めるツールです。授業の指名、会議の発表順、軽い抽選、タスク割り当て、昼食候補、チームのウォームアップなど、中立的な選択があると納得しやすい場面で役立ちます。このページは 1 行 1 候補のリスト、抽選アニメーション、ローカル履歴、重複なし抽選に対応し、選ばれた項目を残りの候補から外すこともできます。ランダム性は統計的な公平さに役立ちますが、本人確認、入力内の重複名の検出、監査証拠の作成は行いません。公式抽選、資格確認、賞品配布では、記録と規則のある手順を使ってください。
使い方
使い方
- テキストボックスに選択肢を1行ずつ入力
- 抽選するアイテム数を設定
- 重複を許可するかどうかを選択
- 「抽選開始」ボタンをクリック
- 右側に結果を表示
公平な抽選のヒント
- 候補者を1行ずつ入力し、意図しない空行や重複を削除してください(重複を許可する場合を除く)。
- 公開する抽選では、開始前にシード値、重複ルール、再抽選ルールを決めておくと、結果を説明しやすくなります。
利用シーン
仕組み
ランダムピッカーはWeb Crypto API(W3C、WHATWG)、具体的にはcrypto.getRandomValues(typedArray)を基盤としています。これはブラウザで公開される唯一の暗号学的に安全な乱数源です。内部的には、ブラウザはOSのCSPRNGを呼び出します:WindowsではCryptGenRandom(Windows 10以降はAES-256 CTR-DRBGモード)、Linuxではgetrandom(2)(カーネルの/dev/urandomと同じChaCha20ベースのプールから読み取り)、macOSではSecRandomCopyBytes、iOS・Android・BSDでも同等の機構です。この出力は、キー生成、ノンス、ソルト、IV、予測可能性が問題となる箇所に適しています。 「暗号学的グレード」という区別は重要です。V8のMath.random()はxorshift128+(高速だが低エントロピーのアルゴリズム)を使用し、[0, 1)の64ビット浮動小数点数を返します。攻撃者がいくつかの出力を観察すれば、原理的に128ビット状態を再構成し、将来のすべての値を予測できます。SpiderMonkeyやJavaScriptCoreでも同様です。このため、結果が推測不可能でなければならない用途——当選者の公平な選定、トークン、ワンタイムパスワード、カードゲームの取引、監査サンプル——にはMath.random()は不適切です。crypto.getRandomValues(typedArray)がそれらの唯一の選択肢です。 均一な32ビット整数を[0, N)の均一なインデックスに、モジュロバイアスなしにマッピングすることは、正しい実装と壊れた実装を分ける2つ目のエンジニアリングの詳細です。単純にidx = randomUint32 % Nとすると誤りです:Nが2³²を割り切れない場合、最初の2³² mod N個の値がわずかに選ばれやすくなります。正しいアルゴリズムは棄却サンプリングです:limit = 2³² - (2³² mod N)を計算し、32ビット値rを引きます。r >= limitなら再描画し、そうでなければr % Nを返します。バイアスはO(N / 2³²)からゼロになります。N = 2またはNが2の累乗の場合、モジュロは正確ですが、棄却サンプリングが安全なデフォルトであり、平均で最大1回の再描画で済み(常に終了します)。 ピッカーは結果をバージョン付きキーでlocalStorageに保存するため、ページリロード後もセッションが維持され、抽選履歴を確認できます。履歴は暗号化も署名もされていません——ローカルで、非機密であり、容易にクリアできます。重複なしモードでは、Fisher-Yates部分シャッフルを使用した復元なし抽出を行います:Nのうちのステップkで、要素kを[k, N)から均一に選んだ要素と交換し、要素kを抽出済みとして固定します。これはO(N)時間、O(1)追加空間で、すべての順列に等しい確率を与えます。(単純な「N回描画し、重複を棄却」も正しく動作しますが、O(N²)で長いセッションで停滞する可能性があります。) 重み付き選択(各選択肢に独自の確率がある場合)の標準アルゴリズムは、プレフィックスサム配列による逆CDFサンプリングです:重みのプレフィックスサムを構築し、[0, total)の均一実数を描画し、prefix[i] >= uとなる最小のiを二分探索します。描画ごとにO(N log N)であり、プレフィックスサムは変更ごとに1回構築されます。Alias法(Walker-Vose)はO(N)のセットアップコストで描画ごとにO(1)を実現し、Nが大きく分布が固定されている場合にのみ有効です。
- 乱数源:crypto.getRandomValues(typedArray)——ブラウザで唯一の暗号学的に安全なRNG、OSレベルのCSPRNGで裏付け(Windows 10+ではAES-256 CTR-DRBG、Linux/macOS/iOS/AndroidではChaCha20)。
- Math.random()はV8ではxorshift128+(他のエンジンでは変種):高速だが予測可能。公平な選定、トークン、OTP、監査サンプルには絶対に使用しない——視覚ノイズ、アニメーション、非セキュリティサンプリングのみに使用。
- バイアスのないインデックスマッピング:モジュロではなく棄却サンプリング。limit = 2³² - (2³² mod N)を計算し、ランダムuint32がlimit以上なら再描画、そうでなければr % Nを返す。短い範囲のインデックスがより頻繁に出現する古典的な「モジュロバイアス」を回避。
- 重複なし抽選はFisher-Yates部分シャッフルをO(N)時間、O(1)空間で使用:ステップkで要素kを[k, N)の均一な要素と交換してからkを固定。すべての順列が等確率。
- 重み付き選択は逆CDFサンプリングを使用:重みのプレフィックスサムを1回構築し、[0, total)の均一実数を描画し、prefix[i] >= uとなる最小値を二分探索。描画ごとにO(log N)。
- 抽選履歴はバージョン付きキーでlocalStorageに永続化され、ページリロード後もセッションが維持。履歴はローカル専用でセキュリティ上機密ではない——完了後にUIからクリア可能。
- Fisher-Yatesと「棄却付きN回描画」の比較:分布はどちらも正しいが、Fisher-Yatesは合計O(N)・メモリO(1)なのに対し、単純な棄却は最悪の場合O(N²)(長いリストの終盤で多数の重複が発生)。
- 出力範囲と型:getRandomValuesはInt8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、BigInt64Array、BigUint64Arrayを受け付ける——ページでは常にUint32Arrayを使用してインデックスマッピングステップに供給。
使用例
候補リストからの重複なし抽選
入力リスト(1 行に 1 件):
Alice
Bob
Charlie
David
Eve
Frank
重複を許可: OFF 抽選数: 3
結果:
#1: Charlie
#2: Alice
#3: Frank
(Bob、David、Eve はプール内に残る)
ページは Uint32Array に対して crypto.getRandomValues() を呼び出し、抽選ごとに
[0, n) の一様な整数を生成します(n は残り候補数)。各回ごとにすべての名前が等しく
1/n の確率を持ち、選ばれたインデックスはアニメーション開始前に確定しています。重複ありとタイムスタンプ付き履歴
入力リスト(1 行に 1 件):
Head
Tails
重複を許可: ON 抽選数: 5
結果:
#1 (14:23:01): Head
#2 (14:23:01): Tails
#3 (14:23:01): Head
#4 (14:23:01): Head
#5 (14:23:01): Tails
重複モードでは同じエントリが連続で選ばれる可能性があり、プールも縮みません。
各レコードに抽選タイムスタンプが追加されるため、同じ候補リストを複数ラウンド
再利用しつつ、各抽選が起きた正確な時刻を履歴で確認できます。レコードは候補リスト
とは別にクリアしてください。異なる localStorage キーに保存されています。選択ロジックの JavaScript スニペット
// Web Crypto (CSPRNG) を使って [0, n) から 1 つのインデックスを選ぶ
function pickIndex(n) {
// crypto.getRandomValues は一様な 32 ビット値を返す。リスト抽選では n は最大でも
// 数千程度なので、modulo n は安全(2^32 / n が大きく、modulo バイアスは無視できる)。
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
return buf[0] % n;
}
// pickIndex(6) -> 例: 4 (上の例の Charlie)
// pickIndex(2) -> 0 または 1 (Head または Tails)
//
// 注: n が 2^32 に近づくほど巨大なプールでは、modulo バイアスを除くために棄却サンプリングを使用:
// const limit = Math.floor(0xFFFFFFFF / n) * n;
// let r; do { crypto.getRandomValues(buf); r = buf[0]; } while (r >= limit);1,000 回抽選の公平性チェック
リスト: ['A', 'B', 'C', 'D'] (4 エントリ、期待割合 25.0%)
抽選数: 1,000 重複を許可: ON
観測値:
A: 247 (24.7%)
B: 256 (25.6%)
C: 248 (24.8%)
D: 249 (24.9%)
crypto.getRandomValues を使った 1,000 回の抽選では、各エントリは期待割合の
+/- 約 3 ポイント以内に収まるはずです。それより大きく外れる場合(例: 1 つが 35%)
通常は実装が Math.random() を呼び出しているか、modulo の使い方が誤っています。
規制対象の抽選では、ソースリスト、乱数シード源(ブラウザ/OS のエントロピー)、
抽選タイムスタンプ、立会い署名を保存してください。localStorage は永続的な記録
システムではありません。よくある質問
選出は本当にランダムですか?
はい。Web Crypto API の crypto.getRandomValues を使用しており、暗号学的に強度の高い乱数を生成します。重みを設定しない限り、各選択肢は等確率で選ばれます。
同じ選択肢が連続して選ばれることはありますか?
はい。独立したランダム選択ではそれが自然な挙動です。5 個の選択肢があれば、2 回連続で同じものが選ばれる確率は 1/5 = 20% になります。重複を避けたい場合は「選出後に削除」を有効にすれば、リストが空になるまで非復元抽出を行います。
「N 個まとめて選出」はどう処理されますか?
デフォルトでは非復元抽出となり、1 回の N 個抽選で各項目は最大 1 回しか選ばれません。重複を許容する場合(例:1 人に N 個のタスクを割り当てる)は「復元抽出」を有効にしてください。非復元モードでは N が選択肢の総数を超えることはできません。
選出に重み付けはできますか?
一部のバージョンでは選択肢ごとの重み付けに対応しています(例:選択肢 A の重み 3、B の重み 1 → A が 3 倍選ばれやすい)。ページ側で重みを確率に正規化します。重みを設定しない場合、すべての選択肢が等確率となります。
なぜ「直感」で選ぶよりも公平なのですか?
人間はランダム選択が苦手で、直近の選択を避けたり、目立つ選択肢を選びすぎたり、知っている名前を無意識に選ぶ傾向があります。コンピュータによる選出はこうした偏りを排除するため、抽選的な決定を参加者がより納得しやすくなります。
リストは保存されますか?
一部のバージョンでは localStorage に保存されるため、同じブラウザならリストは残ります。タブを閉じたりブラウザを切り替えたりすると、エクスポートしていない限り失われます。サーバーへのアップロードは行われません。
公式の抽選やくじに使用してもよいですか?
いいえ。法的なラッフル、宝くじ、ギャンブルの抽選には監査可能なランダム手順が求められ、多くの場合は物理的な装置や認定済みの RNG ハードウェアが必要です。汎用的な Web ツールには文書化や監査がないため、社内抽選や非公式な抽選にのみ利用してください。