public static void Dump(SolutionState solution)
        {
            Console.WriteLine("Iterations: {0}", solution.IterationsCount);
            Console.WriteLine("Unique states created: {0}", solution.UniqueStatesCount);
            Console.WriteLine("Max front states count: {0}", solution.MaxFrontStatesCount);
            Console.WriteLine("Elapsed time: {0} ms", solution.ElapsedTime);

            var stateAtFinish = solution.State;

            if (stateAtFinish.IsFinished())
            {
                Console.WriteLine("Solution turns count: {0}", stateAtFinish.turn);
                foreach (var state in stateAtFinish.History)
                {
                    Console.WriteLine(state.ToString());
                }
            }
            else
            {
                Console.WriteLine("No solution found.");
            }
        }
        public SolutionState Solve_AStar()
        {
            var beginState = GetStartingState();

            if (beginState.IsFinished())
            {
                return(new SolutionState(beginState, 0, 0, 0, 0));
            }

            HashSet <StateHash> allUniqueStates = new HashSet <StateHash>();

            allUniqueStates.Add(beginState.Hash);

            PriorityQueue <GameState> frontStates = new PriorityQueue <GameState>(32000);

            frontStates.Add(beginState);

            int iterations          = 0;
            int maxFrontStatesCount = 0;

            var sw = Stopwatch.StartNew();

            GameState currentState = null;

            Func <StateHash, bool> checkHash = (hash) =>
            {
                return(allUniqueStates.Contains(hash) == false);
            };

            Func <GameState, Direction, bool> f = (state, dir) =>
            {
                GameState newState = GetNewState(state, dir, checkHash);
                if (newState != null)
                {
                    if (newState.IsFinished())
                    {
                        currentState = newState;
                        return(true);
                    }

                    allUniqueStates.Add(newState.Hash);
                    //if ((Symmetry & eMapSymmetry.Horizontal) == eMapSymmetry.Horizontal)
                    //    allUniqueStates.Add(GetHashForSymmetricState(newState, 1, 0));
                    //if ((Symmetry & eMapSymmetry.Vertical) == eMapSymmetry.Vertical)
                    //    allUniqueStates.Add(GetHashForSymmetricState(newState, 0, 1));
                    //if ((Symmetry & eMapSymmetry.Both) == eMapSymmetry.Both)
                    //    allUniqueStates.Add(GetHashForSymmetricState(newState, 1, 1));

                    newState.CalculateWeight(this);

                    frontStates.Add(newState);
                }
                return(false);
            };

            sw.Stop();

            while (frontStates.Count > 0)
            {
                currentState = frontStates.RemoveMin();

                if (f(currentState, Direction.Left))
                {
                    break;
                }
                if (f(currentState, Direction.Up))
                {
                    break;
                }
                if (f(currentState, Direction.Right))
                {
                    break;
                }
                if (f(currentState, Direction.Down))
                {
                    break;
                }

                iterations++;

                maxFrontStatesCount = Math.Max(maxFrontStatesCount, frontStates.Count);
            }

            SolutionState solution = new SolutionState(currentState, elapsedTime: (int)(sw.ElapsedMilliseconds),
                                                       iterationsCount: iterations,
                                                       maxFrontStatesCount: maxFrontStatesCount,
                                                       uniquesStatesCount: allUniqueStates.Count);

            return(solution);
        }