public List <Move> GetCalculatedNextMoves(CellState[,] board, Team team, List <List <Move> > beats, List <List <Move> > moves, CancellationToken token)
        {
            var firstPredictions = new List <PredictionNode>();

            try
            {
                var predictions = new List <PredictionNode>();
                foreach (var beat in beats)
                {
                    if (beat.Count > 0)
                    {
                        var updatedBoard = board.UpdateFromMoves(beat);

                        if (updatedBoard.CountEnemies(team) == 0)
                        {
                            return(beat);
                        }

                        var ranking = _getMoveWeight.CalculateMoveWeight(beat, board, updatedBoard, team, true);
                        var node    = new PredictionNode
                        {
                            InitialMoves      = beat,
                            NextTeam          = team.GetNextTeam(),
                            NextBoard         = updatedBoard,
                            Depth             = 0,
                            AccumulatedWeight = ranking.weight,
                            StatsForPlayer    = ranking.stats
                        };

                        firstPredictions.Add(node);
                        predictions.AddRange(_predictionBuilder.GetDepthwisePrediction(node, team, 3, token));
                    }
                }

                foreach (var move in moves)
                {
                    if (token.IsCancellationRequested)
                    {
                        throw new TaskCanceledException();
                    }

                    var updatedBoard = board.UpdateFromMoves(move);
                    var ranking      = _getMoveWeight.CalculateMoveWeight(move, board, updatedBoard, team);

                    var node = new PredictionNode
                    {
                        InitialMoves      = move,
                        NextTeam          = team.GetNextTeam(),
                        NextBoard         = updatedBoard,
                        Depth             = 0,
                        AccumulatedWeight = ranking.weight,
                        StatsForPlayer    = ranking.stats
                    };

                    firstPredictions.Add(node);
                    predictions.AddRange(_predictionBuilder.GetDepthwisePrediction(node, team, 3, token));
                }

                return(GetBestForRandom(predictions));
            }

            catch (TaskCanceledException)
            {
                Console.WriteLine("Task cancelled");
            }

            return(GetBestForRandom(firstPredictions));
        }
        public List <PredictionNode> GetDepthwisePrediction(PredictionNode node, Team teamPlaying, int predictionDepth, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                throw new TaskCanceledException();
            }

            var teamNext  = node.NextTeam;
            var boardNext = node.NextBoard;

            var toKill = boardNext.CountEnemies(teamNext);
            var depth  = node.Depth + 1;
            var beats  = _beatsCalc.GetPossibleBeats(boardNext, teamNext);

            var nextPossibilities = new List <PredictionNode>();

            foreach (var beat in beats)
            {
                if (token.IsCancellationRequested)
                {
                    throw new TaskCanceledException();
                }

                if (beat.Count > 0)
                {
                    var updatedBoard = boardNext.UpdateFromMoves(beat);
                    var rank         = _getMoveWeight.CalculateMoveWeight(beat, boardNext, updatedBoard, teamNext, true);

                    if (rank.stats > -2)
                    {
                        var nodeNext = new PredictionNode
                        {
                            InitialMoves      = node.InitialMoves,
                            NextTeam          = teamNext.GetNextTeam(),
                            NextBoard         = updatedBoard,
                            Depth             = depth,
                            AccumulatedWeight = node.AccumulatedWeight + (teamNext == teamPlaying ? +rank.weight : -rank.weight),
                            StatsForPlayer    = teamNext == teamPlaying ? +rank.weight : -rank.weight
                        };

                        if (depth == predictionDepth || toKill == 0)
                        {
                            nextPossibilities.Add(nodeNext);
                        }

                        if (depth < predictionDepth && toKill > 0)
                        {
                            nextPossibilities.AddRange(GetDepthwisePrediction(nodeNext, teamPlaying, predictionDepth,
                                                                              token));
                        }
                    }
                }
            }

            var moves = _movesCalc.GetPossibleMoves(boardNext, teamNext);

            foreach (var move in moves)
            {
                if (token.IsCancellationRequested)
                {
                    throw new TaskCanceledException();
                }

                var updatedBoard = boardNext.UpdateFromMoves(move);
                var rank         = _getMoveWeight.CalculateMoveWeight(move, boardNext, updatedBoard, teamNext);

                var nodeNext = new PredictionNode
                {
                    InitialMoves      = node.InitialMoves,
                    NextTeam          = teamNext.GetNextTeam(),
                    NextBoard         = updatedBoard,
                    Depth             = depth,
                    AccumulatedWeight = node.AccumulatedWeight + (teamNext == teamPlaying ? +rank.weight : -rank.weight),
                    StatsForPlayer    = teamNext == teamPlaying ? +rank.weight : -rank.weight
                };

                if (depth == predictionDepth)
                {
                    nextPossibilities.Add(nodeNext);
                }
                if (depth < predictionDepth)
                {
                    nextPossibilities.AddRange(GetDepthwisePrediction(nodeNext, teamPlaying, predictionDepth, token));
                }
            }

            return(nextPossibilities);
        }