private bool WordWillFit(WordSolution solution, PuzzleBoard board, PuzzlePoint directionOffsets, int x, int y)
        {
            var rc = true;

            // We may be finding another placement ...
            solution.Points.Clear();

            for (int position = 0; position < solution.Word.Length; position++)
            {
                var thisChar = solution.Word[position].ToString();
                var currX    = x + (position * directionOffsets.X);
                var currY    = y + (position * directionOffsets.Y);

                if (currX < 0 || currX > (board.Width - 1) || currY < 0 || currY > (board.Height - 1))
                {
                    rc = false;
                    break; // outside the bounds of the grid
                }
                // First chance - target cell is empty; Second chance - target cell contains the letter
                if (board.Letters[currY, currX] != null && board.Letters[currY, currX] != thisChar)
                {
                    rc = false;
                    break; // won't fit
                }

                // Looks like it will fit so far - add Point ...
                solution.Points.Add(new PuzzlePoint(currX, currY));
            }

            // Verify there is no overlay inside another word placement
            if (rc)
            {
                rc = !board.Solutions.Any(
                    s =>
                    s != null &&
                    solution.Word.Length <= s.Word.Length &&
                    solution.Points.Intersect(s.Points).SequenceEqual(solution.Points)
                    );
            }

            return(rc);
        }
        private WordSolution PlaceWord(PuzzleBoard board, string word, bool verbose)
        {
            if (verbose)
            {
                Logger.LogDebug($"Placing word={word}");
            }

            var rc = new WordSolution
            {
                Word      = word,
                Placed    = false,
                WordSlope = WordSlope.S,
                Origin    = new PuzzlePoint(),
                Points    = new List <PuzzlePoint>()
            };

            var tries = 0;

            for (; tries < MaxTries; tries++)
            {
                var x = board.Width.Random();
                var y = board.Height.Random();

                // Is the first cell a probable match
                if (board.Letters[y, x] == null || board.Letters[y, x] == word[0].ToString())
                {
                    // Iterate over directions in random order
                    var dirIdxs = Enumerable.Range(0, Directions.Length).ToArray();
                    dirIdxs.Shuffle();

                    foreach (var idx in dirIdxs)
                    {
                        // get the selected direction deltas
                        var wordSlope  = Directions[idx];
                        var dirOffsets = DirectionOffsets[wordSlope];

                        // Make sure the cells for word are empty, contain matching char
                        // and are not contained inside another solution
                        if (WordWillFit(rc, board, dirOffsets, x, y))
                        {
                            WordCopyToBoard(word, board, dirOffsets, x, y);

                            if (verbose)
                            {
                                Logger.LogDebug($"{word} was placed @ ({x},{y}) via {wordSlope} for puzzle={board.Puzzle.Id} in {tries} tries");
                            }

                            rc.Placed    = true;
                            rc.WordSlope = wordSlope;
                            rc.Origin    = new PuzzlePoint(x, y);

                            return(rc);
                        }
                    }
                }
            }

            if (verbose)
            {
                Logger.LogDebug($"{word} was not placed in {tries} tries");
            }

            return(rc);
        }