private bool GetSolution(Game.NumbersGame game, out ISolution solution)
        {
            var  timer  = Stopwatch.StartNew();
            bool solved = Solve(game);

            solution = new Solution(game.History, timer.Elapsed);
            return(solved);
        }
        private readonly List <INumbersGame> _wip = new List <INumbersGame>(60); // work in progress

        public bool GetSolution(int[] inputNumbers, int target, out ISolution solution)
        {
            var initialNumbers = new Game.NumbersGame(inputNumbers)
            {
                Target = target
            };

            return(GetSolution(initialNumbers, out solution));
        }
        private bool GetSolution(Game.NumbersGame initialGame, out ISolution solution)
        {
            var t0 = DateTime.Now;

            _wip.Add(initialGame);

            while (_wip.Any())
            {
                // Process exactly the lists we had from the last iteration first
                // That begins at 1, for the single initial game
                int lists = _wip.Count;
                for (int idx = 0; idx < lists; ++idx)
                {
                    INumbersGame game = _wip[idx];
                    if (game.IsSolved)
                    {
                        solution = new Solution(game.History, DateTime.Now - t0);
                        return(true);
                    }

                    if (!game.IsExhausted)
                    {
                        var derivatives = game.CreateAllDescendents();
                        foreach (var v in derivatives)
                        {
                            _wip.AddRange(derivatives);
                        }
                    }
                }
                // We have dealt with (0,lists] now. RemoveRange does exactly what we need.
                _wip.RemoveRange(0, lists);
            }
            // There aint one
            solution = null;
            var t1 = System.DateTime.Now;
            var dt = t1 - t0;

            Console.WriteLine("Exhausting the possibilities took {0} s {1} ms", dt.Seconds, dt.Milliseconds);
            return(false);
        }
        private bool Solve(Game.NumbersGame game)
        {
            if (game.IsSolved)
            {
                return(true);
            }

            int numbers = game.NumberCount;
            int maxIdx0 = numbers - 1;

            for (int idx0 = 0; idx0 < maxIdx0; ++idx0)
            {
                int n1 = game.GetNumber(idx0);
                for (int idx1 = idx0 + 1; idx1 < numbers; ++idx1)
                {
                    int n2 = game.GetNumber(idx1);
                    foreach (Operator op in Enum.GetValues(typeof(Operator)))
                    {
                        if (Operation.IsValid(n1, n2, op))
                        {
                            game.DoOperation(new Operation(n1, n2, op));
                            if (game.IsSolved)
                            {
                                return(true);
                            }
                            if (game.NumberCount >= 2 && Solve(game))
                            {
                                return(true);
                            }
                            game.UndoOperation();
                        }
                    }
                }
            }
            return(false);
        }