From 4721221f7dfbb66cfdc12916f5fc09d1c5c05212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20C=C3=A1ceres?= Date: Wed, 20 Nov 2024 18:26:42 +0100 Subject: [PATCH] Refactor and simplify Perft --- src/Lynx.Dev/Program.cs | 15 +++-------- src/Lynx/Perft.cs | 41 +++++++++++-------------------- src/Lynx/UCIHandler.cs | 14 +++++------ tests/Lynx.Test/PerftTest.cs | 2 +- tests/Lynx.Test/PerftTestSuite.cs | 2 +- 5 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/Lynx.Dev/Program.cs b/src/Lynx.Dev/Program.cs index 7488131b2..9d1510a09 100644 --- a/src/Lynx.Dev/Program.cs +++ b/src/Lynx.Dev/Program.cs @@ -561,21 +561,14 @@ static void _42_Perft() for (int depth = 0; depth < 7; ++depth) { - var sw = new Stopwatch(); - sw.Start(); - var result = Perft.Results(pos, depth); - sw.Stop(); - - Perft.PrintPerftResult(depth, result, Console.WriteLine); + Perft.RunPerft(pos, depth, Console.WriteLine); } } static void _43_Divide() { - var result = Perft.Divide(new Position(Constants.InitialPositionFEN), 5, Console.WriteLine); - Perft.PrintPerftResult(5, result, Console.WriteLine); - result = Perft.Divide(new Position(TrickyPosition), 5, Console.WriteLine); - Perft.PrintPerftResult(5, result, Console.WriteLine); + Perft.RunDivide(new Position(Constants.InitialPositionFEN), 5, Console.WriteLine); + Perft.RunDivide(new Position(TrickyPosition), 5, Console.WriteLine); } static void _44_ParseUCI() @@ -1108,7 +1101,7 @@ static void TesSize(int size) static void UnmakeMove() { var pos = new Position("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq"); - var a = Perft.ResultsImpl(pos, 1, default); + var a = Perft.PerftRecursiveImpl(pos, 1, default); TestMoveGen(Constants.InitialPositionFEN); TestMoveGen(Constants.TTPositionFEN); diff --git a/src/Lynx/Perft.cs b/src/Lynx/Perft.cs index 75e83892a..0507b40cf 100644 --- a/src/Lynx/Perft.cs +++ b/src/Lynx/Perft.cs @@ -10,35 +10,35 @@ namespace Lynx; /// public static class Perft { - public static (long Nodes, double ElapsedSeconds) Results(Position position, int depth) + public static void RunPerft(Position position, int depth, Action write) { var sw = new Stopwatch(); sw.Start(); - var nodes = ResultsImpl(position, depth, 0); + var nodes = PerftRecursiveImpl(position, depth, 0); sw.Stop(); - return (nodes, Utils.CalculateElapsedSeconds(sw)); + PrintPerftResult(depth, nodes, Utils.CalculateElapsedSeconds(sw), write); } - public static (long Nodes, double ElapsedSeconds) Divide(Position position, int depth, Action write) + public static void RunDivide(Position position, int depth, Action write) { var sw = new Stopwatch(); sw.Start(); - var nodes = DivideImpl(position, depth, 0, write); + var nodes = DivideRecursiveImpl(position, depth, 0, write); sw.Stop(); - return (nodes, Utils.CalculateElapsedSeconds(sw)); + PrintPerftResult(depth, nodes, Utils.CalculateElapsedSeconds(sw), write); } /// - /// Proper implementation, used by as well + /// Proper implementation, used by as well /// /// /// /// /// [SkipLocalsInit] - internal static long ResultsImpl(Position position, int depth, long nodes) + internal static long PerftRecursiveImpl(Position position, int depth, long nodes) { if (depth != 0) { @@ -49,7 +49,7 @@ internal static long ResultsImpl(Position position, int depth, long nodes) if (position.WasProduceByAValidMove()) { - nodes = ResultsImpl(position, depth - 1, nodes); + nodes = PerftRecursiveImpl(position, depth - 1, nodes); } position.UnmakeMove(move, state); } @@ -61,7 +61,7 @@ internal static long ResultsImpl(Position position, int depth, long nodes) } [SkipLocalsInit] - private static long DivideImpl(Position position, int depth, long nodes, Action write) + private static long DivideRecursiveImpl(Position position, int depth, long nodes, Action write) { if (depth != 0) { @@ -73,7 +73,7 @@ private static long DivideImpl(Position position, int depth, long nodes, Action< if (position.WasProduceByAValidMove()) { var accumulatedNodes = nodes; - nodes = ResultsImpl(position, depth - 1, nodes); + nodes = PerftRecursiveImpl(position, depth - 1, nodes); write($"{move.UCIString()}\t\t{nodes - accumulatedNodes}"); } @@ -89,26 +89,15 @@ private static long DivideImpl(Position position, int depth, long nodes, Action< return nodes + 1; } - public static void PrintPerftResult(int depth, (long Nodes, double ElapsedSeconds) peftResult, Action write) + private static void PrintPerftResult(int depth, long nodes, double elapsedSeconds, Action write) { - var timeStr = TimeToString(peftResult.ElapsedSeconds * 1_000); + var timeStr = TimeToString(elapsedSeconds * 1_000); write( $"Depth:\t{depth}" + Environment.NewLine + - $"Nodes:\t{peftResult.Nodes}" + Environment.NewLine + + $"Nodes:\t{nodes}" + Environment.NewLine + $"Time:\t{timeStr}" + Environment.NewLine + - $"nps:\t{peftResult.Nodes / (peftResult.ElapsedSeconds * 1_000_000):F} Mnps" + Environment.NewLine); - } - - public static async ValueTask PrintPerftResult(int depth, (long Nodes, double ElapsedSeconds) peftResult, Func write) - { - var timeStr = TimeToString(peftResult.ElapsedSeconds * 1_000); - - await write( - $"Depth:\t{depth}" + Environment.NewLine + - $"Nodes:\t{peftResult.Nodes}" + Environment.NewLine + - $"Time:\t{timeStr}" + Environment.NewLine + - $"nps:\t{peftResult.Nodes / (peftResult.ElapsedSeconds * 1_000_000):F} Mnps" + Environment.NewLine); + $"nps:\t{nodes / (elapsedSeconds * 1_000_000):F} Mnps" + Environment.NewLine); } private static string TimeToString(double milliseconds) diff --git a/src/Lynx/UCIHandler.cs b/src/Lynx/UCIHandler.cs index e604481dd..8946574bd 100644 --- a/src/Lynx/UCIHandler.cs +++ b/src/Lynx/UCIHandler.cs @@ -82,10 +82,10 @@ static ReadOnlySpan ExtractCommandItems(string rawCommand) HandleNewGame(); break; case "perft": - await HandlePerft(rawCommand); + HandlePerft(rawCommand); break; case "divide": - await HandleDivide(rawCommand); + HandleDivide(rawCommand); break; case "bench": await HandleBench(rawCommand); @@ -556,25 +556,23 @@ private void HandleQuit() private void HandleRegister(ReadOnlySpan rawCommand) => _engine.Registration = new RegisterCommand(rawCommand); - private async Task HandlePerft(string rawCommand) + private void HandlePerft(string rawCommand) { var items = rawCommand.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (items.Length >= 2 && int.TryParse(items[1], out int depth) && depth >= 1) { - var results = Perft.Results(_engine.Game.CurrentPosition, depth); - await Perft.PrintPerftResult(depth, results, str => _engineToUci.Writer.WriteAsync(str)); + Perft.RunPerft(_engine.CurrentPosition, depth, str => _engineToUci.Writer.TryWrite(str)); } } - private async ValueTask HandleDivide(string rawCommand) + private void HandleDivide(string rawCommand) { var items = rawCommand.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (items.Length >= 2 && int.TryParse(items[1], out int depth) && depth >= 1) { - var results = Perft.Divide(_engine.Game.CurrentPosition, depth, str => _engineToUci.Writer.TryWrite(str)); - await Perft.PrintPerftResult(depth, results, str => _engineToUci.Writer.WriteAsync(str)); + Perft.RunDivide(_engine.CurrentPosition, depth, str => _engineToUci.Writer.TryWrite(str)); } } diff --git a/tests/Lynx.Test/PerftTest.cs b/tests/Lynx.Test/PerftTest.cs index cb0d1cbc3..9737302c2 100644 --- a/tests/Lynx.Test/PerftTest.cs +++ b/tests/Lynx.Test/PerftTest.cs @@ -279,6 +279,6 @@ public void MartinnPositions(string fen, int depth, long expectedNumberOfNodes) private static void Validate(string fen, int depth, long expectedNumberOfNodes) { - Assert.AreEqual(expectedNumberOfNodes, Perft.ResultsImpl(new Position(fen), depth, default)); + Assert.AreEqual(expectedNumberOfNodes, Perft.PerftRecursiveImpl(new Position(fen), depth, default)); } } diff --git a/tests/Lynx.Test/PerftTestSuite.cs b/tests/Lynx.Test/PerftTestSuite.cs index ddefbbb09..8573d33ca 100644 --- a/tests/Lynx.Test/PerftTestSuite.cs +++ b/tests/Lynx.Test/PerftTestSuite.cs @@ -771,6 +771,6 @@ public void Suite(string fen, int depth, long expectedNumberOfNodes) private static void Validate(string fen, int depth, long expectedNumberOfNodes) { - Assert.AreEqual(expectedNumberOfNodes, Perft.ResultsImpl(new Position(fen), depth, default)); + Assert.AreEqual(expectedNumberOfNodes, Perft.PerftRecursiveImpl(new Position(fen), depth, default)); } }