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); }