rudzen / ChessLib

C# chess library containing a complete data structure and move generation.
MIT License
81 stars 22 forks source link

How to achieve that ~6 second search time for depth of 6 #26

Closed JamesLear92 closed 4 years ago

JamesLear92 commented 4 years ago

Hi, I've been playing around with this library this afternoon, and I've written the following as a very basic search function:

    static void Main(string[] args)
    {
        var game = new Game(new Position());
        game.NewGame();
        var start = DateTime.Now;
        var t = Search(game, 0, 5);
        Console.WriteLine(t.Count());
        var end = DateTime.Now;
        var difference = end - start;
        Console.WriteLine(difference);
    }
    static IEnumerable<Move> Search(Game game, int currentDepth, int targetDepth)
    {
        foreach (var move in game.Position.GenerateMoves(Chess.Enums.Emgf.Legalmoves, true, false))
        {
            if (currentDepth < targetDepth)
            {
                game.MakeMove(move);
                yield return move;
                foreach (var item in (Search(game, currentDepth + 1, targetDepth)))
                    yield return item;
                game.TakeMove();
            }
        }
    }

To get to a depth of 6, it's taking a very very long time, depth of 5 I'm getting about 9 seconds.

Is there a better way to perform this search?

Many Thanks, James

rudzen commented 4 years ago

I tried your code out and it yield about 7 seconds on my machine, which is quite high for depth 5. However, using the build in Perft method i could reduce that to less than 0.5 seconds.

However, since that might not be what you are actually looking for, this slight change to your Search method completes in about 1.5 seconds on my machine

private static IEnumerable<Move> Search(Game game, int currentDepth, int targetDepth)
{
    if (currentDepth >= targetDepth)
        yield break;

    foreach (var move in game.Pos.GenerateMoves(Chess.Enums.Emgf.Legalmoves, true, false))
    {
        game.MakeMove(move);
        yield return move;

        foreach (var item in (Search(game, currentDepth + 1, targetDepth)))
            yield return item;
        game.TakeMove();
    }
}

This runs quite a bit faster as you were generating moves at the last depth even though you did not use it. The move generator does not employ deferred execution of any kind (on purpose).

Hope it helps a bit.

Cheers, Rudy

JamesLear92 commented 4 years ago

Thanks Rudy!