예제 #1
0
        public async Task <EngineEvaluation> BuildEngineEvaluations(TreeMove treeMove, params string[] previousMoves)
        {
            var engineEvaluation = await chessMetersContext.EngineEvaluations.SingleOrDefaultAsync(x => x.TreeMoveId == treeMove.Id && x.EngineId == engine.EngineId);

            if (engineEvaluation?.Depth >= engineDepth)
            {
                return(engineEvaluation);
            }

            await engine.SetPosition(previousMoves.Any()?$"{string.Join(' ', previousMoves)} {treeMove.Move}" : treeMove.Move);

            var evaluationCentipawns = await engine.GetEvaluationCentipawns(treeMove.ColorId);

            if (engineEvaluation != null)
            {
                engineEvaluation.Depth = engineDepth;
                engineEvaluation.EvaluationCentipawns = evaluationCentipawns;
                chessMetersContext.Update(engineEvaluation);
                await chessMetersContext.SaveChangesAsync();
            }
            else
            {
                await chessMetersContext.EngineEvaluations.AddAsync(new EngineEvaluation
                {
                    TreeMoveId           = treeMove.Id,
                    EngineId             = engine.EngineId,
                    Depth                = engineDepth,
                    EvaluationCentipawns = evaluationCentipawns
                });

                await chessMetersContext.SaveChangesAsync();
            }
            return(engineEvaluation);
        }
예제 #2
0
        public async Task <IEnumerable <TreeMove> > BuildTree(short analyzeDepth, Game game)
        {
            var treeMoves = new List <TreeMove>();

            try
            {
                var moves = game.Moves.Split(' ');
                if (!moves.Any())
                {
                    return(treeMoves);
                }

                var      fullPathIds    = new List <long>();
                TreeMove parentTreeMove = null;

                await engineAnalyzeEvaluator.StartNewGame(analyzeDepth);

                foreach (var move in moves)
                {
                    var parentTreeMoveId = parentTreeMove?.Id;
                    var treeMove         = await chessMetersContext.TreeMoves.SingleOrDefaultAsync(x => x.Move == move && x.ParentTreeMoveId == parentTreeMoveId);

                    if (treeMove == null)
                    {
                        treeMove = new TreeMove
                        {
                            Move             = move,
                            FullPath         = fullPathIds.Any() ? string.Join(" ", fullPathIds) : null,
                            ParentTreeMoveId = parentTreeMoveId,
                            ParentTreeMove   = parentTreeMove,
                            ColorId          = fullPathIds.Count % 2 == 0 ? ColorEnum.White : ColorEnum.Black
                        };
                        await chessMetersContext.TreeMoves.AddAsync(treeMove);

                        await chessMetersContext.SaveChangesAsync();
                    }

                    await engineAnalyzeEvaluator.BuildEngineEvaluations(treeMove, treeMoves.Select(x => x.Move).ToArray());

                    treeMoves.Add(treeMove);
                    fullPathIds.Add(treeMove.Id);
                    parentTreeMove = treeMove;
                }

                game.LastTreeMoveId = fullPathIds.LastOrDefault();
                chessMetersContext.Games.Update(game);
                await chessMetersContext.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                game.AnalyzeExceptionStackTrace = ex.ToString();
            }

            return(treeMoves);
        }
예제 #3
0
        public async Task <IActionResult> Generate([FromBody] GenerateReportViewModel generateReport)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var games = await gameConverter.ConvertFromPGN(generateReport.PGN);

            for (var i = 0; i < games.Count(); i++)
            {
                games.ElementAt(i).UserColorId = generateReport.UserColors.ElementAt(i);
            }

            var report = new Report
            {
                Description  = generateReport.Description,
                PGN          = generateReport.PGN,
                UserId       = User.FindFirst(ClaimTypes.NameIdentifier).Value,
                CreationDate = DateTime.Now,
                Games        = games.ToList()
            };
            await chessMetersContext.Reports.AddAsync(report);

            await chessMetersContext.SaveChangesAsync();

            var data = new Dictionary <string, int>
            {
                { "id", report.Id }
            };
            var jobData   = new JobDataMap(data);
            var scheduler = await schedulerFactory.GetScheduler();

            await scheduler.TriggerJob(new JobKey(typeof(ReportGeneratorJob).Name), jobData);

            return(Ok());
        }
예제 #4
0
        public async Task Schedule(Game game, short engineDepth)
        {
            try
            {
                var treeMoves = await treeMoveBuilder.BuildTree(engineDepth, game);

                game.LastTreeMoveId = treeMoves.LastOrDefault()?.Id;
                await flagBuilder.AnalizeGame(game);

                game.Analyzed = true;
                chessMetersContext.Games.Update(game);
            }
            catch (Exception ex)
            {
                game.AnalyzeExceptionStackTrace = ex.ToString();
            }
            finally
            {
                await chessMetersContext.SaveChangesAsync();
            }
        }
        public async Task BuildTree_Should_SetupTreeAndSaveToDbIfMoveNotFound()
        {
            string pgn = "[Event \"Live Chess\"] [Site \"Chess.com\"] [Date \"2020.11.25\"] [Round \"?\"] [White \"claudiuoprea\"] [Black \"Cest_Sebastian\"] [Result \"0-1\"] [ECO \"C26\"] [WhiteElo \"1174\"] [BlackElo \"1212\"] [TimeControl \"600\"] [EndTime \"5:58:12 PST\"] [Termination \"Cest_Sebastian won by resignation\"] 1. e4 {[%timestamp 1]} 1... e5 {[%timestamp 1]} 2. Bc4 {[%timestamp 1]} 2... Nf6 {[%timestamp 1]} 3. Nc3 {[%timestamp 16]} 3... Nc6 {[%timestamp 253]} 4. d3 {[%timestamp 21]} 4... Bb4 {[%timestamp 93]} 5. f4 {[%timestamp 79]} 5... Bxc3+ {[%timestamp 70]} 6. bxc3 {[%timestamp 10]} 6... O-O {[%timestamp 80]} 7. fxe5 {[%timestamp 91]} 7... Nxe5 {[%timestamp 66]} 8. Bb3 {[%timestamp 33]} 8... d6 {[%timestamp 52]} 9. Nf3 {[%timestamp 24]} 9... Bg4 {[%timestamp 27]} 10. h3 {[%timestamp 114]} 10... Bxf3 {[%timestamp 14]} 11. gxf3 {[%timestamp 39]} 11... d5 {[%timestamp 33]} 12. Rg1 {[%timestamp 107]} 12... dxe4 {[%timestamp 58]} 13. Bh6 {[%timestamp 48]} 13... Re8 {[%timestamp 135]} 14. Bxg7 {[%timestamp 126]} 14... Ng6 {[%timestamp 1]} 15. Bh6 {[%timestamp 250]} 15... exf3+ {[%timestamp 59]} 16. Kd2 {[%timestamp 49]} 16... f2 {[%timestamp 174]} 17. Rg2 {[%timestamp 187]} 17... Ne4+ {[%timestamp 237]} 18. Kc1 {[%timestamp 74]} 18... Nxc3 {[%timestamp 142]} 19. Qd2 {[%timestamp 109]} 19... f1=Q+ {[%timestamp 58]} 20. Kb2 {[%timestamp 60]} 20... Na4+ {[%timestamp 431]} 21. Bxa4 {[%timestamp 175]} 21... Qd4+ {[%timestamp 76]} 22. Ka3 {[%timestamp 128]} 22... Qc5+ {[%timestamp 114]} 23. Kb3 {[%timestamp 112]} 23... Qd5+ {[%timestamp 60]} 24. Ka3 {[%timestamp 35]} 24... Qfxg2 {[%timestamp 40]} 25. Qc3 {[%timestamp 74]} 25... Qd6+ {[%timestamp 179]} 26. Kb3 {[%timestamp 149]} 26... Qgd5+ {[%timestamp 69]} 27. Kb2 {[%timestamp 29]} 27... Qb6+ {[%timestamp 96]} 28. Bb3 {[%timestamp 52]} 28... Qdd4 {[%timestamp 1]} 29. Qxd4 {[%timestamp 1]} 29... Qxd4+ {[%timestamp 1]} 30. Ka3 {[%timestamp 31]} 0-1";

            using var context = new ChessMetersContext(options, new OperationalStoreOptionsMigrations());
            var engineProcess          = new EngineProcess();
            var stockfishEngine        = new StockfishEngine(engineProcess);
            var engineAnalyzeEvaluator = new EngineEvaluationBuilder(stockfishEngine, context);
            var gameAnalyzer           = new TreeMovesBuilder(context, engineAnalyzeEvaluator);

            var user = await context.Users.FirstAsync();

            var report = new Report
            {
                PGN         = pgn,
                Description = $"Unit test ${DateTime.Now}",
                UserId      = user.Id
            };

            await context.Reports.AddAsync(report);

            await context.SaveChangesAsync();

            var moves = await gameAnalyzer.BuildTree(EngineConsts.defaultAnalyzeDepth, new Game
            {
                ReportId = report.Id,
                Result   = "0-1",
                Moves    = "d2d4 d7d5 c2c4 c7c6 g1f3"
            });

            Assert.Equal(5, moves.Count());
            Assert.All(moves, x => Assert.NotEqual(0, x.Id));
            Assert.Null(moves.First().ParentTreeMoveId);
            Assert.NotNull(moves.Last().ParentTreeMoveId);
            Assert.NotNull(moves.Last().ParentTreeMove);
        }
예제 #6
0
        public async Task AnalizeGame(Game game)
        {
            var lastTreeMove = await chessMetersContext.TreeMoves.FindAsync(game.LastTreeMoveId);

            var pathIds = game.LastTreeMove.FullPath.Split(' ');
            var moveIds = pathIds.Select(x => long.Parse(x)).ToList();

            moveIds.Add(game.LastTreeMoveId.Value);
            var moves = await chessMetersContext.TreeMoves.Include(x => x.EngineEvaluations).Include(x => x.TreeMoveFlags)
                        .Where(x => moveIds.Contains(x.Id)).ToListAsync();

            var treeMoves = new List <TreeMove>();

            foreach (var moveId in moveIds)
            {
                treeMoves.Add(moves.Single(x => x.Id == moveId));
            }

            boardState.Initialize(treeMoves, game.UserColorId);
            var rules     = assemblyLoader.GetAllTypesOf <IRule>();
            var gameFlags = new HashSet <FlagEnum>();

            foreach (var treeMove in treeMoves)
            {
                var treeMoveFlags = new HashSet <FlagEnum>();
                foreach (var rule in rules)
                {
                    if (!rule.Evaluate(boardState))
                    {
                        continue;
                    }

                    if (rule.IsGameRule)
                    {
                        gameFlags.Add(rule.Flag);
                    }
                    else
                    {
                        treeMoveFlags.Add(rule.Flag);
                    }
                }

                chessMetersContext.TreeMoveFlags.RemoveRange(treeMove.TreeMoveFlags.Where(x => !treeMoveFlags.Contains(x.FlagId)));
                await chessMetersContext.TreeMoveFlags.AddRangeAsync(treeMoveFlags.Where(x => !treeMove.TreeMoveFlags.Any(tmf => tmf.FlagId == x)).Select(x => new TreeMoveFlag
                {
                    TreeMoveId = treeMove.Id,
                    FlagId     = x
                }));

                boardState.SetNextTreeMove();
            }

            chessMetersContext.GameFlags.RemoveRange(game.GameFlags);
            await chessMetersContext.GameFlags.AddRangeAsync(gameFlags.Select(x => new GameFlag
            {
                FlagId = x,
                GameId = game.Id
            }));

            await chessMetersContext.SaveChangesAsync();
        }