public SolvedPuzzleViewModel SolvePuzzle(PuzzleViewModel puzzleVM)
        {
            var solvedPuzzleVM = new SolvedPuzzleViewModel();

            solvedPuzzleVM.ErrorList = ValidatePuzzle(puzzleVM);
            if (solvedPuzzleVM.ErrorList.Any())
            {
                return(solvedPuzzleVM);
            }
            Initiator.Initialize(puzzleVM);
            UsedTileList.Clear();
            UsedTileDictionary = TileList.ToDictionary(s => s.TileNumber, s => false);

            var breakCount = 0;
            var tries      = new List <String>();

            var start = DateTime.Now;

            //After the first run, the DepthCounter dictionary should probably be updated to be * 2?
            //while (!solvedPuzzleVM.Solved && CheckedTileDictionary.Values.All(s => s == AmountOfMaximumTriesPerTile))
            while (!solvedPuzzleVM.Solved && AmountOfCheckedSolutions < AmountOfTotalSolutions && breakCount <= AmountOfTotalSolutions)
            {
                breakCount++;
                foreach (var tile in Initiator.TotalRotationTileList)
                {
                    if (solvedPuzzleVM.Solved)
                    {
                        break;
                    }
                    if (UsedTileDictionary[tile.TileNumber])
                    {
                        continue;
                    }

                    if (!UsedTileDictionary[tile.TileNumber])
                    {
                        UsedTileList.Add(tile);
                        UsedTileDictionary[tile.TileNumber] = true;
                    }

                    //var puzzleFieldCount = 0;
                    foreach (var puzzleTile in puzzleVM.TileIndexList.Where(s => !UsedPuzzleTilesIndices.Contains(s.Index)))
                    {
                        //There already is a tile on this puzzlefield
                        if (UsedPuzzleTilesIndices.Contains(puzzleTile.Index))
                        {
                            continue;
                        }

                        if (tile.PuzzleIndex >= 0)
                        {
                            break;
                        }
                        tile.PuzzleDepthCounter = PuzzleIndexCounter[puzzleTile.Index];
                        var tileKey = new UsedTileDictionaryKey(puzzleTile.Index, tile.TileNumber, tile.Degrees);

                        //var usedTileNumbers = new HashSet<int>(UsedTileList.Select(a => a.TileNumber));
                        //var tilesInSameLayer = CheckedTileDictionary.Keys.Where(s => s.PuzzleIndex == tileKey.PuzzleIndex && !usedTileNumbers.Contains(s.TileNumber));
                        //var lessAmount = tilesInSameLayer.Any(a => CheckedTileDictionary[a] < DynamicCheckedTileDictionary[tileKey]);

                        if (CheckedTileDictionary[tileKey] >= DynamicCheckedTileDictionary[tileKey])
                        {
                            RemoveAndResetPuzzleTile(tile);
                            //UsedPuzzleTilesIndices.Remove(tile.PuzzleIndex);
                            //UsedTileList.Remove(tile);
                            //UsedTileDictionary[tile.TileNumber] = false;
                            //tile.PuzzleIndex = -1;
                            //tile.PuzzleDepthCounter = 0;
                            break;
                        }

                        tile.PuzzleIndex = puzzleTile.Index;
                        UsedPuzzleTilesIndices.Add(puzzleTile.Index);

                        if (puzzleVM.UseBailout)
                        {
                            if (UsedTileList.Count >= 1 && UsedTileList.Count < SubmittedPuzzleTileCount)
                            {
                                if (DoEarlyBailOut())
                                {
                                    break;
                                }
                            }
                        }

                        if (UsedTileList.Count == SubmittedPuzzleTileCount)
                        {
                            AmountOfCheckedSolutions++;
                            //var solveString = String.Format("Trying to solve with: {0}", String.Join(" AND ", UsedTileList.OrderBy(s => s.PuzzleIndex).Select(s => s.ToString())));
                            //tries.Add(solveString);

                            FillPuzzleRoads(UsedTileList);
                            if (DoesDefinitiveRoadListSolvePuzzle(Initiator.SimpleConditionsList))
                            {
                                var newList = new List <Tile>();
                                //solvedPuzzleVM.Solved = true;
                                if (solvedPuzzleVM.TileSet.Count <= 2)
                                {
                                    foreach (var ut in UsedTileList)
                                    {
                                        var newTile = new Tile(ut.TileNumber, ut.Degrees);
                                        newTile.PuzzleIndex = ut.PuzzleIndex;
                                        newList.Add(newTile);
                                    }

                                    solvedPuzzleVM.TileSet.Add(newList);
                                }
                            }



                            //var allKeys = UsedTileList
                            //    .Select(s => new UsedTileDictionaryKey(s.PuzzleIndex, s.TileNumber, s.Degrees)).ToList();

                            //foreach (var key in allKeys)
                            //{
                            //    Initiator.CheckedTileDictionary[key]++;
                            //}

                            ////There are still other tile combinations to be checked
                            //foreach (var key in allKeys.OrderByDescending(s => s.PuzzleIndex))
                            //{
                            //    var relevantTile = UsedTileList.FirstOrDefault(s =>
                            //            s.TileNumber == key.TileNumber && s.Degrees == key.Degrees);

                            //    //See if one of the used keys (starting at the end) has been used too much
                            //    if (Initiator.CheckedTileDictionary[key] >= DynamicCheckedTileDictionary[key])
                            //    {
                            //        //UsedPuzzleTilesIndices.Remove(key.PuzzleIndex);
                            //        //UsedTileList.Remove(relevantTile);
                            //        //UsedTileDictionary[key.TileNumber] = false;

                            //        //We should only += the DynamicDepthCounter in the above layers.
                            //        var aboveLayer = OriginalDepthCounter.FirstOrDefault(s => s.Key > relevantTile.PuzzleDepthCounter);
                            //        if (aboveLayer.Key != 0)
                            //        {
                            //            var usedTileNumbersAboveThisLayer = allKeys.Where(s => s.PuzzleIndex < DepthToIndex[aboveLayer.Key]).Select(a => a.TileNumber).ToList();
                            //            var relevantIndex = DepthToIndex[aboveLayer.Key];
                            //            var everyKeyExceptUsedOnes = DynamicCheckedTileDictionary.Where(s =>
                            //            s.Key.PuzzleIndex == relevantIndex &&
                            //            !usedTileNumbersAboveThisLayer.Contains(s.Key.TileNumber)).ToList();

                            //            foreach (var keyEx in everyKeyExceptUsedOnes)
                            //            {
                            //                //Update the count for the next round
                            //                DynamicCheckedTileDictionary[keyEx.Key] += OriginalDepthCounter[aboveLayer.Key];
                            //            }
                            //        }

                            //        RemoveAndResetPuzzleTile(relevantTile);

                            //        //relevantTile.PuzzleDepthCounter = 0;
                            //        //relevantTile.PuzzleIndex = -1;
                            //    }
                            //}
                        }

                        CheckTileCountAndUpIfNeeded(false);
                    }
                }
            }

            var end = DateTime.Now;

            solvedPuzzleVM.SolveDuration            = (end - start);
            solvedPuzzleVM.AmountOfCheckedSolutions = AmountOfCheckedSolutions;
            solvedPuzzleVM.AmountOfTotalSolutions   = AmountOfTotalSolutions;
            solvedPuzzleVM.AmountOfFoundSolutions   = solvedPuzzleVM.TileSet.Count;
            solvedPuzzleVM.TriedSolutions           = tries;
            var nonMax           = Initiator.CheckedTileDictionary.Where(s => s.Value < AmountOfMaximumTriesPerTile).ToList();
            var nonCheckedAmount = nonMax.Sum(s => AmountOfMaximumTriesPerTile - s.Value);

            if (solvedPuzzleVM.AmountOfFoundSolutions == 1)
            {
                //Valid puzzle, lets write to JSON
                if (puzzleVM.Name != "Puzzle ")
                {
                    var jsonPuzzles    = GetJsonPuzzles();
                    var relevantPuzzle = jsonPuzzles.PuzzleList.FirstOrDefault(s => s.Name == puzzleVM.Name);
                    if (relevantPuzzle != null)
                    {
                        if (relevantPuzzle.BestSolveTime.TotalMilliseconds == 0 || solvedPuzzleVM.SolveDuration < relevantPuzzle.BestSolveTime)
                        {
                            solvedPuzzleVM.ErrorList.Add("New solve record!");
                            relevantPuzzle.BestSolveTime = solvedPuzzleVM.SolveDuration;
                            //open file stream
                            using (StreamWriter file = File.CreateText(JsonPuzzlesPath))
                            {
                                string         json       = JsonConvert.SerializeObject(jsonPuzzles);
                                JsonSerializer serializer = new JsonSerializer();
                                //serialize object directly into file stream
                                serializer.Serialize(file, jsonPuzzles);
                                solvedPuzzleVM.SavedPuzzleName = puzzleVM.Name;
                            }
                        }
                        else
                        {
                            solvedPuzzleVM.ErrorList.Add("Puzzle is already saved as: " + puzzleVM.Name + " !");
                        }
                    }
                }
            }

            return(solvedPuzzleVM);
        }