オープニングブックの場合、このアプローチを使用できます。
すべてのボードについて、適切な 64 ビット ハッシュコードを生成します (google zobrist ハッシュ)
ハッシュコードをキーとして使用する辞書を用意します。
したがって、実際のボードは保管しません。ハッシュコードが一致する場合、同一のボードであると見なすことができます (64 ビットの衝突の可能性は、10 進数の 15 番目以降から始まります)。ボード上で最初の動きが許可されているかどうかの最終チェック テストとして、準備ができているかどうかを確認します。
次に、辞書全体を保存するコードを記述します。このコードはそれを行い、すべての列挙可能なコンテナーに対して機能します。
// save
using (var fs = new FileStream(fileName, FileMode.Create))
{
var bw = new BinaryWriter(fs);
foreach (var kvp in this)
{
kvp.Key.AddToStream(bw);
kvp.Value.AddToStream(bw);
}
}
// load
using (var fs = new FileStream(fileName, FileMode.Open))
{
var fslen = fs.Length;
var br = new BinaryReader(fs);
while (fs.Position < fslen)
{
var k = new Pattern();
var v = new BestMove();
k.ReadFromStream(br);
v.ReadFromStream(br);
Add(k, v);
}
}
これは、64 ビットの Zobrist ハッシュを生成する方法です。これらは、この回答の下部に示されているコード メソッドで後で再利用できるように、永続的な場所に保存する必要があります。ここでは、静的クラスの静的メンバーとして格納されています。
internal static class HashKeys
{
internal static readonly UInt64[,] PieceSquareKeys = new UInt64[64,16];
internal static readonly UInt64[] EnPassantKeys = new UInt64[64];
internal static readonly UInt64 SideToMoveKey;
internal static readonly UInt64 WhiteCastlingKingSideKey;
internal static readonly UInt64 WhiteCastlingQueenSideKey;
internal static readonly UInt64 BlackCastlingKingSideKey;
internal static readonly UInt64 BlackCastlingQueenSideKey;
// Constructor - generates pseudo-random numbers for Zobrist hashing.
// The use of a CSPRNG is a good guaranteee of genuinely random numbers.
static HashKeys()
{
RNGCryptoServiceProvider randomGenerator = new RNGCryptoServiceProvider();
byte[] eightRandomBytes = new byte[8];
try
{
for (Int32 i1 = 0; i1 < 64; i1++)
{
for (Int32 i2 = 0; i1 < 16; i1++)
{
randomGenerator.GetBytes(eightRandomBytes);
PieceSquareKeys[i1, i2] = BitConverter.ToUInt64(eightRandomBytes, 0);
}
randomGenerator.GetBytes(eightRandomBytes);
EnPassantKeys[i1] = BitConverter.ToUInt64(eightRandomBytes, 0);
}
randomGenerator.GetBytes(eightRandomBytes);
SideToMoveKey = BitConverter.ToUInt64(eightRandomBytes, 0);
randomGenerator.GetBytes(eightRandomBytes);
WhiteCastlingKingSideKey = BitConverter.ToUInt64(eightRandomBytes, 0);
randomGenerator.GetBytes(eightRandomBytes);
WhiteCastlingQueenSideKey = BitConverter.ToUInt64(eightRandomBytes, 0);
randomGenerator.GetBytes(eightRandomBytes);
BlackCastlingKingSideKey = BitConverter.ToUInt64(eightRandomBytes, 0);
randomGenerator.GetBytes(eightRandomBytes);
BlackCastlingQueenSideKey = BitConverter.ToUInt64(eightRandomBytes, 0);
}
finally
{
randomGenerator.Dispose();
}
}
}
これは、ボードの位置を表す 64 ビットの Zobrish ハッシュを生成する方法です (移動する側、キャスリング権、アンパッサンなどを含む)。
// Init Zobrist position hash, used in transposition table and draw detection.
// This will be incrementally updated during move make/unmake.
internal static UInt64 InitPositionHash(byte[] squares, ComplexProperties propertyStore, byte sideToMove)
{
UInt64 positionHash = 0;
// Calculate piece/square hashes.
for (Int32 i = 0; i < 64; i++)
{
if (squares[i] != Constants.EMPTY)
{
positionHash ^= HashKeys.PieceSquareKeys[i, squares[i]];
}
}
// Add side to move only if Black.
if (sideToMove == Constants.BLACK)
{
positionHash ^= HashKeys.SideToMoveKey;
}
// Add en-passant square if applicable.
if (propertyStore.EpSquare != 0)
{
positionHash ^= HashKeys.EnPassantKeys[propertyStore.EpSquare];
}
// White castling.
switch (propertyStore.WhiteCastlingStatus)
{
case Constants.EnumCastlingStatus.CAN_CASTLE_BOTH:
positionHash ^= HashKeys.WhiteCastlingKingSideKey;
positionHash ^= HashKeys.WhiteCastlingQueenSideKey;
break;
case Constants.EnumCastlingStatus.CAN_CASTLE_OO:
positionHash ^= HashKeys.WhiteCastlingKingSideKey;
break;
case Constants.EnumCastlingStatus.CAN_CASTLE_OOO:
positionHash ^= HashKeys.WhiteCastlingQueenSideKey;
break;
case Constants.EnumCastlingStatus.CANT_CASTLE:
break;
default:
Debug.Assert(false, "White has an invalid castling status!");
break;
}
// Black castling.
switch (propertyStore.BlackCastlingStatus)
{
case Constants.EnumCastlingStatus.CAN_CASTLE_BOTH:
positionHash ^= HashKeys.BlackCastlingKingSideKey;
positionHash ^= HashKeys.BlackCastlingQueenSideKey;
break;
case Constants.EnumCastlingStatus.CAN_CASTLE_OO:
positionHash ^= HashKeys.BlackCastlingKingSideKey;
break;
case Constants.EnumCastlingStatus.CAN_CASTLE_OOO:
positionHash ^= HashKeys.BlackCastlingQueenSideKey;
break;
case Constants.EnumCastlingStatus.CANT_CASTLE:
break;
default:
Debug.Assert(false, "Black has an invalid castling status!");
break;
}
return positionHash;
}