2014-11-08 3 views
1

Common LISP에서 기본 slitherlink 게임을 구현하려고합니다. 현재 보드의 모든 라인 목록을 가져 오는 방법을 구현하려고합니다. 그러나 LISP 재귀와 함께 뭔가 이상한 일이 일어나고 있으며, 왜 이런 일이 일어나고 있는지 우둔합니다. "|"예기치 않게 작동하는 조건부 종료 문

(defun check-loop(loop-list to-check) 
    (loop for line in loop-list 
     do (if (and (equal (car line) (car to-check)) (equal (cadr line) (cadr to-check))) 
       (format t "~% Check passed for ~S in ~S" to-check loop-list) 
      (return-from check-loop T))) 
    (format t "~% Check failed for ~S in ~S" to-check loop-list) 
    nil) 

(defun get-loop(board loop-list x y &optional (from-x -1) (from-y -1)) 
    (let ((x-limit (array-dimension board 0)) 
     (y-limit (array-dimension board 1))) 
    (if (and (equal from-x -1) (equal from-y -1)) 
     (format t "~% x-limit=~3D y-limit=~3D" x-limit y-limit)) 
    (format t "~% loop-list is ~S and x=~3D y=~3D from-x= ~3D from-y=~3D" loop-list x y from-x from-y) 
    (cond ((check-loop loop-list (list x y)) 
      (progn (format t "~%Returned with ~S. while x =~3D y=~3D" loop-list x y) 
        (return-from get-loop loop-list))) 
      ((not (check-loop loop-list (list x y))) 
      (setq loop-list (append loop-list (list (list x y)))) 
      (format t "~% loop-list after append is ~S and x=~3D y=~3D" loop-list x y) 
      (if (and (not (< (1- x) 0)) (not (< (1- y) 0))) 
       (if (and (is-line board (1- x) (1- y)) (and (/= (1- x) from-x) (/= (1- y) from-y))) 
        (progn (format t "~%Here - 1 to ~3D ~3D" (1- x) (1- y)) 
          (setq loop-list (get-loop board loop-list (1- x) (1- y) x y))))) 
      (if (and (not (< (1- x) 0)) (< (1+ y) y-limit)) 
       (if (and (is-line board (1- x) (1+ y)) (and (/= (1- x) from-x) (/= (1+ y) from-y))) 
        (progn (format t "~%Here - 2 to ~3D ~3D" (1- x) (1+ y)) 
          (setq loop-list (get-loop board loop-list (1- x) (1+ y) x y))))) 
      (if (and (< (1+ x) x-limit) (not (< (1- y) 0))) 
       (if (and (is-line board (1+ x) (1- y)) (and (/= (1+ x) from-x) (/= (1- y) from-y))) 
        (progn (format t "~%Here - 3 to ~3D ~3D" (1+ x) (1- y)) 
          (setq loop-list (get-loop board loop-list (1+ x) (1- y) x y))))) 
      (if (and (< (1+ x) x-limit) (< (1+ y) y-limit)) 
       (if (and (is-line board (1+ x) (1+ y)) (and (/= (1+ x) from-x) (/= (1+ y) from-y))) 
        (progn (format t "~%Here - 4 to ~3D ~3D" (1+ x) (1+ y)) 
          (setq loop-list (get-loop board loop-list (1+ x) (1+ y) x y))))) 
      (cond ((equal (aref board x y) #\|) 
        (if(not (< (- x 2) 0)) 
         (if (and (is-line board (- 2 x) y) (/= (- 2 x) from-x)) 
          (progn (format t "~%Here - 5 to ~3D ~3D" (- x 2) y) 
           (setq loop-list (get-loop board loop-list (- 2 x) y x y))))) 
        (if(< (+ x 2) x-limit) 
         (if (and (is-line board (+ 2 x) y) (/= (+ 2 x) from-x)) 
          (progn (format t "~%Here - 6 to ~3D ~3D" (+ x 2) y) 
           (setq loop-list (get-loop board loop-list (+ 2 x) y x y)))))) 
       ((equal (aref board x y) #\-) 
        (if(not (< (- y 2) 0)) 
         (if (and (is-line board x (- 2 y)) (/= (- 2 y) from-y)) 
          (progn (format t "~%Here - 7 to ~3D ~3D" x (- y 2)) 
           (setq loop-list (get-loop board loop-list x (- 2 y) x y))))) 
        (if(< (+ y 2) y-limit) 
         (if (and (is-line board x (+ 2 y)) (/= (+ 2 y) from-y)) 
          (progn (format t "~%Here - 8 to ~3D ~3D" x (+ y 2)) 
           (setq loop-list (get-loop board loop-list x (+ 2 y) x y))))))))) 
    (format t "~% get-loop end with ~3D ~3D" x y) 
    (return-from get-loop loop-list))) 
문제의 세포 인 경우

는 IS-라인 기능은 단순히 확인하는 :

내 코드는 다음과 같이 보입니다 또는 "_". check-loop 함수는 특정 인덱스 목록이 루프 목록의 일부인지 확인합니다. get-loop 함수는 처음에 행이 주어질 때 보드에 루프의 일부로 행이있는 모든 인덱스 쌍 목록을 얻으려고합니다. 이 함수는 현재 행 다음에 오는 행으로 자신을 호출하여 행 (배열 색인 쌍)을 사용하여 재귀 적으로 호출합니다.

아래의 보드에 대해 get 루프를 호출하고 (배열), 루프 목록을 NIL로, x와 y를 각각 1과 0으로 호출합니다.

+ - + - + 
| 3  3 | 
+ - + - + 

출력은이 같은 모습을 얻을 :

x-limit= 3 y-limit= 5 
loop-list is NIL and x= 0 y= 1 from-x= -1 from-y= -1 
Check failed for (0 1) in NIL 
Check failed for (0 1) in NIL 
loop-list after append is ((0 1)) and x= 0 y= 1 
Here - 3 to 1 0 
loop-list is ((0 1)) and x= 1 y= 0 from-x= 0 from-y= 1 
Returned with ((0 1)). while x = 1 y= 0 
Here - 8 to 0 3 
loop-list is ((0 1)) and x= 0 y= 3 from-x= 0 from-y= 1 
Returned with ((0 1)). while x = 0 y= 3 
get-loop end with 0 1 
Finished. List is ((0 1)) 

는 내가 이해하지 못하는 것은 처음 returncheck-loop에서 인쇄 문이 실행되지 않기 때문에 실행중인 check-loop없이 실행되는 방식이다. 출력의 마지막 완성 된 행은 get-loop의 호출자가 인쇄합니다. 나는 아직도 멍청하다. 그래서 내가 바보가되어 명백한 것을 놓친다면 용서해주십시오. 도와 주셔서 미리 감사드립니다!

+0

이'무슨 일이 일어나고 있는지보고 (...) 추적 (GET-루프)는'를 사용하여 시도, 쓰기? – Barmar

+0

'Finished' 라인은 어디서 오는가? 'get-loop'가'get-loop end' 라인에 도착하면, 그것은리스트를 반환하지 않습니다. – Barmar

+0

코드가 매우 추해 보입니다. 단순화 또는 재구성하기 위해 리팩터링을 할 수 있습니다. –

답변

0

check-looploop-list의 첫 번째 줄이 테스트에 실패하면 아무 것도 인쇄하지 않습니다.

loop for line in loop-list에 들어가면 각 줄을 테스트합니다. 첫 번째 줄이 if 테스트에 실패하면 check passed 줄을 건너 뛰고 (return-from check-loop T)을 수행합니다. 따라서 check failed을 인쇄하지 마십시오. 당신이 당신의 if에서 다른 절을 필요로하지 않는 경우

대신 when를 사용

(defun check-loop(loop-list to-check) 
    (loop for line in loop-list 
     do (when (and (equal (car line) (car to-check)) (equal (cadr line) (cadr to-check))) 
      (format t "~% Check passed for ~S in ~S" to-check loop-list) 
      (return-from check-loop T))) 
    (format t "~% Check failed for ~S in ~S" to-check loop-list) 
    nil) 

을 당신은 테스트가 성공하면 그래서 그들은 모두 할거야 prognformatreturn-from을 둘 필요 , 단지 format이 아닙니다.

현재 line에는 두 개의 요소 만있는 경우 if (equal line to-check)으로 간단히 지정할 수 있습니다.

또한 get-loop에는 check-loop을 두 번 호출 할 필요가 없습니다. cond의 두 번째 절에 도달하면 check-loop이 실패 했으므로 (not (check-loop ...))을 테스트하지 않아도됩니다. 두 가지가 있기 때문에 if를 사용,

(cond ((check-loop ...) 
     (format ...) 
     (return-from ...)) 
     (t (setq ...) 
     ...)) 

을 또는 :

(if (check-loop) 
    (progn 
     (format ...) 
     (return-from ...)) 
    (progn 
     (setq ...) 
     ... 
    )) 
+0

고마워요! 그건 바보 같았 어, 바보 같아! 그 progn이 내 문제를 해결하는 것처럼 보였습니다. 또한 check-loop에 대한 두 번째 호출을 제거하고 제안 사항대로 T를 사용했습니다! 시간을내어 도와 주셔서 다시 한 번 감사드립니다. –