public Core.Sudoku Solve(Core.Sudoku s) { var internalRows = BuildInternalRowsForSudoku(s); var dlxRows = BuildDlxRows(internalRows); var solutions = _dlx .Solve(dlxRows, d => d, r => r) //.Where(solution => VerifySolution(internalRows, solution)) .ToImmutableList(); //Console.WriteLine(); if (solutions.Any()) { Console.WriteLine($"First solution (of {solutions.Count}):"); Console.WriteLine(); return(SolutionToSudoku(internalRows, solutions.First())); } else { Console.WriteLine("No solutions found!"); } return(null); }
public Core.Sudoku SolveCombinatorial(Core.Sudoku s) { var sudokuTab = (Core.Sudoku)s.Clone(); Console.WriteLine("Begin solving Sudoku using combinatorial evolution"); Console.WriteLine("The Sudoku is:"); var sudoku = CombinatorialSudoku.Convert(sudokuTab); const int numOrganisms = 200; const int maxEpochs = 5000; const int maxRestarts = 40; Console.WriteLine($"Setting numOrganisms: {numOrganisms}"); Console.WriteLine($"Setting maxEpochs: {maxEpochs}"); Console.WriteLine($"Setting maxRestarts: {maxRestarts}"); var solver = new CombinatorialSudokuSolver(); var solvedSudoku = solver.Solve(sudoku, numOrganisms, maxEpochs, maxRestarts); Console.WriteLine(solvedSudoku.Error == 0 ? "Success" : "Did not find optimal solution"); Console.WriteLine("End Sudoku using combinatorial evolution"); var solution = ConvertSolution(solvedSudoku); return(solution); }
public Core.Sudoku Solve(Core.Sudoku s) { var toReturn = SolveCombinatorial(s); return(toReturn); }
/// <summary> /// Constructor that accepts a Sudoku to solve /// </summary> /// <param name="targetCore.Sudoku">the target sudoku to solve</param> public SudokuCellsChromosome(Core.Sudoku targetSudoku) : base(81) { _targetSudoku = targetSudoku; for (int i = 0; i < Length; i++) { ReplaceGene(i, GenerateGene(i)); } }
public Core.Sudoku Solve(Core.Sudoku s) { //var toReturn = SolveCombinatorial(s); var toReturn = SolveGeneticSharp(s); return(toReturn); }
/// <summary> /// Constructor with a mask and a number of genes /// </summary> /// <param name="targetCore.Sudoku">the target sudoku to solve</param> /// <param name="length">the number of genes</param> public SudokuPermutationsChromosome(Core.Sudoku targetSudoku, int length) : base(length) { TargetSudoku = targetSudoku; TargetRowsPermutations = GetRowsPermutations(TargetSudoku); for (int i = 0; i < Length; i++) { ReplaceGene(i, GenerateGene(i)); } }
public Core.Sudoku Solve(Core.Sudoku s) { var solution = (Core.Sudoku)s.Clone(); var model = BaseModel.LoadModel(DataSetHelper.GetFullPath(@"Sudoku.NeuralNetwork\Models\sudoku.model")); solution = Model.SolveSudoku(solution, model); Console.WriteLine(solution); return(solution); }
/// <summary> /// Evaluates a single Sudoku board by counting the duplicates in rows, boxes /// and the digits differing from the target mask. /// </summary> /// <param name="testSudoku">the board to evaluate</param> /// <returns>the number of mistakes the Sudoku contains.</returns> public double Evaluate(Core.Sudoku testSudoku) { var cells = testSudoku.Cells.Select((c, i) => new { index = i, cell = c }).ToList(); var toTest = cells.GroupBy(x => x.index / 9).Select(g => g.Select(c => c.cell)) // rows .Concat(cells.GroupBy(x => x.index % 9).Select(g => g.Select(c => c.cell))) //columns .Concat(cells.GroupBy(x => x.index / 27 * 27 + x.index % 9 / 3 * 3).Select(g => g.Select(c => c.cell))); //boxes var toReturn = -toTest.Sum(test => test.GroupBy(x => x).Select(g => g.Count() - 1).Sum()); toReturn -= cells.Count(x => _targetSudoku.Cells[x.index] > 0 && _targetSudoku.Cells[x.index] != x.cell); return(toReturn); }
// Récupération de la solution public static void SetValuesFromAssignment(Assignment a, Core.Sudoku s) { foreach (Variable objVar in a.getVariables().toArray()) { int rowIdx = 0; int colIdx = 0; GetIndices(objVar, ref rowIdx, ref colIdx); int value = (int)a.getAssignment(objVar); s.SetCell(rowIdx, colIdx, value); } }
// Fonction principale pour construire le CSP à partir d'un masque de Sudoku à résoudre public static CSP GetSudokuCSP(Core.Sudoku s) { //initialisation à l'aide des contraintes communes var toReturn = GetSudokuBaseCSP(); // Ajout des contraintes spécifiques au masque fourni //var sArray = s.getInitialSudoku(); var cellVars = toReturn.getVariables(); //récupération du masque var mask = new Dictionary <int, int>(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { var cellVal = s.GetCell(i, j); if (cellVal != 0) { mask[i * 9 + j] = cellVal; } } } //Ajout des contraintes de masque en faisant défiler les variables existantes var maskQueue = new Queue <int>(mask.Keys); var currentMaskIdx = maskQueue.Dequeue(); var currentVarName = GetVarName(currentMaskIdx / 9, currentMaskIdx % 9); foreach (Variable objVar in cellVars.toArray()) { if (objVar.getName() == currentVarName) { //toReturn.addConstraint(new ValueConstraint(objVar, mask[currentMaskIdx])); var cellValue = mask[currentMaskIdx]; toReturn.setDomain(objVar, new Domain(new object[] { cellValue })); if (maskQueue.Count == 0) { break; } currentMaskIdx = maskQueue.Dequeue(); currentVarName = GetVarName(currentMaskIdx / 9, currentMaskIdx % 9); } } return(toReturn); }
/// <summary> /// Evaluates a single Sudoku board by counting the duplicates in rows, boxes /// and the digits differing from the target mask. /// </summary> /// <param name="testSudoku">the board to evaluate</param> /// <returns>the number of mistakes the Sudoku contains.</returns> public double Evaluate(Core.Sudoku testSudoku) { // We use a large lambda expression to count duplicates in rows, columns and boxes var cells = testSudoku.Cells.Select((c, i) => new { index = i, cell = c }).ToList(); var toTest = cells.GroupBy(x => x.index / 9).Select(g => g.Select(c => c.cell)) // rows .Concat(cells.GroupBy(x => x.index % 9).Select(g => g.Select(c => c.cell))) //columns .Concat(cells.GroupBy(x => x.index / 27 * 27 + x.index % 9 / 3 * 3).Select(g => g.Select(c => c.cell))); //boxes var toReturn = -toTest.Sum(test => test.GroupBy(x => x).Select(g => g.Count() - 1).Sum()); // Summing over duplicates toReturn -= cells.Count(x => _targetSudoku.Cells[x.index] > 0 && _targetSudoku.Cells[x.index] != x.cell); // Mask return(toReturn); }
/// <summary> /// builds a single Sudoku from the given row permutation genes /// </summary> /// <returns>a list with the single Sudoku built from the genes</returns> public virtual IList <Core.Sudoku> GetSudokus() { var listInt = new List <int>(81); for (int i = 0; i < 9; i++) { var perm = GetPermutation(i); listInt.AddRange(perm); } var sudoku = new Core.Sudoku(listInt); return(new List <Core.Sudoku>(new[] { sudoku })); }
public static Core.Sudoku SolveSudoku(Core.Sudoku s, BaseModel model) { NDarray sFeatures = np.array(s.Cells.ToArray()).reshape(9, 9); sFeatures = (sFeatures / 9) - 0.5; var prediction = Solve(sFeatures, model); return(new Core.Sudoku() { Cells = prediction.flatten().astype(np.int32).GetData <int>().ToList() }); }
public Core.Sudoku ConvertSolution(CombinatorialSudoku sudoku) { var list = new List <int> { }; for (int row = 1; row <= 9; row++) { for (int column = 1; column <= 9; column++) { list.Add(sudoku.CellValues[row - 1, column - 1]); } } var output = new Core.Sudoku(list); return(output); }
public Core.Sudoku Solve(Core.Sudoku s) { //Construction du CSP var objCSP = SudokuCSPHelper.GetSudokuCSP(s); // Résolution du Sudoku var objChrono = Stopwatch.StartNew(); var assignation = _Strategy.solve(objCSP); Console.WriteLine($"Pure solve Time : {objChrono.Elapsed.TotalMilliseconds} ms"); //Traduction du Sudoku SudokuCSPHelper.SetValuesFromAssignment(assignation, s); return(s); }
private void Run() { Inputs = new int[Core.Sudoku.SIZE, Core.Sudoku.SIZE]; for (int y = 0; y < Core.Sudoku.SIZE; y++) { System.Console.Out.WriteLine($"Enter line {y + 1}, followed by enter key"); for (int x = 0; x < Core.Sudoku.SIZE; x++) { while (true) { int key = System.Console.Read(); var number = key - 48; if (number >= 0 && number <= 9) { Inputs[x, y] = number; break; } } } } // var transposedInput = new int[Core.Sudoku.SIZE, Core.Sudoku.SIZE]; // for (var i = 0; i < Core.Sudoku.SIZE; i++) // { // for (var j = 0; j < Core.Sudoku.SIZE; j++) // { // transposedInput[i, j] = Inputs[j, i]; // } // } for (int y = 0; y < 9; y++) { for (int x = 0; x < 9; x++) { System.Console.Out.Write($"{Inputs[x, y]}".PadRight(10, ' ')); } System.Console.Out.WriteLine(); } _sudoku = new Core.Sudoku(this); _sudoku.Solve(); }
public Core.Sudoku SolveWithTimeLimit(Core.Sudoku puzzle, TimeSpan maxDuration) { try { Core.Sudoku toReturn = null; Task task = Task.Factory.StartNew(() => toReturn = Solver.Solve(puzzle.CloneSudoku())); task.Wait(maxDuration); if (!task.IsCompleted) { throw new ApplicationException($"Solver {ToString()} has exceeded the maximum allowed duration {maxDuration.TotalSeconds} seconds"); } return(toReturn); } catch (AggregateException ae) { throw ae.InnerExceptions[0]; } }
private IList <IList <IList <int> > > GetRowsPermutationsUncached(Core.Sudoku objSudoku) { var toReturn = new List <IList <IList <int> > >(9); for (int i = 0; i < 9; i++) { var tempList = new List <IList <int> >(); foreach (var perm in AllPermutations) { // Permutation should match current mask row numbers, and have numbers different that other mask rows if (!Range9.Any(rowIdx => Range9.Any(j => objSudoku.GetCell(rowIdx, j) > 0 && ((rowIdx == i && perm[j] != objSudoku.GetCell(rowIdx, j)) || (rowIdx != i && perm[j] == objSudoku.GetCell(rowIdx, j)))))) { tempList.Add(perm); } } toReturn.Add(tempList); } return(toReturn); }
/// <summary> /// This method computes for each row the list of digit permutations that respect the target mask, that is the list of valid rows discarding columns and boxes /// </summary> /// <param name="Core.Sudoku">the target sudoku to account for</param> /// <returns>the list of permutations available</returns> public IList <IList <IList <int> > > GetRowsPermutations(Core.Sudoku objSudoku) { if (objSudoku == null) { return(UnfilteredPermutations); } // we store permutations to compute them once only for each target Sudoku if (!_rowsPermutations.TryGetValue(objSudoku, out var toReturn)) { // Since this is a static member we use a lock to prevent parallelism. // This should be computed once only. lock (_rowsPermutations) { if (!_rowsPermutations.TryGetValue(objSudoku, out toReturn)) { toReturn = GetRowsPermutationsUncached(objSudoku); _rowsPermutations[objSudoku] = toReturn; } } } return(toReturn); }
public static CombinatorialSudoku Convert(Core.Sudoku sudoku) { var problem = new[, ] { { 0, 0, 7, 0, 0, 2, 9, 3, 0 }, { 0, 8, 1, 0, 0, 0, 0, 0, 5 }, { 9, 0, 4, 7, 0, 0, 1, 6, 0 }, { 0, 1, 0, 8, 0, 0, 0, 0, 6 }, { 8, 4, 6, 0, 0, 0, 5, 9, 2 }, { 5, 0, 0, 0, 0, 6, 0, 1, 0 }, { 0, 9, 2, 0, 0, 8, 3, 0, 1 }, { 4, 0, 0, 0, 0, 0, 6, 5, 0 }, { 0, 6, 5, 4, 0, 0, 2, 0, 0 } }; for (int row = 1; row <= 9; row++) { for (int column = 1; column <= 9; column++) { problem[row - 1, column - 1] = sudoku.GetCell(row - 1, column - 1); } } return(new CombinatorialSudoku(problem)); }
private void btnSolve_Click(object sender, System.EventArgs e) { txtStatus.Text = string.Empty; _sudoku = new Core.Sudoku(this); _sudoku.Solve(); }
/// <summary> /// Builds a single Sudoku from the 81 genes /// </summary> /// <returns>A Sudoku board built from the 81 genes</returns> public IList <Core.Sudoku> GetSudokus() { var sudoku = new Core.Sudoku(GetGenes().Select(g => (int)g.Value)); return(new List <Core.Sudoku>(new[] { sudoku })); }
private static IImmutableList <Tuple <int, int, int, bool> > BuildInternalRowsForSudoku(Core.Sudoku s) { var rowsByCols = from row in Rows from col in Cols let value = s.GetCell(row, col) select BuildInternalRowsForCell(row, col, value); return(rowsByCols.SelectMany(cols => cols).ToImmutableList()); }
/// <summary> /// Constructor with a mask sudoku to solve, assuming a length of 9 genes /// </summary> /// <param name="targetCore.Sudoku">the target sudoku to solve</param> public SudokuPermutationsChromosome(Core.Sudoku targetSudoku) : this(targetSudoku, 9) { }
public Core.Sudoku SolveGeneticSharp(Core.Sudoku s) { var populationSize = 5000; IChromosome sudokuChromosome = new SudokuPermutationsChromosome(s); //IChromosome sudokuChromosome = new SudokuCellsChromosome(s); var fitnessThreshold = 0; var crossoverProbability = 0.75f; var mutationProbability = 0.2f; var fitness = new SudokuFitness(s); var selection = new EliteSelection(); var crossover = new UniformCrossover(); var mutation = new UniformMutation(); IChromosome bestIndividual; var solution = s; int nbErrors = int.MaxValue; do { var population = new Population(populationSize, populationSize, sudokuChromosome); var ga = new GeneticAlgorithm(population, fitness, selection, crossover, mutation) { Termination = new OrTermination(new ITermination[] { new FitnessThresholdTermination(fitnessThreshold), new FitnessStagnationTermination(10), //new GenerationNumberTermination(generationNb) //new TimeEvolvingTermination(TimeSpan.FromSeconds(10)), }), MutationProbability = mutationProbability, CrossoverProbability = crossoverProbability, OperatorsStrategy = new TplOperatorsStrategy(), }; ga.GenerationRan += delegate(object sender, EventArgs args) { bestIndividual = (ga.Population.BestChromosome); solution = ((ISudokuChromosome)bestIndividual).GetSudokus()[0]; nbErrors = solution.NbErrors(s); Console.WriteLine($"Generation #{ga.GenerationsNumber}: best individual has {nbErrors} errors"); }; ga.Start(); //bestIndividual = (ga.Population.BestChromosome); //solution = ((ISudokuChromosome)bestIndividual).GetSudokus()[0]; //nbErrors = solution.NbErrors(s); if (nbErrors == 0) { break; } else { populationSize *= 2; Console.WriteLine($"Genetic search failed with {nbErrors} resulting errors, doubling population to {populationSize}"); } } while (true); return(solution); }
public Core.Sudoku Solve(Core.Sudoku s) { var toReturn = SolveGeneticSharp(s); return(toReturn); }
public SudokuFitness(Core.Sudoku targetSudoku) { _targetSudoku = targetSudoku; }
public static (BaseModel model, double accuracy) TrainAndTest(BaseModel model) { // Global parameters string datasetPath = @"Sudoku.NeuralNetwork\Dataset\sudoku.csv.gz"; int numSudokus = 1000; // ML parameters double testPercent = 0.2; float learningRate = .001F; int batchSize = 32; int epochs = 2; Console.WriteLine("Initialize dataset"); var(sPuzzles, sSols) = DataSetHelper.ParseCSV(datasetPath, numSudokus); var(_sPuzzzlesTrain, _sPuzzlesTest) = DataSetHelper.SplitDataSet(sPuzzles, testPercent); var(_sSolsTrain, _sSolsTest) = DataSetHelper.SplitDataSet(sSols, testPercent); Console.WriteLine("Preprocess data"); var sPuzzzlesTrain = DataSetHelper.PreprocessSudokus(_sPuzzzlesTrain); var sSolsTrain = DataSetHelper.PreprocessSudokus(_sSolsTrain); var sPuzzlesTest = DataSetHelper.PreprocessSudokus(_sPuzzlesTest); var sSolsTest = DataSetHelper.PreprocessSudokus(_sSolsTest); // Add optimizer var adam = new Keras.Optimizers.Adam(learningRate); model.Compile(loss: "sparse_categorical_crossentropy", optimizer: adam); Console.WriteLine("Train model"); model.Fit(sPuzzzlesTrain, sSolsTrain, batch_size: batchSize, epochs: epochs); // Test model int correct = 0; for (int i = 0; i < 1; i++) { Console.WriteLine("Testing " + i); // Predict result var prediction = Solve(sPuzzlesTest[i], model); // Convert to sudoku var sPredict = new Core.Sudoku() { Cells = prediction.flatten().astype(np.int32).GetData <int>().ToList() }; var sSol = new Core.Sudoku() { Cells = ((sSolsTest[i] + 0.5) * 9).flatten().astype(np.int32).GetData <int>().ToList() }; // Compare sudoku var same = true; for (int j = 0; j < 9; j++) { for (int k = 0; k < 9; k++) { if (sPredict.GetCell(j, k) != sSol.GetCell(j, k)) { same = false; } } } Console.WriteLine("Prediction : \n" + sPredict); Console.WriteLine("Solution : \n" + sSol); if (same) { correct += 1; } } // Calculate accuracy var accuracy = (correct / sPuzzlesTest.size) * 100; // Return return(model, accuracy); }
public Core.Sudoku Solve(Core.Sudoku s) { return(s); }