private async Task AnalyzeRecursively(BoardAnalysisInfo info, bool[,] visited, string currentWord, Coordinates currentCoordinates, List <Coordinates> path)
        {
            // Initialize information
            var coordinates = currentCoordinates;

            visited = (bool[, ])visited.Clone();
            visited[coordinates.X, coordinates.Y] = true;

            path.Add(currentCoordinates);

            var cellCharacter = info.Board[currentCoordinates.X][currentCoordinates.Y];

            currentWord += cellCharacter;

            _logger.WriteLine($"Analyzing word {currentWord}");

            // Words Detection
            var hasCurrentWordAlreadyBeenMatched = info.DetectedWords.ContainsKey(currentWord);
            var isCurrentlyMatchingAWord         = IsCurrentlyMatchingAWord(info, currentWord);

            if (isCurrentlyMatchingAWord && !hasCurrentWordAlreadyBeenMatched)
            {
                _logger.WriteLine($"Added word {currentWord}...");
                info.DetectedWords.TryAdd(currentWord, path.ToArray());
            }

            // Recursion
            await MoveTo(info, visited, currentWord, currentCoordinates, path);

            path.Remove(currentCoordinates);
        }
        private Coordinates[] GetNextCoordinates(BoardAnalysisInfo info, bool[,] visited, Coordinates currentCoordinates)
        {
            var nextCoordinates = new List <Coordinates>();

            var startXPosition = Math.Max(0, currentCoordinates.X - 1);
            var maxXPosition   = Math.Min(info.BoardDimensions.X - 1, currentCoordinates.X + 1); // BoardDimensions.X - 1 as array starts at 0

            var startYPosition = Math.Max(0, currentCoordinates.Y - 1);
            var maxYPosition   = Math.Min(info.BoardDimensions.Y - 1, currentCoordinates.Y + 1); // BoardDimensions.Y + 1 as array starts at 0

            for (var x = startXPosition; x <= maxXPosition; ++x)
            {
                for (var y = startYPosition; y <= maxYPosition; ++y)
                {
                    var alreadyVisited = visited[x, y];

                    if (!alreadyVisited)
                    {
                        nextCoordinates.Add(new Coordinates(x, y));
                    }
                }
            }

            return(nextCoordinates.ToArray());
        }
        private bool IsCurrentlyMatchingAWord(BoardAnalysisInfo info, string currentWord)
        {
            if (currentWord.Length < info.Dictionary.MinLength)
            {
                return(false);
            }

            return(info.Dictionary.Words.Contains(currentWord));
        }
        private async Task <IDictionary <string, Coordinates[]> > DetectWords(char[][] board, Dictionary <char, LetterDictionaryInfo> wordsByFirstChar)
        {
            var xSize         = board.Length;
            var ySize         = board[0].Length;
            var detectedWords = new ConcurrentDictionary <string, Coordinates[]>();
            var tasks         = new List <Task>();

            // For all starting element
            for (var x = 0; x < xSize; ++x)
            {
                for (var y = 0; y < ySize; ++y)
                {
                    var firstCharacter             = board[x][y];
                    var wordsStartingWithCharacter = wordsByFirstChar[firstCharacter];

                    _logger.WriteLine($"Analyzing board[{x}][{y}] = {firstCharacter}...");

                    if (wordsStartingWithCharacter == null)
                    {
                        _logger.WriteLine($"The dictionary does not contain any word starting with character {firstCharacter}...");
                        continue;
                    }

                    var boardLetterInfo = new BoardAnalysisInfo
                    {
                        Board         = board,
                        Dictionary    = wordsStartingWithCharacter,
                        DetectedWords = detectedWords // TODO - This will become a bottleneck
                    };

                    var operationX = x;
                    var operationY = y;

                    var task = Task.Factory.StartNew(() =>
                    {
                        var coordinates = new List <Coordinates>();
                        AnalyzeRecursively(boardLetterInfo, new bool[xSize, ySize], "", new Coordinates(operationX, operationY), coordinates).Wait();
                    }, TaskCreationOptions.LongRunning);

                    tasks.Add(task);
                }
            }

            await Task.WhenAll(tasks.ToArray());

            return(detectedWords);
        }
        private async Task MoveTo(BoardAnalysisInfo info, bool[,] visited, string currentWord, Coordinates currentCoordinates, List <Coordinates> path)
        {
            if (currentWord.Length >= info.Dictionary.MaxLength)
            {
                return;
            }

            var nextMoveCoordinates = GetNextCoordinates(info, visited, currentCoordinates);

            if (nextMoveCoordinates.Length == 0)
            {
                return;
            }

            foreach (var nextCoordinates in nextMoveCoordinates)
            {
                await AnalyzeRecursively(info, visited, currentWord, nextCoordinates, path);
            }
        }