To write a general LISP program to test the Grid-World Robots of Chapters 2,5 of Nilsson.
Inputs include:
a. Size of the grid
b. Number and location of the boundaries
c. Sensory input and feature vector set
d. Production rule set used to simulate robot behavior
To generate LISP programs for the following cases:
a. To generate robot motion for the wall-following system on page 28
b. The system on page 73
c. Problem 2 in Exam 1
d. To do obstacle avoidance with a robot
I. Whose sensor set is {s1, s2, s3, s4, s5, s6, s7, s8}
II. Whose sensors are defective and can only sense {s1, s3, s5, s7}
III. Whose sensors are defective and can only sense {s2, s4, s6, s8}
e. Same as (d) but with obstacle-countouring
In order to program the robot required for the cases (a) – (e), I first write a general purpose robot program that can perform the basic operations that the robot needs to do, i.e.,
1. Move a single step north, east, south or west
2. Move according to conditions specified
Then for each case, specific programs are written that provide the robot with the following information (user input as required by the question):
a. The sensor values
b. The feature vectors
c. The production rules
d. The grid size and boundary location
I have followed Nilsson’s approach in most cases:
My specific approach to each part is detailed below:
Part A:
· Sensor set {s1, s2, s3, s4, s5, s6, s7, s8}
· Feature vectors {x1, x2, x3, x4} as follows:
X1 = s2 OR s3
X2 = s4 OR s5
X3 = s6 OR s7
X4 = s8 OR s1
· Production rules (representing x1 by /x1)
x4 (/x1) ® North
x3 (/x4) ® West
x2 (/x3) ® South
x1 (/x2) ® East
1 ® North
Part B:
· Defective sensor set {s2, s4, s6, s8}
· Feature vectors {x1, x2, x3, x4} as follows:
w2 = s2
w4 = s4
w6 = s6
w8 = s8
w1 = (old w2 = 1 AND state = east)
w3 = (old w4 = 1 AND state = south)
w5 = (old w6 = 1 AND state = west)
w7 = (old w8 = 1 AND state = north)
· Production rules
w2 (/w4) ® east
w4 (/x6) ® south
w6 (/w8) ® west
w8 (/w2) ® north
w1 ® north
w3 ® east
w5 ® south
w7 ® west
1 ® North
Part C
This is the same as Part B. So the same sensor and feature vector set can be used.
Part D
Obstacle Avoidance for my robot uses a very simple algorithm:
s2 ® South
s4 ® West
s6 ® North
s8 ® North
1 ® Wall following
For part (1), the wall following procedure would be as in part (a). For part (3), the wall following procedure would be as in part (b).
Part E
Obstacle contouring uses the same procedure as wall following. The only condition would be that the robot would have to start next to the obstacle rather than next to the wall.
For part (1), the procedure would be as in part (a). For part (3), the procedure would be as in part (b).
The algorithm of the robot program is as follows:
1. Set state, counter variables to initial values.
2. Print out initial location of the robot
3. Apply production rules, and move
4. Print out location of robot
5. Increment counter
6. If counter equals the number of iterations, then STOP
Else Loop
The robot program consists of the following functions:
Function Name |
Arguments |
Returns |
What function does |
At_xy() |
Pos-x, pos-y |
0 or 1 |
Returns the value (0 or 1) at position [pos-x, pos-y] in the grid. |
Aor() |
O1, o2 |
0 if both o1 and o2 are 0; 1 otherwise |
Arithmetic OR – does a Boolean OR on the inputs (which are binary) |
Aand() |
A1, a2 |
1 if both a1 and a2 are 1; 0 otherwise |
Arithmetic AND – does a Boolean AND on the inputs |
Anot() |
N |
1 if n=0; 0 if n=1 |
Arithmetic NOT – binary negation of input |
N() |
|
|
Moves the robot one step north if possible, otherwise returns an error |
S() |
|
|
Moves the robot one step north if possible, otherwise returns an error |
W() |
|
|
Moves the robot one step north if possible, otherwise returns an error |
E() |
|
|
Moves the robot one step north if possible, otherwise returns an error |
Move() |
|
|
Moves the robot as many times as requested by user input; also displays [x, y] coordinates of the robot. |
Each of the user input program consists of the following functions:
Function Name |
Arguments |
Returns |
What function does |
Sensor input functions – si() |
|
|
Returns the value of the grid at the particular cell around the robot |
The feature vector set – xi() or wi() |
|
|
Logical function of sensor values or older feature vectors |
Rules() |
|
|
Production rules specifying the robot motion |
All variables are global and are used across both the robot function and user input.
Varible Name |
Used for |
X |
x coordinate of the robot location |
Y |
y coordinate of the robot location |
State |
Direction the robot is currently moving (Values: north, south, east, west) |
I |
Counter variable |
Size |
Grid size with coordinates starting from 0 |
|
|
Grid-size |
Actual grid size |
Grid |
2-dimensional list containing the location of boundaries (in binary) |
ROBOT.LSP
; Returns the object (0 or 1) present
at co-ordinates
(defun at_xy (pos-x pos-y) (nth pos-x (nth pos-y grid)))
; Arithmetic OR – needed to combine
0s and 1s
(defun aor (o1 o2) (cond
( (eq (+ o1 o2) 0) 0 )
( t 1 )
))
; Arithmetic AND
(defun aand (a1 a2) (* a1 a2))
; Arithmetic NOT
(defun anot (n) (cond
( (eq n 0) 1 )
( (eq n 1) 0 )
))
; Move north
(defun n() (prog()
(if (< y 2) 'cannot_move_north
(setf y (1- y)) )
(setf state 'north)
))
; Move south
(defun s() (prog()
(if (> y (- size 2)) 'cannot_move_south
(setf y (1+ y)) )
(setf state 'south)
))
; Move west
(defun w() (prog()
(if (< x 2) 'cannot_move_west
(setf x (1- x)) )
(setf state 'west)
))
; Move east
(defun e() (prog()
(if (> x (- size 2)) 'cannot_move_east
(setf x (1+ x)) )
(setf state 'east)
))
; The runtime function – applies the
rules and prints
; the position the robot is at.
(defun move() (prog (i)
; Sets size to 1 – grid_size: so that coordinates start at 0
(setf size (1- grid-size))
; Set state to 0
(setf state 0)
(setf i 0)
; Print initial location
(print (list x y))
LOOP
; Apply production rules
(rules)
; Print current location
(print (list x y))
(setf i (1+ i))
; If iterations are complete, return T…
(if (> i iterations) (return t))
; … else continue
(go LOOP)
))
For parts (a), (b) and (c): the cells, starting position and robot’s motion, according to my input would be:
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
Cells
the robot cannot occupy |
|||
|
|
R |
|
|
|
|
|
||
|
|
|
|
|
|
|
R The robot’s starting position |
||
|
|
|
|
|
|
|
Motion
of the robot |
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
(a)
PART-A.LSP
; The set s – points around the robot
(defun s1() (at_xy (1- x) (1- y)))
(defun s2() (at_xy x (1- y)))
(defun s3() (at_xy (1+ x) (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s5() (at_xy (1+ x) (1+ y)))
(defun s6() (at_xy x (1+ y)))
(defun s7() (at_xy (1- x) (1+ y)))
(defun s8() (at_xy (1- x) y ))
; The feature vector x
(defun x1() (aor (s2) (s3)))
(defun x2() (aor (s4) (s5)))
(defun x3() (aor (s6) (s7)))
(defun x4() (aor (s8) (s1)))
; Rules that the robot follows
(defun rules() (cond
( (eq (aand (x4) (anot (x1))) 1) (n) )
( (eq (aand (x3) (anot (x4))) 1) (w) )
( (eq (aand (x2) (anot (x3))) 1) (s) )
( (eq (aand (x1) (anot (x2))) 1) (e) )
( t (n) )
))
; User variables
(setf grid-size 8)
(setf iterations 25)
(setf grid '((1 1 1 1 1 1 1 1)
(1 0 0 1 1 0 0 1)
(1 0 0 1 1 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 1 1 0 0 1)
(1 1 1 1 1 1 1 1)
))
(setf x '2 y '2)
OUTPUT
> (load "robot.lsp")
; loading robot.lsp
T
> (load "part-a.lsp")
; loading part-a.lsp
T
> (move)
(2 2)
(2 3)
(3 3)
(4 3)
(5 3)
(5 2)
(5 1)
(6 1)
(6 2)
(6 3)
(6 4)
(6 5)
(6 6)
(5 6)
(5 5)
(4 5)
(3 5)
(2 5)
(2 6)
(1 6)
(1 5)
(1 4)
(1 3)
(1 2)
(1 1)
(2 1)
(2 2)
T
(b)
PART-B.LSP
; Variables for memory operations
(setf o_w2 '0 o_w4 '0 o_w6 '0 o_w8 '0 o_state '0)
; The robot’s sensor values
(defun s2() (at_xy x (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s6() (at_xy x (1+ y)))
(defun s8() (at_xy (1- x) y ))
; Rules the robot follows
(defun rules() (prog()
; w2, w4, w6, w8 – Current sensor values
(setf w2 (s2))
(setf w4 (s4))
(setf w6 (s6))
(setf w8 (s8))
; w1, w3, w5, w7 – Memory based values
(setf w1 (and (eq o_w2 1) (eq o_state 'east)))
(setf w3 (and (eq o_w4 1) (eq o_state 'south)))
(setf w5 (and (eq o_w6 1) (eq o_state 'west)))
(setf w7 (and (eq o_w8 1) (eq o_state 'north)))
(cond
( (eq (aand w2 (anot w4)) 1) (e) )
( (eq (aand w4 (anot w6)) 1) (s) )
( (eq (aand w6 (anot w8)) 1) (w) )
( (eq (aand w8 (anot w2)) 1) (n) )
( w1 (n) )
( w3 (e) )
( w5 (s) )
( w7 (w) )
( t (n) )
)
; Used to remember current state
(setf o_w2 w2)
(setf o_w4 w4)
(setf o_w6 w6)
(setf o_w8 w8)
(setf o_state state)
))
; User variables
(setf grid-size 8)
(setf iterations 25)
(setf grid '((1 1 1 1 1 1 1 1)
(1 0 0 1 1 0 0 1)
(1 0 0 1 1 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 1 1 0 0 1)
(1 1 1 1 1 1 1 1)
))
(setf x '2 y '2)
OUTPUT
> (load "robot.lsp")
; loading robot.lsp
T
> (load "part-b.lsp")
; loading part-b.lsp
T
> (move)
(2 2)
(2 3)
(3 3)
(4 3)
(5 3)
(5 2)
(5 1)
(6 1)
(6 2)
(6 3)
(6 4)
(6 5)
(6 6)
(5 6)
(5 5)
(4 5)
(3 5)
(2 5)
(2 6)
(1 6)
(1 5)
(1 4)
(1 3)
(1 2)
(1 1)
(2 1)
(2 2)
T
(c)
The solution for Problem 2 in Exam 1 is the same as the solution for Part B, i.e., the robot that can only sense {s2, s4, s6, s8}.
(d) Obstacle avoidance
For part (d) (1, 2, 3): the cells, starting position and robot’s motion, according to my input would be (as mentioned before, the robot does extremely simple obstacle avoidance! That is why it keeps cycling in the indicated place):
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
Cells
the robot cannot occupy |
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
R The robot’s starting position |
||
|
|
|
|
|
R |
|
Motion
of the robot |
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
(1)
PART-D1.LSP
(defun s1() (at_xy (1- x) (1- y)))
(defun s2() (at_xy x (1- y)))
(defun s3() (at_xy (1+ x) (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s5() (at_xy (1+ x) (1+ y)))
(defun s6() (at_xy x (1+ y)))
(defun s7() (at_xy (1- x) (1+ y)))
(defun s8() (at_xy (1- x) y ))
(defun x1() (aor (s2) (s3)))
(defun x2() (aor (s4) (s5)))
(defun x3() (aor (s6) (s7)))
(defun x4() (aor (s8) (s1)))
(defun rules() (cond
( (eq (s2) 1) (s) )
( (eq (s8) 1) (e) )
( (eq (s6) 1) (n) )
( (eq (s4) 1) (w) )
( (eq (aand (x4) (anot (x1))) 1) (n) )
( (eq (aand (x3) (anot (x4))) 1) (w) )
( (eq (aand (x2) (anot (x3))) 1) (s) )
( (eq (aand (x1) (anot (x2))) 1) (e) )
( t (n) )
)
(setf o_state state)
)
(setf grid-size 8)
(setf iterations 20)
(setf grid '((1 1 1 1 1 1 1 1)
(1 0 0 1 1 0 0 1)
(1 0 0 1 1 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 1 1 0 0 1)
(1 1 1 1 1 1 1 1)
))
(setf x '5 y '4)
OUTPUT
> (load "robot.lsp")
; loading robot.lsp
T
> (load "part-d1.lsp")
; loading part-d1.lsp
T
> (move)
(5 4)
(5 3)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
T
(2)
A robot that can sense only {s1, s3, s5, s7} cannot do obstacle avoidance since it cannot see the cells directly in front of it, i.e., the cells it needs to move to.
(3)
PART-D3.LSP
(setf o_w2 '0 o_w4 '0 o_w6 '0 o_w8 '0 o_state '0)
(defun s2() (at_xy x (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s6() (at_xy x (1+ y)))
(defun s8() (at_xy (1- x) y ))
(defun rules() (prog()
(setf w2 (s2))
(setf w4 (s4))
(setf w6 (s6))
(setf w8 (s8))
(setf w1 (and (eq o_w2 1) (eq o_state 'east)))
(setf w3 (and (eq o_w4 1) (eq o_state 'south)))
(setf w5 (and (eq o_w6 1) (eq o_state 'west)))
(setf w7 (and (eq o_w8 1) (eq o_state 'north)))
(cond
( (eq (s2) 1) (s) )
( (eq (s8) 1) (e) )
( (eq (s6) 1) (n) )
( (eq (s4) 1) (w) )
( (eq (aand w2 (anot w4)) 1) (e) )
( (eq (aand w4 (anot w6)) 1) (s) )
( (eq (aand w6 (anot w8)) 1) (w) )
( (eq (aand w8 (anot w2)) 1) (n) )
( w1 (n) )
( w3 (e) )
( w5 (s) )
( w7 (w) )
( t (n) )
)
(setf o_w2 w2)
(setf o_w4 w4)
(setf o_w6 w6)
(setf o_w8 w8)
(setf o_state state)
))
; USER INPUT
(setf grid-size 8)
(setf iterations 25)
(setf grid '((1 1 1 1 1 1 1 1)
(1 0 0 1 1 0 0 1)
(1 0 0 1 1 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 1)
(1 0 0 1 1 0 0 1)
(1 1 1 1 1 1 1 1)
))
(setf x '5 y '4)
OUTPUT
> (load "robot.lsp")
; loading robot.lsp
T
> (load "part-d3.lsp")
; loading part-d3.lsp
T
> (move)
(5 4)
(5 3)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
(5 2)
(6 2)
T
(e) Obstacle contouring
For part (e) (1, 2, 3): the cells, starting position and robot’s motion, according to my input would be:
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
Cells
the robot cannot occupy |
||
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
R The robot’s starting position |
||
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
Motion
of the robot |
||
|
|
|
|
|
R |
|
|
|
||
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
(1)
PART-E1.LSP
(defun s1() (at_xy (1- x) (1- y)))
(defun s2() (at_xy x (1- y)))
(defun s3() (at_xy (1+ x) (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s5() (at_xy (1+ x) (1+ y)))
(defun s6() (at_xy x (1+ y)))
(defun s7() (at_xy (1- x) (1+ y)))
(defun s8() (at_xy (1- x) y ))
(defun x1() (aor (s2) (s3)))
(defun x2() (aor (s4) (s5)))
(defun x3() (aor (s6) (s7)))
(defun x4() (aor (s8) (s1)))
(defun rules() (cond
( (eq (aand (x4) (anot (x1))) 1) (n) )
( (eq (aand (x3) (anot (x4))) 1) (w) )
( (eq (aand (x2) (anot (x3))) 1) (s) )
( (eq (aand (x1) (anot (x2))) 1) (e) )
( t (n) )
))
(setf grid-size 9)
(setf iterations 25)
(setf grid '((1 1 1 1 1 1 1 1 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 1 1 1 1 1 1 1 1)
))
(setf x '5 y '6)
OUTPUT
> (load "robot.lsp")
; loading robot.lsp
T
> (load "part-e1.lsp")
; loading part-e1.lsp
T
> (move)
(5 6)
(6 6)
(6 5)
(6 4)
(6 3)
(6 2)
(5 2)
(4 2)
(3 2)
(2 2)
(2 3)
(2 4)
(2 5)
(2 6)
(3 6)
(4 6)
(5 6)
(6 6)
(6 5)
(6 4)
(6 3)
(6 2)
(5 2)
(4 2)
(3 2)
(2 2)
(2 3)
T
(2)
As explained in (d) (2), a robot that can only sense {s1, s3, s5, s7} cannot be used for obstacle contouring since it is unable to see the cells that it had to move to.
(3)
PART-E3.LSP
(setf o_w2 '0 o_w4 '0 o_w6 '0 o_w8 '0 o_state '0)
(defun s2() (at_xy x (1- y)))
(defun s4() (at_xy (1+ x) y ))
(defun s6() (at_xy x (1+ y)))
(defun s8() (at_xy (1- x) y ))
(defun rules() (prog()
(setf w2 (s2))
(setf w4 (s4))
(setf w6 (s6))
(setf w8 (s8))
(setf w1 (and (eq o_w2 1) (eq o_state 'east)))
(setf w3 (and (eq o_w4 1) (eq o_state 'south)))
(setf w5 (and (eq o_w6 1) (eq o_state 'west)))
(setf w7 (and (eq o_w8 1) (eq o_state 'north)))
(cond
( (eq (aand w2 (anot w4)) 1) (e) )
( (eq (aand w4 (anot w6)) 1) (s) )
( (eq (aand w6 (anot w8)) 1) (w) )
( (eq (aand w8 (anot w2)) 1) (n) )
( w1 (n) )
( w3 (e) )
( w5 (s) )
( w7 (w) )
( t (n) )
)
(setf o_w2 w2)
(setf o_w4 w4)
(setf o_w6 w6)
(setf o_w8 w8)
(setf o_state state)
))
; USER INPUT
(setf grid-size 9)
(setf iterations 25)
(setf grid '((1 1 1 1 1 1 1 1 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 1 1 1 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 0 0 0 0 0 0 0 1)
(1 1 1 1 1 1 1 1 1)
))
(setf x '5 y '6)
OUTPUT
> (load "part-e3.lsp")
; loading part-e3.lsp
T
> (move)
(5 6)
(6 6)
(6 5)
(6 4)
(6 3)
(6 2)
(5 2)
(4 2)
(3 2)
(2 2)
(2 3)
(2 4)
(2 5)
(2 6)
(3 6)
(4 6)
(5 6)
(6 6)
(6 5)
(6 4)
(6 3)
(6 2)
(5 2)
(4 2)
(3 2)
(2 2)
(2 3)
T
I made an attempt to program the A* search for the 8 puzzle and 15 puzzle in LISP. Unfortunately, as I ran out of time towards the end of the semester, I was unable to complete the program. I have included my algorithm and what I have managed to complete.
To write a general LISP program to implement A* search, where both the heuristic function h(n) and fixed cost function g(n) are specified by the user.
a) To test the program with the 8 puzzles used in class
b) Specify a heuristic function and use it to solve a given 8 puzzle
c) Specify a heuristic function and use it to solve a given 15 puzzle
The representation of the puzzle would be as shown in the example:
((2 8 3) (0 1 4) (5 6 7)) would be the start node’s puzzle representation
I would use what I call a “representation list”, which would contain the required fields needed to store all the required data associated with the puzzle as follows:
(<puzzle> <id> <pointer> <depth> <f(n)>)
where
Tag |
Used for |
puzzle |
The 2-dimensional list containing the puzzle |
id |
A unique ID to identify the node (to be used to backtrack from goal node) |
pointer |
Points to the ID of the parent node |
depth |
Indicates depth of the node in the tree. Would be used to calculate g(n) |
f(n) |
The cost function f(n) of the node |
E.g.: ( ((2 8 3) (0 1 4) (5 6 7)) 1 0 0 8 ) would be the start node’s representation.
Thus, CLOSED and OPEN would be lists consisting of the representation lists of the puzzles.
E.g.: CLOSED: ( ( ((2 8 3) (0 1 4) (5
6 7)) 1 0 0 8 )
( ((0 8 3) (2 1 4) (5 6 7)) 2 1 1 9 ) )
1. Initialize start and goal nodes, and construct the start node’s representation list.
2. Set OPEN = list of representation list of start node, CLOSED = empty list
3. If OPEN = nil, exit with failure
4. Move the first list in OPEN to CLOSED
5. If first list in CLOSED is the goal node, then print the path to the goal node.
6. Generate successors of the first list in CLOSED, calculate their id, pointer, depth and f(n), and add them to OPEN.
7. Sort OPEN according to increasing f(n) values.
8. Go to step (3).
(setf start '((2 8 3) (0 1 4) (5 6 7)))
(setf goal '((1 2 3) (4 5 6) (7 8 0)))
(setf OPEN (list (append (list start) (1 0 0 0))))
(setf CLOSED nil)
(defun a-star () (prog()
LOOP
; If OPEN = nil, exit with failure
(if (null OPEN) (return nil))
; Move first of OPEN to CLOSED
(setf CLOSED (first OPEN))
(setf OPEN (rest OPEN))
; If the first list in CLOSED is the goal…
; …print the path to the goal
(if (eq (first (first CLOSED)) goal)
((print_success) (return T)))
; Generate successors
(generate_successors)
; Sort the list OPEN
(sort_open)
(goto LOOP)
))
1. Set ‘ptr’ to pointer of goal node
2. Set a temporary list to puzzle configuration of the goal node
3. Search CLOSED for parent of the node.
4. If the parent is the start node:
a. Reverse the temporary list.
b. Print it out
else,
a. Append the parent to the temporary list.
b. Set ‘ptr’ to the pointer of this node
c. Goto step (3).
(defun print_success () (prog (lis)
; Set the pointer to parent of goal node
(setf ptr (third (first CLOSED)))
; Add the puzzle arrangement of the goal node to lis
(setf lis (first (first CLOSED)))
(setf l (length CLOSED))
L1
; If start node is found, reverse lis, and print the nodes
(if (eq ptr 0) (prog (true_lis)
(setf true_lis (reverse lis))
(dolist element true_lis i
(print element))
(return T)
))
; If the parent is found, add it to lis, and continue search
(if (eq (second(nth CLOSED i)) ptr) (
(setf lis (append lis (first (nth CLOSED i))))
(setf ptr (third (nth CLOSED i)))
(setf i 1)
(goto L1)
)
( (setf i (1+ i))
(goto L1)
)
))
1. Get the puzzle arrangement, ID, and depth of the node
2. Locate the blank in the arrangement, and move it left, right, up and down (if these are possible)
3. Calculate the ID, pointer, depth and f(n) for these arrangements, and create a list SUCCESSOR containing the representation list of the successors.
4. Check if each element of the SUCCESSOR list is a member of either OPEN or CLOSED. If it not, then add it to OPEN.