// 3. Searching for Single Candidates: Square
        // "is there a value in any square that is only possible in one location?"

        public static void SearchSquareForSingleCandidates(this Grid grid)
        {
            for (int s = 0; s < grid.GridSize; s++)
            {
                for (int value = 1; value <= grid.GridSize; value++)
                {
                    // that value already exists in the col
                    if (Array.Exists(grid.GetSquare(s), element => element == value))
                    {
                        continue;
                    }

                    Tuple <int, int> result = grid.CheckSquareForValueInOptions(s, value);
                    if (result.Item1 != -1 && result.Item2 != -1)
                    {
                        grid.SolveCell(result.Item1, result.Item2, value);
                        grid.UpdateNeighbours(result.Item1, result.Item2);
                    }
                }
            }
        }
        public static bool IsValidSolution(this Grid grid)
        {
            if (grid.CompletedCells < grid.GridSize * grid.GridSize)
            {
                return(false);
            }

            for (int i = 0; i < grid.GridSize; i++)
            {
                bool validRow    = new HashSet <int>(grid.GetRow(i)).SetEquals(Enumerable.Range(1, grid.GridSize));
                bool validCol    = new HashSet <int>(grid.GetColumn(i)).SetEquals(Enumerable.Range(1, grid.GridSize));
                bool validSquare = new HashSet <int>(grid.GetSquare(i)).SetEquals(Enumerable.Range(1, grid.GridSize));

                if (!(validRow & validCol & validSquare))
                {
                    return(false);
                }
            }

            return(true);
        }