Scheme 如何在方案中最好地实现裸单和隐单
我正在计划中编写一个数独解算器。我将电路板单元表示为3x3向量的3x3向量,并在每个单元中列出候选编号。例如,一块空白板和更新其中一个单元格Scheme 如何在方案中最好地实现裸单和隐单,scheme,racket,sudoku,Scheme,Racket,Sudoku,我正在计划中编写一个数独解算器。我将电路板单元表示为3x3向量的3x3向量,并在每个单元中列出候选编号。例如,一块空白板和更新其中一个单元格 (define blank-board-cell (for/list ([x 9]) (add1 x))) (define blank-row (make-vector 9 blank-board-cell)) (define blank-board (make-vector 9 blank-row)) (define
(define blank-board-cell (for/list ([x 9]) (add1 x)))
(define blank-row (make-vector 9 blank-board-cell))
(define blank-board (make-vector 9 blank-row))
(define (board-ref b row col)
(vector-ref (vector-ref b row) col))
(define (board-update b target-row target-col new-cell)
(for/vector ([row (vector-length b)])
(for/vector ([col (vector-length b)])
(cond [(and (= row target-row)
(= col target-col))
new-cell]
[else (board-ref b row col)]))))
我想实施裸单和隐单策略来解决董事会问题。
裸单:查找空单元格,通过查看其行、列和3x3块的内容可以推断其值。如果已经为这些相邻单元分配了8个编号,则空单元必须包含最后剩余的编号,并且必须从同一行、列和3x3块中的单元中删除该编号
例如,在Java/命令式样式中
boolean nakedSingles()
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
HashSet<Integer> cellCandidates = board[row][col].candidates;
if (cellCandidates.size()==1)
{
board[row][col].setValue(cellCandidates.iterator().next());
//remove candidate from neighboring cells
return true;
}
}
}
return false;
}
boolean hiddenSingles()
{
int [] unitCandidates = new int[10];
// For each row, column or boxID
for (int unitSelect = 0; unitSelect < 3; unitSelect++)
{
for (int i = 0; i < 9; i++)
{
if (unitSelect == 0)
{
unit = getRow(i);
}
else if (unitSelect == 1)
{
unit = getCol(i);
}
else if (unitSelect == 2)
{
unit = getBox(i + 1);
}
for (int n = 1; n <= 9; n++)
{
unitCandidates[n] = 0;
}
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
for (int cand:board[row][col].candidates)
{
unitCandidates[cand] += 1;
}
}
}
int foundDigit = 0;
for (int n = 1; n <= 9; n++)
{
// Check for hidden single
if (unitCandidates[n] == 1)
{
// Found hidden single
foundDigit = n;
break;
}
}
// If a hidden single was found, check what cell
// contained that hidden single and set cellvalue
if (foundDigit != 0)
{
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
if (board[row]col].candidates.contains((Object)
foundDigit))
{
board[row][col].setValue(foundDigit);
removeDigitfrom(row,col);
return true;
}
}
}
}
}
}
return false;
}
这看起来合理/正确吗
隐藏单个:通过查看行、列和3x3块,可以清楚地看到,虽然单元格本身可能有多个候选,但只有一个候选。我们将该候选者分配给单元格,并将其从同一行、列和3x3块中的单元格中删除
例如,在Java/命令式样式中
boolean nakedSingles()
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
HashSet<Integer> cellCandidates = board[row][col].candidates;
if (cellCandidates.size()==1)
{
board[row][col].setValue(cellCandidates.iterator().next());
//remove candidate from neighboring cells
return true;
}
}
}
return false;
}
boolean hiddenSingles()
{
int [] unitCandidates = new int[10];
// For each row, column or boxID
for (int unitSelect = 0; unitSelect < 3; unitSelect++)
{
for (int i = 0; i < 9; i++)
{
if (unitSelect == 0)
{
unit = getRow(i);
}
else if (unitSelect == 1)
{
unit = getCol(i);
}
else if (unitSelect == 2)
{
unit = getBox(i + 1);
}
for (int n = 1; n <= 9; n++)
{
unitCandidates[n] = 0;
}
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
for (int cand:board[row][col].candidates)
{
unitCandidates[cand] += 1;
}
}
}
int foundDigit = 0;
for (int n = 1; n <= 9; n++)
{
// Check for hidden single
if (unitCandidates[n] == 1)
{
// Found hidden single
foundDigit = n;
break;
}
}
// If a hidden single was found, check what cell
// contained that hidden single and set cellvalue
if (foundDigit != 0)
{
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
if (board[row]col].candidates.contains((Object)
foundDigit))
{
board[row][col].setValue(foundDigit);
removeDigitfrom(row,col);
return true;
}
}
}
}
}
}
return false;
}
boolean hiddenSingles()
{
int[]单位候选人=新的int[10];
//对于每一行、每一列或每一个boxID
对于(int unitSelect=0;unitSelect<3;unitSelect++)
{
对于(int i=0;i<9;i++)
{
如果(unitSelect==0)
{
单位=getRow(i);
}
else if(unitSelect==1)
{
单位=getCol(i);
}
else if(unitSelect==2)
{
单位=getBox(i+1);
}
对于(int n=1;n,您可以通过一点冗余来简化和加速您的方法
电路板单元格应仅包含两种类型的值-一个数字或一个特殊值,表示该值仍需确定。这样,您可以快速找到所有尚未确定的单元格
同时,保留一组可能的值
- 每行
- 每列
- 每单元
在创建空白板时,使用所有可能的值(1到9)初始化所有
创建一个设置单元格值的过程(最初从外部格式读取电路板时使用,或找到要设置的值时使用),并确保
- 您可以在电路板上设置单元格的值
- 从行的值集中删除该值
- 从列的值集中删除该值
- 清除可能值的单元格集(可选)
在电路板上迭代(我称之为“通过1”),对于每个尚未确定的单元,计算行、列和单元的集合交点。如果只剩下一个值,则使用前面描述的过程。如果没有留下值,则电路板无法解算。“裸单”和“隐藏单”之间没有区别
迭代,直到您在pass上成功,并且没有找到任何东西
保留待确定的单元格数量,并在将单元格设置为某个值时递减。这样,您就可以知道电路板的求解时间
许多数独难题都可以通过这种方式解决,但对于一些问题,你需要一个“pass2”,在这里你递归地尝试一个单元格的所有值,看看这是否有助于你找到其他的值一个值,返回到第1关,这会更快。请注意,在第2关中,如果副本与原件没有结构共享,则需要复制电路板的副本。我喜欢将此问题视为一个难题,但此处显示的工作量不足,无法以任何好的方式提供帮助。只需运行(空白电路板)
使用你的代码,你会发现你已经有问题了。谢谢我修复了你提到的代码。我不想把所有的实用程序代码都放在黑板上,我必须防止弄乱帖子。但是我可以添加可能有用的东西。我可以添加一些代码,或者链接到我用Racket编写的数独解算器,它实现了我描述的所有内容。但我觉得您可能更喜欢自己创建大部分代码。请随意询问任何特定部分,甚至整个代码。我将这一点留给您。“请注意,您需要在pass 2中复制您的董事会,其中副本与原件没有结构共享。”我最近的一次尝试是通过一个树结构实现了这个板,它可以让你免费回溯。