Skip to content

Commit

Permalink
Cleanup and use switch method
Browse files Browse the repository at this point in the history
  • Loading branch information
eduherminio committed Jan 2, 2024
1 parent 5bad766 commit 90e7079
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 133 deletions.
74 changes: 0 additions & 74 deletions src/Lynx.Benchmark/CastleHash.cs

This file was deleted.

147 changes: 147 additions & 0 deletions src/Lynx.Benchmark/ZobristHash_Castle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
*
*/

using BenchmarkDotNet.Attributes;
using Lynx.Model;
using System.Runtime.CompilerServices;

namespace Lynx.Benchmark;
public class ZobristHash_Castle : BaseBenchmark
{
public static IEnumerable<Position> Data => new[] {
new Position(Constants.InitialPositionFEN),
new Position(Constants.TrickyTestPositionFEN),
new Position(Constants.TrickyTestPositionReversedFEN),
new Position(Constants.CmkTestPositionFEN),
new Position(Constants.ComplexPositionFEN),
new Position(Constants.KillerTestPositionFEN),
};

[Benchmark(Baseline = true)]
[ArgumentsSource(nameof(Data))]
public long Naive(Position position) => CalculateMethod(position.Castle);

[Benchmark]
[ArgumentsSource(nameof(Data))]
public long Dictionary(Position position) => DictionaryMethod(position.Castle);

[Benchmark]
[ArgumentsSource(nameof(Data))]
public long Switch(Position position) => SwitchMethod(position);

private static readonly long[,] _table = Initialize();

private static readonly long WK_Hash = _table[(int)BoardSquare.a8, (int)Piece.p];
private static readonly long WQ_Hash = _table[(int)BoardSquare.b8, (int)Piece.p];
private static readonly long BK_Hash = _table[(int)BoardSquare.c8, (int)Piece.p];
private static readonly long BQ_Hash = _table[(int)BoardSquare.d8, (int)Piece.p];

private static readonly Dictionary<byte, long> _castleHashDictionary = new()
{
[0] = 0, // - | -
[(byte)CastlingRights.WK] = WK_Hash, // K | -
[(byte)CastlingRights.WQ] = WQ_Hash, // Q | -
[(byte)CastlingRights.BK] = BK_Hash, // - | k
[(byte)CastlingRights.BQ] = BQ_Hash, // - | q

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ] = WK_Hash ^ WQ_Hash, // KQ | -
[(byte)CastlingRights.WK | (byte)CastlingRights.BK] = WK_Hash ^ BK_Hash, // K | k
[(byte)CastlingRights.WK | (byte)CastlingRights.BQ] = WK_Hash ^ BQ_Hash, // K | q
[(byte)CastlingRights.WQ | (byte)CastlingRights.BK] = WQ_Hash ^ BK_Hash, // Q | k
[(byte)CastlingRights.WQ | (byte)CastlingRights.BQ] = WQ_Hash ^ BQ_Hash, // Q | q
[(byte)CastlingRights.BK | (byte)CastlingRights.BQ] = BK_Hash ^ BQ_Hash, // - | kq

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK] = WK_Hash ^ WQ_Hash ^ BK_Hash, // KQ | k
[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BQ] = WK_Hash ^ WQ_Hash ^ BQ_Hash, // KQ | q
[(byte)CastlingRights.WK | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = WK_Hash ^ BK_Hash ^ BQ_Hash, // K | kq
[(byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = WQ_Hash ^ BK_Hash ^ BQ_Hash, // Q | kq

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = // KQ | kq
WK_Hash ^ WQ_Hash ^ BK_Hash ^ BQ_Hash
};

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static long CalculateMethod(byte castle)
{
long combinedHash = 0;

if ((castle & (int)CastlingRights.WK) != default)
{
combinedHash ^= _table[(int)BoardSquare.a8, (int)Piece.p]; // a8
}

if ((castle & (int)CastlingRights.WQ) != default)
{
combinedHash ^= _table[(int)BoardSquare.b8, (int)Piece.p]; // b8
}

if ((castle & (int)CastlingRights.BK) != default)
{
combinedHash ^= _table[(int)BoardSquare.c8, (int)Piece.p]; // c8
}

if ((castle & (int)CastlingRights.BQ) != default)
{
combinedHash ^= _table[(int)BoardSquare.d8, (int)Piece.p]; // d8
}

return combinedHash;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long SwitchMethod(Position position)
{
return position.Castle switch
{
0 => 0, // - | -

(byte)CastlingRights.WK => WK_Hash, // K | -
(byte)CastlingRights.WQ => WQ_Hash, // Q | -
(byte)CastlingRights.BK => BK_Hash, // - | k
(byte)CastlingRights.BQ => BQ_Hash, // - | q

(byte)CastlingRights.WK | (byte)CastlingRights.WQ => WK_Hash ^ WQ_Hash, // KQ | -
(byte)CastlingRights.WK | (byte)CastlingRights.BK => WK_Hash ^ BK_Hash, // K | k
(byte)CastlingRights.WK | (byte)CastlingRights.BQ => WK_Hash ^ BQ_Hash, // K | q
(byte)CastlingRights.WQ | (byte)CastlingRights.BK => WQ_Hash ^ BK_Hash, // Q | k
(byte)CastlingRights.WQ | (byte)CastlingRights.BQ => WQ_Hash ^ BQ_Hash, // Q | q
(byte)CastlingRights.BK | (byte)CastlingRights.BQ => BK_Hash ^ BQ_Hash, // - | kq

(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK => WK_Hash ^ WQ_Hash ^ BK_Hash, // KQ | k
(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BQ => WK_Hash ^ WQ_Hash ^ BQ_Hash, // KQ | q
(byte)CastlingRights.WK | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => WK_Hash ^ BK_Hash ^ BQ_Hash, // K | kq
(byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => WQ_Hash ^ BK_Hash ^ BQ_Hash, // Q | kq

(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => // KQ | kq
WK_Hash ^ WQ_Hash ^ BK_Hash ^ BQ_Hash,

_ => new()
};
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long DictionaryMethod(byte castle) => _castleHashDictionary[castle];

/// <summary>
/// Initializes Zobrist table (long[64, 12])
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long[,] Initialize()
{
var zobristTable = new long[64, 12];
var randomInstance = new Random(int.MaxValue);

for (int squareIndex = 0; squareIndex < 64; ++squareIndex)
{
for (int pieceIndex = 0; pieceIndex < 12; ++pieceIndex)
{
zobristTable[squareIndex, pieceIndex] = randomInstance.NextInt64();
}
}

return zobristTable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
using System.Runtime.CompilerServices;

namespace Lynx.Benchmark;
public class PieceHash : BaseBenchmark
public class ZobristHash_EnPassant : BaseBenchmark
{
private static readonly long[,] _table = Initialize();

Expand Down
88 changes: 30 additions & 58 deletions src/Lynx/ZobristTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public static class ZobristTable
{
private static readonly long[,] _table = Initialize();

private static readonly long WK_Hash = _table[(int)BoardSquare.a8, (int)Piece.p];
private static readonly long WQ_Hash = _table[(int)BoardSquare.b8, (int)Piece.p];
private static readonly long BK_Hash = _table[(int)BoardSquare.c8, (int)Piece.p];
private static readonly long BQ_Hash = _table[(int)BoardSquare.d8, (int)Piece.p];

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long PieceHash(int boardSquare, int piece) => _table[boardSquare, piece];

Expand Down Expand Up @@ -49,35 +54,6 @@ public static long SideHash()
return _table[(int)BoardSquare.h8, (int)Piece.p];
}

internal static readonly long WK_Hash = _table[(int)BoardSquare.a8, (int)Piece.p];
internal static readonly long WQ_Hash = _table[(int)BoardSquare.b8, (int)Piece.p];
internal static readonly long BK_Hash = _table[(int)BoardSquare.c8, (int)Piece.p];
internal static readonly long BQ_Hash = _table[(int)BoardSquare.d8, (int)Piece.p];

private static readonly Dictionary<byte, long> _castleHashDictionary = new()
{
[0] = 0, // - | -
[(byte)CastlingRights.WK] = WK_Hash, // K | -
[(byte)CastlingRights.WQ] = WQ_Hash, // Q | -
[(byte)CastlingRights.BK] = BK_Hash, // - | k
[(byte)CastlingRights.BQ] = BQ_Hash, // - | q

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ] = WK_Hash ^ WQ_Hash, // KQ | -
[(byte)CastlingRights.WK | (byte)CastlingRights.BK] = WK_Hash ^ BK_Hash, // K | k
[(byte)CastlingRights.WK | (byte)CastlingRights.BQ] = WK_Hash ^ BQ_Hash, // K | q
[(byte)CastlingRights.WQ | (byte)CastlingRights.BK] = WQ_Hash ^ BK_Hash, // Q | k
[(byte)CastlingRights.WQ | (byte)CastlingRights.BQ] = WQ_Hash ^ BQ_Hash, // Q | q
[(byte)CastlingRights.BK | (byte)CastlingRights.BQ] = BK_Hash ^ BQ_Hash, // - | kq

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK] = WK_Hash ^ WQ_Hash ^ BK_Hash, // KQ | k
[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BQ] = WK_Hash ^ WQ_Hash ^ BQ_Hash, // KQ | q
[(byte)CastlingRights.WK | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = WK_Hash ^ BK_Hash ^ BQ_Hash, // K | kq
[(byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = WQ_Hash ^ BK_Hash ^ BQ_Hash, // Q | kq

[(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ] = // KQ | kq
WK_Hash ^ WQ_Hash ^ BK_Hash ^ BQ_Hash
};

/// <summary>
/// Uses <see cref="Piece.p"/> and
/// <see cref="BoardSquare.a8"/> for <see cref="CastlingRights.WK"/>, <see cref="BoardSquare.b8"/> for <see cref="CastlingRights.WQ"/>
Expand All @@ -88,36 +64,32 @@ public static long SideHash()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long CastleHash(byte castle)
{
System.Diagnostics.Debug.Assert(_castleHashDictionary[castle] == CalculateCastleHash(castle));

return _castleHashDictionary[castle];
}

internal static long CalculateCastleHash(byte castle)
{
long combinedHash = 0;

if ((castle & (int)CastlingRights.WK) != default)
{
combinedHash ^= _table[(int)BoardSquare.a8, (int)Piece.p]; // a8
}

if ((castle & (int)CastlingRights.WQ) != default)
{
combinedHash ^= _table[(int)BoardSquare.b8, (int)Piece.p]; // b8
}

if ((castle & (int)CastlingRights.BK) != default)
return castle switch
{
combinedHash ^= _table[(int)BoardSquare.c8, (int)Piece.p]; // c8
}

if ((castle & (int)CastlingRights.BQ) != default)
{
combinedHash ^= _table[(int)BoardSquare.d8, (int)Piece.p]; // d8
}

return combinedHash;
0 => 0, // - | -

(byte)CastlingRights.WK => WK_Hash, // K | -
(byte)CastlingRights.WQ => WQ_Hash, // Q | -
(byte)CastlingRights.BK => BK_Hash, // - | k
(byte)CastlingRights.BQ => BQ_Hash, // - | q

(byte)CastlingRights.WK | (byte)CastlingRights.WQ => WK_Hash ^ WQ_Hash, // KQ | -
(byte)CastlingRights.WK | (byte)CastlingRights.BK => WK_Hash ^ BK_Hash, // K | k
(byte)CastlingRights.WK | (byte)CastlingRights.BQ => WK_Hash ^ BQ_Hash, // K | q
(byte)CastlingRights.WQ | (byte)CastlingRights.BK => WQ_Hash ^ BK_Hash, // Q | k
(byte)CastlingRights.WQ | (byte)CastlingRights.BQ => WQ_Hash ^ BQ_Hash, // Q | q
(byte)CastlingRights.BK | (byte)CastlingRights.BQ => BK_Hash ^ BQ_Hash, // - | kq

(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK => WK_Hash ^ WQ_Hash ^ BK_Hash, // KQ | k
(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BQ => WK_Hash ^ WQ_Hash ^ BQ_Hash, // KQ | q
(byte)CastlingRights.WK | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => WK_Hash ^ BK_Hash ^ BQ_Hash, // K | kq
(byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => WQ_Hash ^ BK_Hash ^ BQ_Hash, // Q | kq

(byte)CastlingRights.WK | (byte)CastlingRights.WQ | (byte)CastlingRights.BK | (byte)CastlingRights.BQ => // KQ | kq
WK_Hash ^ WQ_Hash ^ BK_Hash ^ BQ_Hash,

_ => throw new($"Unexpected castle encoded number: {castle}")
};
}

/// <summary>
Expand Down
29 changes: 29 additions & 0 deletions tests/Lynx.Test/ZobristTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,35 @@ public void CastleHash(string fen)

var castleHash = ZobristTable.CastleHash(position.Castle);

Assert.AreEqual(CalculateCastleHash(position.Castle)castleHash);

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (ubuntu-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (ubuntu-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (ubuntu-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (ubuntu-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / winning-at-chess (ubuntu-latest, WinningAtChess_FixedTime)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / winning-at-chess (ubuntu-latest, WinningAtChess_FixedTime)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (ubuntu-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (ubuntu-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (ubuntu-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (macOS-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (macOS-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, windows-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Release, windows-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (windows-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (windows-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (windows-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / long-running-tests (windows-latest, LongRunning)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, windows-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / fast-tests (Debug, windows-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (macOS-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / other-tests (macOS-latest, Configuration)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (macOS-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (windows-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (windows-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (macOS-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / perft-tests (macOS-latest, Perft)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (windows-latest)

Syntax error, ',' expected

Check failure on line 99 in tests/Lynx.Test/ZobristTableTest.cs

View workflow job for this annotation

GitHub Actions / benchmark (windows-latest)

Syntax error, ',' expected

Assert.AreEqual(positionWithoutCastlingRightsHash, positionHash ^ castleHash);
}

private static long CalculateCastleHash(byte castle)
{
long combinedHash = 0;

if ((castle & (int)CastlingRights.WK) != default)
{
combinedHash ^= _zobristTable[(int)BoardSquare.a8, (int)Piece.p]; // a8
}

if ((castle & (int)CastlingRights.WQ) != default)
{
combinedHash ^= _zobristTable[(int)BoardSquare.b8, (int)Piece.p]; // b8
}

if ((castle & (int)CastlingRights.BK) != default)
{
combinedHash ^= _zobristTable[(int)BoardSquare.c8, (int)Piece.p]; // c8
}

if ((castle & (int)CastlingRights.BQ) != default)
{
combinedHash ^= _zobristTable[(int)BoardSquare.d8, (int)Piece.p]; // d8
}

return combinedHash;
}
}

0 comments on commit 90e7079

Please sign in to comment.