cteeters
cteeters

Reputation: 49

lisp difference between plus and minus

Alright, so I'm writing a program in Lisp to solve the tile puzzle (http://www.tilepuzzles.com/default.asp?p=12) and I have a problem with two of my functions. I have separate functions to "swap" the empty tile with the one above, below, left or right of it, but only the above and left are working. The only difference between the switch_above and switch_below is the use of a + in one and a - in the other (see code) and as far as I can tell that is what is causing a problem.

;;Switches the Empty tile with whatever is above it
(defun switch_above (state)
  (let ((x (nth (- (find_empty state) 3) state)))    ;;Find the number that   is above the Empty tile, set as X
    (setf (nth (find_empty state) state) x)          ;;Replace the Empty tile with X
    (setf (nth (position x state) state) 'E)) state) ;;Put Empty tile where X was

;;Switches the Empty tile with whatever is below it
(defun switch_below (state)
  (let ((x (nth (+ (find_empty state) 3) state)))    ;;Find the number that is below the Empty tile, set as X
    (setf (nth (find_empty state) state) x)          ;;Replace the Empty tile with X
    (setf (nth (position x state) state) 'E)) state) ;;Put Empty tile where X was

The "state" list is set up like this: (1 2 3 4 E 5 6 7 8) where E is the empty tile

find_empty returns the location of the empty tile, so it would return 4 in the above state.

As they are written switch_above works, but switch_below does not.

Upvotes: 1

Views: 436

Answers (1)

Rainer Joswig
Rainer Joswig

Reputation: 139401

Think about what happens when you do the first SETF in switch_below.

ROTATEF rotates places

Try to use the Common Lisp macro ROTATEF instead. See this example:

CL-USER 76 > (defun find-empty (state)
               (position 'e state))
FIND-EMPTY

CL-USER 77 > (defun switch-below (state &aux (empty-pos (find-empty state)))
               (rotatef (nth empty-pos       state)
                        (nth (+ empty-pos 3) state))
               state)
SWITCH-BELOW

CL-USER 78 > (switch-below '(1 2 3 4 E 5 6 7 8))
(1 2 3 4 7 5 6 E 8)

Btw.: if one wonders why I have used a quote list in the interaction above. In Common Lisp the consequences of modifying a literal list are undefined. Well, we are in a Lisp Listener (a Read Eval Print Loop). The read part typically allocates a fresh new list for each interaction and in the implementations usually these lists are not protected in any way. What could go wrong? a) The list could be protected agains modification. b) it could share structure with other lists (which might be difficult to detect by a user).

In a program it is better to write something like

(switch-below (copy-list '(1 2 3 4 E 5 6 7 8)))

to avoid the mentioned problems.

Upvotes: 4

Related Questions