public static Definition.Sudoku Copy(this Definition.Sudoku source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            var target = new Definition.Sudoku();

            using (var sourceIterator = new SudokuElementEnumerable(source).GetEnumerator())
                using (var targetIterator = new SudokuElementEnumerable(target).GetEnumerator())
                {
                    while (sourceIterator.MoveNext() & targetIterator.MoveNext())
                    {
                        var sourceElement = sourceIterator.Current;
                        var targetElement = targetIterator.Current;

                        if (sourceElement.HasValue)
                        {
                            targetElement.SetValue(sourceElement.Value);
                        }
                        else
                        {
                            targetElement.ClearValue();
                        }
                    }
                }

            return(target);
        }
        public static void UpdateByValued(this Definition.Sudoku source, Definition.Sudoku other)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            using (var sourceIterator = new SudokuElementEnumerable(source).GetEnumerator())
                using (var otherIterator = new SudokuElementEnumerable(other).GetEnumerator())
                {
                    while (sourceIterator.MoveNext() & otherIterator.MoveNext())
                    {
                        var sourceElement = sourceIterator.Current;
                        var otherElement  = otherIterator.Current;

                        if (!sourceElement.HasValue && otherElement.HasValue)
                        {
                            sourceElement.SetValue(otherElement.Value);
                        }
                    }
                }
        }
        public static bool TryParse(string source, out Definition.Sudoku sudoku)
        {
            sudoku = null;

            if (string.IsNullOrEmpty(source))
            {
                return(false);
            }

            int size = SUDOKU_SPLIT_LEN;

            string[] lines = source.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length != size)
            {
                return(false);
            }

            int[] elementValues = new int[size * size];
            int   valueIndex    = 0;

            foreach (var line in lines)
            {
                int[] values;
                if (!TryParse(line, out values))
                {
                    return(false);
                }
                Array.Copy(values, 0, elementValues, valueIndex++ *size, size);
            }

            sudoku = new Definition.Sudoku();
            using (var sudokuElementIterator = new SudokuElementEnumerable(sudoku, SudokuElementTravelType.Row).GetEnumerator())
                using (var valueIterator = elementValues.AsEnumerable().GetEnumerator())
                {
                    while (sudokuElementIterator.MoveNext() && valueIterator.MoveNext())
                    {
                        var element = sudokuElementIterator.Current;
                        int value   = valueIterator.Current;
                        if (value > 0)
                        {
                            element.SetValue(value);
                        }
                    }
                }

            return(true);
        }
        static bool InputSudoku(out Definition.Sudoku sudoku)
        {
            sudoku = null;

            Console.WriteLine("input sudoku data:");
            Console.WriteLine();
            Console.WriteLine("(whitespace to separate elements");
            Console.WriteLine(" _ to indicate empty element");
            Console.WriteLine(" new line to separete rows");
            Console.WriteLine(" esc to cancel)");
            Console.WriteLine();

            bool cancelled = false;
            int  size      = SudokuHelper.SUDOKU_SPLIT_LEN;

            int[] values = new int[size * size];

            for (int i = 0; i < size;)
            {
                Console.WriteLine("line " + (i + 1));
                StringBuilder lineBuilder = new StringBuilder();
                bool          endOfLine   = false;
                while (!endOfLine && !cancelled)
                {
                    var key = Console.ReadKey();
                    switch (key.Key)
                    {
                    case ConsoleKey.Enter:
                        endOfLine = true;
                        break;

                    case ConsoleKey.Escape:
                        cancelled = true;
                        break;

                    case ConsoleKey.Backspace:
                        if (lineBuilder.Length > 0)
                        {
                            lineBuilder.Remove(lineBuilder.Length - 1, 1);
                        }
                        break;
                    }

                    switch (key.KeyChar)
                    {
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '_':
                    case ' ':
                        lineBuilder.Append(key.KeyChar);
                        break;

                    default: break;
                    }
                }

                if (cancelled)
                {
                    Console.WriteLine("cancelled");
                    return(false);
                }

                int[] lineValues;
                if (!SudokuHelper.TryParse(lineBuilder.ToString(), out lineValues))
                {
                    Console.WriteLine("wrong line data");
                    i--;
                    continue;
                }

                Array.Copy(lineValues, 0, values, i++ *size, size);

                Console.WriteLine();
            }

            sudoku = new Definition.Sudoku();
            using (var sudokuElementIterator = new SudokuElementEnumerable(sudoku, SudokuElementTravelType.Row).GetEnumerator())
                using (var valueIterator = values.AsEnumerable().GetEnumerator())
                {
                    while (sudokuElementIterator.MoveNext() && valueIterator.MoveNext())
                    {
                        var element = sudokuElementIterator.Current;
                        int value   = valueIterator.Current;
                        if (value > 0)
                        {
                            element.SetValue(value);
                        }
                    }
                }

            if (!sudoku.Validate())
            {
                sudoku = null;
                Console.WriteLine("invalid sudoku data");
                return(false);
            }

            return(true);
        }