public void SingleThreadedForwardSolver_TreePoolPerformance()
        {
            // IDEA: This puzzle has a relatively large amount of FLOOR space, which will create lots of Nodes in the TreePool

            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(new String[]
                {
                    "##########",
                    "#O.......#",
                    "#O.......#",
                    "#O.......#",
                    "#....X...#",
                    "#...XPX..#",
                    "#........#",
                    "##########"
                }),
                Report = Console.Out,
                ExitConditions = ExitConditions.OneMinute
            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
        }
        public void SingleThreadedForwardSolver_BaseLine_Quick()
        {
            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(),
                Report = Console.Out,
                ExitConditions = new ExitConditions()
                {
                    Duration = TimeSpan.FromSeconds(10),
                    StopOnSolution = true,
                    TotalNodes = 10000
                }
            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
        }
        public List<Result> Run(SolverRun run, SolverCommand baseCommand, ISolver solver = null)
        {
            if (solver == null)
            {
                solver = new SingleThreadedForwardSolver();
            }

            Report.WriteLine("Puzzle Exit Conditions: {0}", run.PuzzleExit);
            Report.WriteLine("Batch Exit Conditions : {0}", run.BatchExit);
            Report.WriteLine("Solver                : {0}", SolverHelper.Describe(solver));
            Report.WriteLine("CPU                   : {0}", DebugHelper.GetCPUDescription());
            Report.WriteLine("Machine               : {0} {1}", Environment.MachineName, Environment.Is64BitProcess ? "x64" : "x32");

            Report.WriteLine();

            var res = new List<Result>();
            var start = new SolverStatistics()
            {
                Started = DateTime.Now
            };
            SolverCommandResult result = null;
            int pp = 0;
            int consecutiveFails = 0;
            foreach (var puzzle in run)
            {
                if (baseCommand.CheckAbort(baseCommand))
                {
                    Progress.WriteLine("EXITING...");
                    break;
                }
                try
                {
                    pp++;
                    Progress.WriteLine("Attempting: {0} ({2}/{3}); Rating: {1}", PuzzleHelper.GetName(puzzle), StaticAnalysis.CalculateRating(puzzle), pp, run.Count);

                    var libPuzzle = puzzle as LibraryPuzzle;
                    Report.WriteLine("           Name: {0}", PuzzleHelper.GetName(puzzle));
                    Report.WriteLine("          Ident: {0}", libPuzzle != null ? libPuzzle.Ident : null);
                    Report.WriteLine("         Rating: {0}", StaticAnalysis.CalculateRating(puzzle));
                    Report.WriteLine("Starting Memory: {0}", Environment.WorkingSet);
                    Report.WriteLine(puzzle.ToString());

                    PuzzleDTO dto = null;
                    if (Repository != null)
                    {
                        dto = Repository.Get(puzzle);
                        if (dto == null)
                        {
                            dto = Repository.ToDTO(puzzle);
                            Repository.Store(dto);
                        }
                        dto.Solutions = Repository.GetSolutions(dto.PuzzleId);
                    }

                    if (SkipPuzzlesWithSolutions)
                    {
                        if (dto != null &&
                            dto.Solutions.Exists(x=>x.HostMachine == Environment.MachineName && x.SolverType == solver.GetType().Name))
                        {
                            Progress.WriteLine("Skipping... (SkipPuzzlesWithSolutions)");
                            continue;
                        }
                    }

                    Report.WriteLine();

                    result = solver.Init(new SolverCommand(baseCommand)
                    {
                        Report = Report,
                        ExitConditions = run.PuzzleExit,
                        Puzzle = puzzle,

                    });
                    if (Tracking != null) Tracking.Begin(result);

                    solver.Solve(result);
                    var r = new Result()
                    {
                        Summary = SolverHelper.Summary(result),
                        Exited = result.Exit,
                        Solutions = result.GetSolutions()
                    };
                    res.Add(r);

                    start.TotalNodes += result.Statistics.TotalNodes;
                    start.TotalDead += result.Statistics.TotalDead;

                    if (r.Solutions.Any())
                    {
                        int cc = 0;
                        foreach (var p in r.Solutions.ToArray())
                        {
                            string error = null;
                            var check = SolverHelper.CheckSolution(puzzle, p, out error);
                            Report.WriteLine("Solution #{0} [{1}] =>\n{2}", cc++, check ? "Valid":"INVALID!"+error, p);
                            if (!check)
                            {
                                r.Solutions.Remove(p);
                                r.Summary += " (INVALID SOLUTION)";
                            }
                        }
                        // Write to DB?
                        if (dto != null)
                        {
                            if (Repository != null)
                            {
                                StoreSolution(solver, dto, r.Solutions);
                            }
                        }
                    }

                    if (r.Solutions.Any()) // May have been removed above
                    {
                        consecutiveFails = 0;
                    }
                    else
                    {
                        consecutiveFails++;
                        if (StopOnConsecutiveFails != 0 && consecutiveFails > StopOnConsecutiveFails)
                        {
                            Progress.WriteLine("ABORTING... StopOnConsecutiveFails");
                            break;
                        }
                    }

                    var finalStats = solver.Statistics;
                    if (finalStats != null)
                    {
                        foreach (var fs in finalStats)
                        {
                            Report.WriteLine("Statistics | {0}", fs);
                        }
                    }

                    if (Tracking != null) Tracking.End(result);

                    Report.WriteLine("[DONE] {0}", r.Summary);
                    if (result.Exception != null)
                    {
                        Report.WriteLine("[EXCEPTION]");
                        WriteException(Report, result.Exception);
                    }

                    Progress.WriteLine();
                    Progress.WriteLine("Completed: {0} ==> {1}", PuzzleHelper.GetName(puzzle), r.Summary);
                    Progress.WriteLine();

                    if (result.Exit == ExitConditions.Conditions.Aborted)
                    {
                        Progress.WriteLine("ABORTING...");
                        WriteSummary(res, start);
                        return res;
                    }

                    if (start.DurationInSec > run.BatchExit.Duration.TotalSeconds)
                    {
                        Progress.WriteLine("BATCH TIMEOUT...");
                        WriteSummary(res, start);
                        return res;
                    }

                    Progress.WriteLine();
                }
                catch (Exception ex)
                {
                    if (result != null) result.Exception = ex;
                    Progress.WriteLine("ERROR: "+ex.Message);
                    WriteException(Report, ex);
                }
                finally
                {
                    result = null;
                    Report.WriteLine("Ending Memory: {0}", Environment.WorkingSet);
                    GC.Collect();
                    Report.WriteLine("Post-GC Memory: {0}", Environment.WorkingSet);
                    Report.WriteLine("===================================");
                    Report.WriteLine();
                }

                Report.Flush();
            }
            WriteSummary(res, start);
            return res;
        }
        public void SingleThreadedForwardSolver_TreePoolPerformance_Large()
        {
            Console.WriteLine("IDEA: This puzzle has a relatively large amount of FLOOR space, which will create lots of Nodes in the TreePool");
            Console.WriteLine("[WILLOW: Started prep for multi-threading] 52000 nodes at 851.658640168867 nodes/sec. Exited EARLY. Time => Nodes: 52000, Dead: 0, Duration: 61.0573269 sec., Duplicates: 236306");
            Console.WriteLine("[WILLOW: Collection optimistion] 59000 nodes at 980.895125589307 nodes/sec. Exited EARLY. Time => Nodes: 59000, Dead: 0, Duration: 60.1491418 sec., Duplicates: 274401");
            Console.WriteLine("[Added Buffered inserts] 68000 nodes at 1129.36134313775 nodes/sec. Exited EARLY. Time => Nodes: 68000, Dead: 0, Duration: 60.2110214 sec., Duplicates: 476102");

            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(new String[]
                {
                    "##########",
                    "#O.......#",
                    "#O.....X.#",
                    "#O.......#",
                    "#........#",
                    "#........#",
                    "#....X...#",
                    "#...XPX..#",
                    "#....O...#",
                    "##########"
                }),
                Report = Console.Out,
                ExitConditions = new ExitConditions()
                {
                    Duration = TimeSpan.FromMinutes(1),
                    TotalNodes =  int.MaxValue,
                    TotalDead = int.MaxValue,
                    StopOnSolution = false // !!!!!!
                },
                Progress = new ConsoleProgressNotifier()

            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            Console.WriteLine("All Nodes");
            Console.WriteLine( (result as SingleThreadedForwardSolver.CommandResult).Pool.ToString());

            // assert
            Assert.That(result, Is.Not.Null);
        }