Reputation: 49
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
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