ブリッジのゲームは、4 人のプレイヤーにランダムに配布される 52 枚の異なるトランプでプレイされ、各プレイヤーは最終的に 13 枚のカードを持ちます。いわゆる「ディール」です。おおよそ2^96以下のブリッジでお値引き可能です。このドキュメントでは、ランダム取引を生成するプログラムの要件を次のように説明しています。
- ソフトウェアは、可能なすべてのブリッジ取引を生成できる必要があります。これは、手動取引でも可能であるためです。
- ソフトウェアは、ボード番号、前のハンド、またはその他の状況に影響されることなく、同じ確率ですべての取引を生成する必要があります。
- セッションで他のすべての取引を見た後でさえ、取引を予測することは不可能であるべきです。
このドキュメントでは、疑似乱数シーケンスの最初の要素を確認することで、使用されるシードを計算できるようになり、ハッカーがその後の取引を予測できるようになるため、疑似乱数ジェネレーターを使用して取引を生成することはできないと述べています。
さらに、ほとんどの疑似乱数ジェネレーターは 32 ビットのシードを使用するため、これらのジェネレーターは、必要な 2^96 ではなく、せいぜい 2^32 の異なるブリッジ ディールを生成できることになり、いわゆる誕生日のパラドックスに従って、 2^32 取引の平方根の後に同じ取引が行われる可能性があります。
ブリッジ ディール生成アプリケーションの要件を説明するドキュメントの著者は、ランダム ディールを生成するために世界中で使用されているプログラムを作成しました。このプログラムは、人間がキーボードでランダムに入力することを使用して 96 ビット シードを生成します。14 年間、このアプローチに欠陥はありませんでした。
必要なシードを生成するために人間の入力を使用する必要がないルーチンを書きたいと思います。
が来るRNGCryptoServiceProvider
。以下のコードを使用してこれを使用し、最初は 1 から 52 の範囲で、次に 1 から 51 の範囲で、1 枚のカードが残るまで乱数を生成しました。
得られたディールのテスト 私は、このコードが同じ確率で可能なあらゆるディールを生み出すことができ、4 人のプレーヤーの 1 人となるカードの確率が 0.25 に等しいことを確信しています。
しかし、RNGCryptoServiceProvider で使用されるシードの強度が不明なため、次のことを考えています。
- このコードは、2^96 の異なる取引を生成することができるか、適応することができます。
- このコードの次の取引は予測できません。
EDIT この質問で前述した乱数を取得する方法には欠陥がありました。これは、このコードが 2^96 の異なる Bridge 取引を生成できるかどうかという主な質問から気をそらします。乱数ジェネレーターを、Stephen Taub と Shawn Farkas が MSDN マガジンで公開したものに置き換えました。
この Web サイトから取得した、1 ~ 52、1 ~ 51、最大 1 ~ 2 の範囲の暗号的に安全な乱数を生成するために使用されるコード
/// <summary>
/// Returns a random number within a specified range.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to <paramref name="minValue"/> and less than <paramref name="maxValue"/>; that is, the range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>. If <paramref name="minValue"/> equals <paramref name="maxValue"/>, <paramref name="minValue"/> is returned.
/// </returns>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
public override Int32 Next(Int32 minValue, Int32 maxValue)
{
if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
if (minValue == maxValue) return minValue;
Int64 diff = maxValue - minValue;
while (true)
{
//The cryptoProvider is of type RNGCryptoServiceProvider.
cryptoProvider.GetBytes(uint32Buffer); //The uint32Buffer has a size of 4 bytes.
UInt32 rand = BitConverter.ToUInt32(uint32Buffer, 0);
Int64 max = (1 + (Int64)UInt32.MaxValue);
Int64 remainder = max % diff;
if (rand < max - remainder)
{
return (Int32)(minValue + (rand % diff));
}
}
}