Sudoku表生成器故障,lisp [英] Sudoku table generator failure, lisp

查看:75
本文介绍了Sudoku表生成器故障,lisp的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Lisp代码的某些部分有问题.它是一个数独表生成器.直到这一部分,它都可以正常工作:

I have a problem with some part of my lisp code. It is a sudoku table generator. It works fine until this part:

(loop for e in entries do     
    (if (and (not (member e sub))
             (not (member e col)))
        (progn (setq choices (nconc choices (list e)))
               (print choices)))
    (if (= (length choices) 1)
        (setq pick (car choices))
        (if (not (= (length choices) 0)) 
            (setq pick (nth (random (+ 0 (length choices))) choices))))

基本上,我在行x和列y上,我需要插入一个元素.我看着该元素和列的子矩阵,然后选择上面没有出现的数字并将其放在那里.那就是"pick"变量.问题是,有时"choices"变量会获得NIL值,尽管在条目循环中它具有正确的值.当它变为NIL时,pick值保持与上一个循环相同(我在该代码段上方循环进入列和行),使我的最终表具有无效的输出(例如,一行中的双精度值).如何跟踪选择变量的变化位置?我仅在此代码段中使用它,我不明白为什么它突然变为nil.

Basically, I am on a row x and a column y, and I need to insert an element. I watch the submatrix for this element and for column, and I choose the number that isn't appearing in any of the above and put it there. That's the "pick" variable. The problem is that sometimes the "choices" variable gets NIL value although in entries loop it has the right value. When it gets NIL, the pick value stays the same as it was in last loop (I am looping in columns and rows, above this snippet), making my final table have invalidated output (double values in a row, for example). How can I track where the choices variable changes? I work with it only in this snippet and I don't understand why it changes suddenly to nil.

例如,我通常有:

  • 在条目循环中:选择(5)
  • 退出条目循环:选择(5)
  • 在条目循环中:选择(6 7)
  • 退出条目循环:选择(6 7),然后选择一个:
  • 在条目循环中:选择为零.

谢谢.

推荐答案

首先,重新格式化:

(loop for e in entries do     
  (if (and (not (member e sub))
           (not (member e col)))
      (progn (setq choices (nconc choices (list e))) 
             (print choices)))
(if (= (length choices) 1)
    (setq pick (car choices))
(if (not (= (length choices) 0))
    (setq pick (nth (random (+ 0 (length choices))) choices))))

然后,如果不需要if的替代子句,但需要progn,则可以使用when:

Then, if you don't need the alternative clause of if, but want a progn, you can use when:

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (setq choices (nconc choices (list e))) 
    (print choices))
(if (= (length choices) 1)
    (setq pick (car choices))
(if (not (= (length choices) 0))
    (setq pick (nth (random (+ 0 (length choices))) choices))))

最后两个if子句是互斥的,因此condcase都是合适的(我现在将使用cond):

The last two if clauses are mutually exclusive, so either cond or case would be appropriate (I'll use cond for now):

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (setq choices (nconc choices (list e))) 
    (print choices))
(cond ((= (length choices) 1)
       (setq pick (car choices)))
      ((not (= (length choices) 0))
       (setq pick (nth (random (+ 0 (length choices))) choices))))

有一个zerop谓词:

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (setq choices (nconc choices (list e))) 
    (print choices))
(cond ((= (length choices) 1)
       (setq pick (car choices)))
      ((not (zerop (length choices)))
       (setq pick (nth (random (+ 0 (length choices))) choices))))

我看不到将0加到某个值会完成什么:

I don't see what adding 0 to some value should accomplish:

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (setq choices (nconc choices (list e))) 
    (print choices))
(cond ((= (length choices) 1)
       (setq pick (car choices)))
      ((not (zerop (length choices)))
       (setq pick (nth (random (length choices)) choices))))

除非您确定首先将pick设置为明智的默认设置,否则您可能应该具有默认情况(这可能是您的问题之一):

Unless you are sure that pick is set to a sensible default to begin with, you should perhaps have a default case (this may be one of your problems):

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (setq choices (nconc choices (list e))) 
    (print choices))
(cond ((= (length choices) 1)
       (setq pick (car choices)))
      ((not (zerop (length choices)))
       (setq pick (nth (random (length choices)) choices)))
      (t
       (setq pick nil))

您可以使用push(而不是使用setqnconc)(这会将新元素放在列表的开头,但是由于您还是随机选择,因此不必担心):

Instead of using setq and nconc, you can use push (this puts the new element at the start of the list, but since you pick randomly anyway, this shouldn't be a concern):

(loop for e in entries do     
  (when (and (not (member e sub))
             (not (member e col)))
    (push e choices)
    (print choices))
(cond ((= (length choices) 1)
       (setq pick (car choices)))
      ((not (zerop (length choices)))
       (setq pick (nth (random (length choices)) choices)))
      (t
       (setq pick nil))

我怀疑在此代码段的开头应该将choices设为(),在此代码段之后您不需要choices,并且打印choices仅用于调试,因此您可以通过使用remove-if并更改条件来以不同的方式执行此操作:

I suspect that at the start of this snippet, choices is supposed to be (), that you don't need choices after this snippet, and that printing choices is just for debugging, so you could do this in a different way by using remove-if and changing the condition:

(let ((choices (remove-if (lambda (e)
                            (or (member e sub)
                                (member e col)))
                          entries)))
  (print choices)
  (cond ((= (length choices) 1)
         (setq pick (car choices)))
        ((not (zerop (length choices)))
         (setq pick (nth (random (length choices)) choices)))
        (t
         (setq pick nil)))

如果现在将choices打印为(),则意味着这里没有任何选择,因此您将必须进行一些回溯(或达到死胡同时的算法).

If choices is printed as () now, it means that there are no choices left here, so you will have to do some backtracking then (or whatever your algorithm does when a dead end is reached).

最后,由于(length choices)只能是非负整数,因此如果以不同的顺序测试个案,则可以使用case代替cond:

Finally, since (length choices) can only be non-negative integers, you can use case instead of cond if you test the cases in different order:

(let ((choices (remove-if (lambda (e)
                            (or (member e sub)
                                (member e col)))
                          entries)))
  (print choices)
  (case (length choices)
    (0 (setq pick nil))
    (1 (setq pick (car choices)))
    (otherwise (setq pick (nth (random (length choices)) choices)))))

根据请求

更新.

正如Rainer指出的那样,这基本上是pick函数的主体,因此我们可以摆脱所有自由变量.此外,您可以使用(用于列表)更具描述性的名称first代替car:

As Rainer points out, this is basically the body of a pick function, so we can get rid of all the free variables. Also, instead of car, you can use the (for lists) more descriptive name first:

(defun pick (entries sub col)
  (let ((choices (remove-if (lambda (e)
                              (or (member e sub)
                                  (member e col)))
                            entries)))
    (print choices)
    (case (length choices)
      (0 nil)
      (1 (first choices))
      (otherwise (nth (random (length choices)) choices)))))

此函数将在其他地方定义,并且在代码段的位置将被这样称呼:

This function would be defined elsewhere, and in the snippet's place, it would be called like this:

(pick entries sub col)

为了不计算两次(length choices),我们可以将其放入let(对于串行评估,该值必须变为let*):

In order not to compute (length choices) twice, we can put that into the let (which needs to become let* for serial evaluation):

(defun pick (entries sub col)
  (let* ((choices (remove-if (lambda (e)
                               (or (member e sub)
                                   (member e col)))
                             entries))
         (choices-length (length choices)))
    (print choices)
    (case choices-length
      (0 nil)
      (1 (first choices))
      (otherwise (nth (random choices-length) choices)))))

最后一步(实际上是可选的,但也许您发现有更多序列会减少选择范围,例如row)将有点笼统:

A final step (really optional, but perhaps you discover that you have more sequences reducing your choices, e.g. row) would be a little generalization:

(defun pick (entries &rest exclusion-sequences)
  (let* ((choices (remove-if (lambda (e)
                               (some #'identity
                                     (mapcar (lambda (seq)
                                               (member e seq))
                                             exclusion-sequences)))
                             entries))
         (choices-length (length choices)))
    (print choices)
    (case choices-length
      (0 nil)
      (1 (first choices))
      (otherwise (nth (random choices-length) choices)))))

对此函数的调用具有相同的形状,但是您现在可以使用任意数量的排除序列:

The call to this function is of the same shape, but you can now use any number of exclusion sequences:

(pick entries col sub row ver ima fou)

这篇关于Sudoku表生成器故障,lisp的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆