抽選・くじ引き(当選者・順番決め・グループ分け)

抽選のしかた

名簿の全員を並べ替え、上から N 人を当選にします。番号は当選した順です。

人
シード(抽選の元になる言葉)

名簿を確定した後に出る公開の値(指標の終値など)をシードにすると、結果を選んでいないことを示せます。

    1. 公平な抽選のやり方

    このツールは、名簿とシード(抽選の元になる言葉)が同じなら、誰がいつやっても同じ結果になります。これを使って抽選が公平だったと示すには、次の順番を守ります。

    1. 名簿を確定し、名簿の指紋(後述)を参加者に伝える
    2. シードを決める。名簿を確定した時点ではまだ誰にも分からず、主催者が左右できない公開の値にする(例:抽選日の翌営業日に出る、決まった指標の終値)
    3. その値が出たら、それをシードにして「自分で決める」で抽選する

    2で使う値は、名簿の指紋と一緒に「どの値を、どの日のものを、どう書いて入れるか」まで先に伝えておきます。書き方(桁区切りを入れるかなど)を後から選べると、書き方の数だけ結果を試せてしまうためです。結果をコピーすると、シードと名簿の指紋が付きます。

    順番を守らないと、公平さは示せません。理由は2つあります。

    • シードを先に公開すると、名簿を変えて結果を選べる。主催者はシードを知ってから、名簿の順番や名前の書き方を変えて、望む結果が出るまで手元で試せます。名簿を先に確定して指紋を伝えておけば、後から名簿を変えていないことを示せます。
    • 名簿の確定後でも、主催者がシードを選べるなら、何通りも試して選べる。主催者が自分でシードを考える場合、手元でいくつものシードを試し、都合のよい結果が出たものを「最初から決めていたシード」として出せます。名簿を確定した時点では誰にも分からない値を使うのは、このためです。

    自動のシードでも、やり直していないことは示せません。自動のシードは押すたびに新しく作られるので、何度も押して都合のよい結果を選ぶこともできてしまいます。自動のシードで出した結果は、誰でも同じ結果を再現できることは示せますが、それが1回目の抽選だったかどうかは示せません。身内の順番決めなど、そこまで要らない場面で使ってください。

    2. 3つの方法の違い

    「当選者を選ぶ」「順番を決める」「グループに分ける」は、どれもまず名簿の全員を同じ手順で並べ替えます。違うのは、その並びをどう使うかだけです。例のボタンで入る10人の名簿とシード yoskly では、次の結果になります。

    方法結果
    順番を決める1. 田中 2. 高橋 3. 小林 4. 中村 5. 渡辺 6. 加藤 7. 鈴木 8. 佐藤 9. 伊藤 10. 山本
    当選者を選ぶ(3人)1. 田中 2. 高橋 3. 小林
    グループに分ける(3組)1組:田中・中村・鈴木・山本
    2組:高橋・渡辺・佐藤
    3組:小林・加藤・伊藤

    当選者は、順番の上から3人と同じです。順番の1〜3番目は田中・高橋・小林で、当選者の3人もこの順です。同じ名簿とシードなら、方法を変えても結果どうしが食い違いません。

    グループは、順番の上から1組・2組・3組・1組…と1人ずつ配っています。

    順番名前組
    1田中1組
    2高橋2組
    3小林3組
    4中村1組
    5渡辺2組
    6加藤3組
    7鈴木1組
    8佐藤2組
    9伊藤3組
    10山本1組

    1組には順番の1・4・7・10番目の田中・中村・鈴木・山本が入るので、1組だけが4人になります。

    3. 結果を確かめる方法

    コピーした結果には、シードと名簿の指紋が付いています。

    【抽選】当選 3人 / 10人
    1. 田中
    2. 高橋
    3. 小林
    シード: yoskly
    名簿の指紋: d730dd4e

    確かめる人は、同じ名簿をこのツールに入れ、「自分で決める」で同じシードを入れて抽選します。同じ結果になれば、その名簿とシードから出た結果です。

    名簿の指紋

    名簿の指紋は、名簿が同じかどうかを確かめるための短い文字列です。名前の順番や書き方が1文字でも違うと、別の値になります。たとえば「佐藤・鈴木・高橋・田中・伊藤・渡辺・山本・中村・小林・加藤」の10人の名簿は d730dd4e です。指紋が違うのに結果も違う場合は、名簿が違っています。

    各行の前後の空白と空行は取り除いてから計算するので、空白や空行の違いでは指紋は変わりません。名前の全角・半角は区別します。

    シードから乱数を作る手順

    シードは、全角の英数字を半角にし、前後の空白を取ってから使います。yoskly と yoskly は同じシードです。大文字と小文字は区別するので、Yoskly は別のシードになり、結果も変わります。

    整えたシードは SHA-256(データから決まった長さの値を作る標準の計算方法)にかけ、その先頭を乱数の初期値にします。SHA-256 は標準の方法なので、ほかの道具でも途中の値を確かめられます。たとえば yoskly の SHA-256 は a47bcb3e… で始まります。

    printf '%s' yoskly | sha256sum

    乱数を作る方法には xoshiro128** を使っています。作者が公開している方法と同じ手順で計算しています。

    4. ランダムに並べる正しい方法

    名簿をランダムに並べ替えるには、Fisher–Yates(フィッシャー–イェーツ)という方法を使います。末尾から順に、まだ決まっていない範囲から1つを選んで入れ替えていきます。

    for (let i = names.length - 1; i >= 1; i--) {
      const j = randomInt(i + 1); // 0〜i の整数
      [names[i], names[j]] = [names[j], names[i]];
    }

    この方法なら、どの並び方も同じ確率で出ます。4人の名簿を何度も並べ替えると、24通りの並び方がどれもほぼ同じ回数ずつ出ます。

    よく見かける次の書き方は、偏ります。

    names.sort(() => Math.random() - 0.5);

    並べ替えの関数は、比べた結果に矛盾がないことを前提に作られています。比べるたびに答えが変わると、並び方によって出やすさに差が出ます。偏りの大きさはブラウザの並べ替えの作り方によって違います。

    このツールでは、当選者・順番・グループのどれも、まず名簿全体をこの方法で並べ替えてから決めます。当選者は並びの先頭からの人数分なので、同じ名簿とシードなら、当選者は順番の先頭と一致します。

    5. 余りを取るだけだと偏る

    乱数から「0〜n−1 の整数」を作るとき、乱数を n で割った余りを使うだけでは偏ることがあります。

    たとえば 0〜255 の乱数を 3 で割った余りを使うと、余りが 0 になるのは86通り、1 と 2 になるのは85通りずつです。256 が 3 で割り切れないため、0 だけが1通り多くなります。

    このツールでは、割り切れない端の部分が出たら捨てて、乱数を引き直します。上の例なら、255 が出たら引き直し、0〜254 の余りだけを使います。0・1・2 はどれも85通りずつになります。

    6. グループの人数

    グループに分けるときは、並べ替えた名簿の1人目を1組、2人目を2組…と順に配っていきます。割り切れないときは、前の組から順に1人多くなります。どの組の人数も、差は1人以内です。

    • 10人を3組に分ける → 4人・3人・3人
    • 10人を4組に分ける → 3人・3人・2人・2人

    人数の多い組を後ろにしたい場合は、組の名前を読み替えてください。

    名前はどこにも送りません

    名簿・シード・抽選はすべてこのページの中で処理します。名前をサーバーに送ったり、URL に含めたりはしません。