对于一本书,您可以使用这种方法;
为每块板生成一个好的 64 位哈希码(谷歌 zobrist 哈希)
有一本字典,您可以在其中使用哈希码作为键。
所以你不存储实际的电路板。如果哈希码匹配,您可以假设它是相同的板(64 位冲突的可能性在小数点后十五位之后开始)。作为最后的检查测试是否允许在棋盘上进行开局,您可以开始了。
然后编写代码将字典保存为一个整体。这段代码可以做到这一点并适用于所有可枚举的容器;
// 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;
}