Scheme 如何在方案中最好地实现裸单和隐单

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

我正在计划中编写一个数独解算器。我将电路板单元表示为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 (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中复制您的董事会,其中副本与原件没有结构共享。”我最近的一次尝试是通过一个树结构实现了这个板,它可以让你免费回溯。