C# 如何生成有效的数独板?[和难度评级]
我在做一个数独程序。目前,我可以生成一个有效的数独板,但我不知道生成的是简单的还是困难的 这是我的建议: 我从生成完整的电路板开始。最后一块板是空的 我开始在21个随机单元格中填充来自全板的值 我找到最后一块板的所有解决方案,对于每个单元格,计算整个板的解决方案差异的次数,选择其中差异最大的一个,然后填充它。(这个想法来源于这里:第一个答案) 这样做,直到你只有一个解决方案 现在,我不知道这个有21个随机单元的方法是否正确。有时,在前21个随机单元之后,我会有很多解,有时会有一些 目前,我以平均0.3秒的时间生成最终板 我想告诉我一个不同的、快速的方法,除了这个方法,有21个随机单元,也许我可以在那里对棋盘的难度进行排序C# 如何生成有效的数独板?[和难度评级],c#,algorithm,sudoku,C#,Algorithm,Sudoku,我在做一个数独程序。目前,我可以生成一个有效的数独板,但我不知道生成的是简单的还是困难的 这是我的建议: 我从生成完整的电路板开始。最后一块板是空的 我开始在21个随机单元格中填充来自全板的值 我找到最后一块板的所有解决方案,对于每个单元格,计算整个板的解决方案差异的次数,选择其中差异最大的一个,然后填充它。(这个想法来源于这里:第一个答案) 这样做,直到你只有一个解决方案 现在,我不知道这个有21个随机单元的方法是否正确。有时,在前21个随机单元之后,我会有很多解,有时会有一些 目前,我以平均
谢谢大家! 看看这段代码,它实现了3个难度级别{Easy,Medium,Hard}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SuperSudoku
{
public enum Difficulty
{
Easy, Medium, Hard
}
class PuzzleGenerator
{
private PuzzleSolver puzzleSolver;
/// <summary>
///
/// </summary>
public PuzzleGrid PermaGrid;
/// <summary>
///
/// </summary>
public PuzzleGrid SolutionGrid;
/// <summary>
///
/// </summary>
private Difficulty difficulty;
/// <summary>
/// This constructs a puzzle generator class.
/// </summary>
/// <param name="difficultyIn">The difficulty to generate a new puzzle.</param>
public PuzzleGenerator(Difficulty difficultyIn)
{
puzzleSolver = new PuzzleSolver();
difficulty = difficultyIn;
}
public PuzzleGrid InitGrid()
{ //Randomly fill in the first row and column of puzzlegrid
PuzzleGrid tempGrid = new PuzzleGrid { }; //temporary grid to assign values into
int row = 0; //variable for navigating 'rows'
int col = 0; //variable for navigating 'columns'
int newVal; //value to place into grid
bool solved;
List<int> valueSet = new List<int>(Enumerable.Range(-9, 9)); //range
//of numbers that can be added to the grid
List<int> valueSet2 = new List<int>(); //placeholder values in column 0
Random rnd = new Random(); //random variable for choosing random number
int randIndex = 0; //index in valueSet/valueSet2 that is accessed
randIndex = rnd.Next(0,8); //get a random number and place in grid(0,0)
newVal = valueSet[randIndex];
tempGrid.InitSetCell(row,col,newVal);
valueSet.Remove(newVal); //remove paced value from options
for(row = 1; row < 9; row++)
{ //fills in column 0 with remaining possible values, storing in place-
//holder as it goes so as to preserve when placing in row 0 later
randIndex = rnd.Next(0,valueSet.Count);
newVal = valueSet[randIndex];
valueSet2.Add(newVal);
valueSet.Remove(newVal);
tempGrid.InitSetCell(row,col,newVal);
}
row = 0; //reset row to 0
for(col = 1; col < 3; col++)
{ //fills in col 1,2 of row 0, checking that don't duplicate the
//values in rows 1,2 of col 0
randIndex = rnd.Next(0,valueSet2.Count);
newVal = valueSet2[randIndex];
while((newVal == tempGrid.Grid[1,0]||(newVal == tempGrid.Grid[2,0])))
{
randIndex = rnd.Next(0,valueSet2.Count);
newVal = valueSet2[randIndex];
}
valueSet2.Remove(newVal);
tempGrid.InitSetCell(row,col,newVal);
}
for(col = 3; col < 9; col++)
{ //fill in remainder of row 0 with remaining possible values
randIndex = rnd.Next(0,valueSet2.Count);
newVal = valueSet2[randIndex];
valueSet2.Remove(newVal);
tempGrid.InitSetCell(row,col,newVal);
}
do
{
puzzleSolver = new PuzzleSolver();
puzzleSolver.SolveGrid((PuzzleGrid)tempGrid.Clone(), false); //Slv to fill remainder of grid
SolutionGrid = puzzleSolver.SolutionGrid;
} while (SolutionGrid == null || SolutionGrid.IsBlank());
PermaGrid = Blanker(SolutionGrid); //call Blanker to carry out the
return PermaGrid; //blanking of fileds,then return the grid to user to solve
}
// Call SolveGrid to solve puzzlegrid
//Store solved gamegrid as the correct solution in solutiongrid
public PuzzleGrid Blanker(PuzzleGrid solvedGrid)
{ //enable blanking of squares based on difficulty
PuzzleGrid tempGrid;
PuzzleGrid saveCopy;
//temporary grids to save between tests
bool unique = true; //flag for if blanked form has unique soln
int totalBlanks = 0; //count of current blanks
int tries = 0; //count of tries to blank appropriately
int desiredBlanks; //amount of blanks desired via difficulty
int symmetry = 0; //symmetry type
tempGrid = (PuzzleGrid)solvedGrid.Clone();
//cloned input grid (no damage)
Random rnd = new Random(); //allow for random number generation
switch (difficulty) //set desiredBlanks via chosen difficulty
{
case Difficulty.Easy: //easy difficulty
desiredBlanks = 40;
break;
case Difficulty.Medium: //medium difficulty
desiredBlanks = 45;
break;
case Difficulty.Hard: //hard difficulty
desiredBlanks = 50;
break;
default: //easy difficulty
desiredBlanks = 40;
break;
}
symmetry = rnd.Next(0, 2); //Randomly select symmetry
do
{ //call RandomlyBlank() to blank random squares symmetrically
saveCopy = (PuzzleGrid)tempGrid.Clone(); // in case undo needed
tempGrid = RandomlyBlank(tempGrid, symmetry, ref totalBlanks);
//blanks 1 or 2 squares according to symmetry chosen
puzzleSolver = new PuzzleSolver();
unique = puzzleSolver.SolveGrid((PuzzleGrid)tempGrid.Clone(), true); // will it solve uniquely?
if(!unique)
{
tempGrid = (PuzzleGrid)saveCopy.Clone();
tries++;
}
} while((totalBlanks < desiredBlanks) && (tries < 1000));
solvedGrid = tempGrid;
solvedGrid.Finish();
return solvedGrid;
}
public PuzzleGrid RandomlyBlank(PuzzleGrid tempGrid, int sym, ref int blankCount)
{
//blank one or two squares(depending on if on center line) randomly
Random rnd = new Random(); //allow random number generation
int row = rnd.Next(0, 8); //choose randomly the row
int column = rnd.Next(0, 8); //and column of cell to blank
while (tempGrid.Grid[row, column] == 0) //don't blank a blank cell
{
row = rnd.Next(0, 8);
column = rnd.Next(0, 8);
}
tempGrid.InitSetCell(row, column, 0); //clear chosen cell
blankCount++; //increment the count of blanks
switch (sym)
{
//based on symmetry, blank a second cell
case 0: //vertical symmetry
if (tempGrid.Grid[row, 8 - column] != 0) //if not already blanked
blankCount++; //increment blank counter
tempGrid.InitSetCell(row, 8 - column, 0); //blank opposite cell
break;
case 1: //horizontal symmetry
if (tempGrid.Grid[8 - row, column] != 0)
blankCount++;
tempGrid.InitSetCell(8 - row, column, 0);
break;
case 2: //diagonal symmetry
if (tempGrid.Grid[column, row] != 0)
blankCount++;
tempGrid.InitSetCell(column, row, 0);
break;
default: //diagonal symmetry
if (tempGrid.Grid[row, 8 - column] != 0)
blankCount++;
tempGrid.InitSetCell(column, row, 0);
break;
}
return tempGrid;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
名称空间SuperSudoku
{
公共枚举困难
{
容易,中等,难
}
类生成器
{
私人解谜;
///
///
///
公共农业;
///
///
///
公共网格解决方案网格;
///
///
///
私人困难;
///
///这将构造一个益智生成器类。
///
///产生新谜题的难度。
公共拼图生成器(难度)
{
拼图解算器=新的拼图解算器();
困难=困难;
}
公共网格InitGrid()
{//随机填写表格的第一行和第一列
PuzzleGrid tempGrid=new PuzzleGrid{};//要将值分配到的临时网格
int row=0;//用于导航“rows”的变量
int col=0;//用于导航“列”的变量
int newVal;//要放入网格的值
布尔解;
列表值集=新列表(可枚举的.Range(-9,9));//范围
//可以添加到网格中的数字的数目
List valueSet2=new List();//列0中的占位符值
Random rnd=new Random();//用于选择随机数的随机变量
int randIndex=0;//访问的valueSet/valueSet2中的索引
randIndex=rnd.Next(0,8);//获取一个随机数并放入网格(0,0)
newVal=值集[randIndex];
InitSetCell(行、列、newVal);
valueSet.Remove(newVal);//从选项中删除带速度的值
用于(行=1;行<9;行++)
{//用剩余的可能值填充列0,并存储在适当的位置-
//保持原样,以便在以后放入第0行时保留
randIndex=rnd.Next(0,valueSet.Count);
newVal=值集[randIndex];
valueSet2.Add(newVal);
valueSet.Remove(newVal);
InitSetCell(行、列、newVal);
}
行=0;//将行重置为0
用于(列=1;列<3;列++)
{//填写第0行的第1,2列,检查是否与
//第0列第1,2行中的值
randIndex=rnd.Next(0,valueSet2.Count);
newVal=valueSet2[randIndex];
而((newVal==tempGrid.Grid[1,0]| |(newVal==tempGrid.Grid[2,0]))
{
randIndex=rnd.Next(0,valueSet2.Count);
newVal=valueSet2[randIndex];
}
valueSet2.删除(newVal);
InitSetCell(行、列、newVal);
}
用于(列=3;列<9;列++)
{//用剩余的可能值填充第0行的剩余部分
randIndex=rnd.Next(0,valueSet2.Count);
newVal=valueSet2[randIndex];
valueSet2.删除(newVal);
InitSetCell(行、列、newVal);
}
做
{
拼图解算器=新的拼图解算器();
拼图解算器.SolveGrid((拼图网格)tempGrid.Clone(),false);//填充网格其余部分的Slv
SolutionGrid=puzzsolver.SolutionGrid;
}而(SolutionGrid==null | | SolutionGrid.IsBlank());
PermaGrid=Blanker(SolutionGrid);//调用Blanker执行
return PermaGrid;//清空文件,然后将网格返回给用户进行求解
}
//调用SolveGrid来解决网格难题
//将已解决的gamegrid作为正确的解决方案存储在solutiongrid中
公共拼图栅格消隐器(拼图栅格解算栅格)
{//根据难度启用方块消隐
快速网格;
保存副本;
//要在测试之间保存的临时网格
bool unique=true;//空白窗体是否具有唯一的soln的标志
int totalBlanks=0;//当前空白的计数
int trytes=0;//尝试适当空白的次数
int desiredBlanks;//通过难度所需的空白量
int symmetry=0;//对称类型
tempGrid=(拼图网格)已解决
func getNumberSudoku() -> [[Int]] {
// Original number
let originalNum = [1,2,3,4,5,6,7,8,9]
// Create line 1 to 9 and shuffle from original
let line1 = originalNum.shuffled()
let line2 = line1.shift(withDistance: 3)
let line3 = line2.shift(withDistance: 3)
let line4 = line3.shift(withDistance: 1)
let line5 = line4.shift(withDistance: 3)
let line6 = line5.shift(withDistance: 3)
let line7 = line6.shift(withDistance: 1)
let line8 = line7.shift(withDistance: 3)
let line9 = line8.shift(withDistance: 3)
// Final array
let renewRow = [line1,line2,line3,line4,line5,line6,line7,line8,line9]
// Pre-shuffle for column
let colSh1 = [0,1,2].shuffled()
let colSh2 = [3,4,5].shuffled()
let colSh3 = [6,7,8].shuffled()
let rowSh1 = [0,1,2].shuffled()
let rowSh2 = [3,4,5].shuffled()
let rowSh3 = [6,7,8].shuffled()
// Create the let and var
let colResult = colSh1 + colSh2 + colSh3
let rowResult = rowSh1 + rowSh2 + rowSh3
var preCol: [Int] = []
var finalCol: [[Int]] = []
var prerow: [Int] = []
var finalRow: [[Int]] = []
// Shuffle the columns
for x in 0...8 {
preCol.removeAll()
for i in 0...8 {
preCol.append(renewRow[x][colResult[i]])
}
finalCol.append(preCol)
}
// Shuffle the rows
for x in 0...8 {
prerow.removeAll()
for i in 0...8 {
prerow.append(finalCol[x][rowResult[i]])
}
finalRow.append(prerow)
}
// Final, create the array into the [[Int]].
return finalRow
}
var resultSudoku = [[Int]]
resultSudoku = getNumberSudoku()