LispWorks 中的嵌套 for 循环(4x4 皇后区)

Nested for-loop in LispWorks (4x4 queens)

我刚开始使用 LispWorks,正在研究 4x4 Queen 问题。我想做的是在 4 个 for 循环的帮助下说明所有可能的 Queen 组合,然后检查它们是否是可能的解决方案。例如,可能的状态 (1 3 4 2) 表示第 1 行中的皇后在第 1 列中,第 2 行中的皇后在第 3 列中,依此类推。

我认为我做错了什么,因为编译器不喜欢我的循环。我收到的错误类似于:Loop keyword expected in...

代码如下:

(loop for i in '(1 2 3 4) 
  nconc (loop for j in '(1 2 3 4) 
              nconc (loop for k in '(1 2 3 4) 
                          nconc (loop for l in '(1 2 3 4) 


                                     (defvar first 0)
                                     (defvar second 0)
                                     (defvar third 0)
                                     (defvar fourth 0)
                                     (setq first (abs (- 1 i)))
                                     (setq second (abs (- 2 j)))
                                     (setq third (abs (- 3 k)))
                                     (setq fourth (abs (- 4 l)))
                                     (if (and (not (eq first second)) (not (eq first third)) (not (eq first fourth)) (not (eq second third)) 
                                                (not (eq second fourth)) (not (eq first second)) (not (eq third fourth)))
                                           (if (and (or (eq i j) (eq i k) (eq i l) (eq j k) (eq j l)) (or (eq k l)))
                                               (print i j k l)))))))

请帮助我解决嵌套循环问题,并随时对我的代码发表评论,并可能提出解决此问题的更好方法。请保持它相当基础,我是 LispWorks 的完全初学者,我之前只做过一些 ADA 95 和 Java。

提前致谢

您收到错误消息的原因是您的代码在内循环中 '(1 2 3 4) 之后缺少关键字 do。由于您不是从循环中收集结果,只是打印最终结果,因此您也应该在外循环中使用 do 而不是 nconc

修复此问题,出现另一个错误:print 仅打印一个对象,因此为了打印所有四个数字,您可以使用 例如 (print (list i j k l))

然后程序打印

(1 1 1 1) 
(1 3 1 1) 
(2 2 1 1) 
(4 2 2 2) 
(4 4 3 3) 
(4 4 4 4)

所以逻辑也有问题。

不过,代码还有很多可以改进的地方:

  1. 不要使用defvar在循环内引入新变量。 defvar 创建动态 ("global") 变量。相反,使用 let,或将它们作为循环变量引入,就像您对 ij .
  2. 所做的那样
  3. 不是先创建变量,然后使用 setq 更新它们一次,而是在创建它们时给它们正确的值(使用 let 或循环关键字)。
  4. 当您比较数字对时:不要使用 eq(用于符号)或 eql(比较两个相同类型的数字的正确方法),而是使用=/= 可以比较许多数字以检查它们是否都是 equal/different.

连同逻辑的小修正,这导致了以下代码(为了说明,引入了一些使用循环关键字的变量,以及一些使用 let 的变量):

(loop for i in '(1 2 3 4) 
      for first = (abs (- 1 i)) 
      do (loop for j in '(1 2 3 4)
               for second = (abs (- 2 j))
               do (loop for k in '(1 2 3 4)
                        do (loop for l in '(1 2 3 4)
                                 do (let ((third (abs (- 3 k)))
                                           (fourth (abs (- 4 l))))
                                       (if (and (/= first second third fourth)
                                                (/= i j k l))
                                          (print (list i j k l))))))))

这导致

(2 4 3 1) 
(3 2 4 1) 
(4 1 3 2) 
(4 2 1 3) 

表示仍然存在逻辑错误。

希望简化的代码可以很容易地发现错误,这可能与未比较(+ i 1)(+ j 2) [有关=33=]

最后:如果您想扩展代码以处理更多皇后,创建递归解决方案将比使用更多嵌套循环的解决方案更好。