home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / BM_STAR.ZIP / STAR.DOC < prev    next >
Encoding:
Text File  |  1992-07-26  |  22.3 KB  |  567 lines

  1.                                                         25jun91/bm
  2.  
  3.  
  4.                               -Contents-
  5.  
  6.  
  7.  
  8.         ... Generation of Test Data
  9.  
  10.         ... Linked List Structures for DFID
  11.  
  12.         ... On TeamWork
  13.  
  14.         ... Comparision of Dfid and A_Star
  15.  
  16.         ... The DFID Test Program
  17.  
  18.         ... Results of DFID Test Program
  19.  
  20.         ... The A* Test Program
  21.  
  22.         ... Statistics
  23.  
  24.         ... Program Listings
  25.  
  26.  
  27.  
  28.  
  29.                       -Generation of Test Data-
  30.  
  31.                         Fifteen Puzzle Problem
  32.  
  33.         This traditional puzzle has 15 sliding blocks labeled
  34.         as 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 and blank. But
  35.         these labels, some with one symbol, some with two, are
  36.         akward for a computer program. Any sensible arrangement of
  37.         unique symbols will do so we choose the following goal:
  38.  
  39.  
  40.                         1 2 3 4
  41.                         5 6 7 8
  42.                         9 A B C
  43.                         D E F -
  44.  
  45.  
  46.         This means the test data can be input and manipulated in
  47.         character string form, say "123-56749ab8dEfc". Note that
  48.         this puzzle really has sixteen elements. Since the "blank"
  49.         changes position, there are 16! puzzle permutations.
  50.  
  51.  
  52.         A compiled C program using the compact memory model which
  53.         has multiple data segments, could only support 9420 puzzles.
  54.         Puzzles created at random are unlikely to fall into such a
  55.         small state space. The puzzles provided in the handouts do
  56.         not have a "hardness" quotient so are not a guide for
  57.         algorithm correctness.
  58.  
  59.         There is a simple way to produce a large number of test
  60.         puzzles for this project.  Do an unconditional Breadth-
  61.         First Search starting with the goal configuration and
  62.         expanding until machine memory is full. This will produce
  63.         thousands of puzzles which can be written in string form
  64.         to a test file.  Append the "Gn" value to the puzzle 
  65.         string as an indication of solvability. Example:
  66.  
  67.               Dfid  1-2356749AB8DEFC  ** Level_5 **
  68.               Astar 13645A-29B87DEFC  ** Level_13 **
  69.  
  70.         If a problem puzzle happens to fit in the above state-
  71.         space mapping, then it's solvability is predictable.
  72.         For example, Dfid solves a level_12 puzzle by searching
  73.         down six levels and up six levels. Level_13 requires
  74.         six down and seven up. Admissable algorithms such as
  75.         A-star should provide a solution path equal to the
  76.         known puzzle depth.
  77.  
  78.         The number of puzzles at each level of the above state-
  79.         space mapping can be easily counted. For example, there
  80.         are 3584 puzzles at level_12 and more than 4000 at thirteen
  81.         when the machine memory becomes full. Yet Dfid generates
  82.         only 1092 puzzles for a level_12 problem. This indicates
  83.         the space economy of bidirectional algorithms and implies
  84.         solvability for problems outside the test domain.
  85.  
  86.         The reader may generate and examine puzzles using the 
  87.         compiled program  provdided as follows:-
  88.  
  89.                 MakePuz
  90.                 List Puzzles.dat
  91.  
  92.         23jun91/bm
  93.  
  94.  
  95.         ---LINKED DATA STRUCTURES FOR DFID---
  96.  
  97.  
  98.  
  99.             ===================    ==================
  100.      Open-> | Num | Ptr | Next --> | Num | Ptr | Next ---/
  101.             ===================    ==================
  102.                      |                     |
  103.                     \|/                   \|/
  104.                   =======               =======
  105.                    Hn                    Hn
  106.                    Gn                    Gn
  107.                    Parent                Parent
  108.                    ptr->"1234.."         ptr->"A13C.."
  109.                   =======               =======
  110.                      ^                    ^
  111.             =========|=========           |
  112.      Hash-> | Num | Ptr | Next -->        |
  113.       ..    ===================           |
  114.       ..                                  |
  115.       ..              ___________________>|
  116.       ..             |                  
  117.       ..    ===================         
  118.      Hash-> | Num | Ptr | Next -->      
  119.             ===================
  120.  
  121.  
  122.         The Dfid open list is a stack stored as a linked list.
  123.         The linked list pointers are separated from the puzzle
  124.         data structures to permit multiple orderings of the
  125.         puzzles.  Puzzles in both the open and closed lists
  126.         are pointed to by collision chains attached to an array
  127.         of pointers. The puzzle hash key is the array index.
  128.  
  129.         Each puzzle link is assigned a unique number as the
  130.         associated puzzle is created. The Parent field of each
  131.         puzzle contains the NodeNum of it's parent. This allows
  132.         tracing of the solution path to establish algorithm
  133.         correctness. Note that the solution path could have been
  134.         established by doublely-linked lists. But I have chosen
  135.         to make the search process more efficient by ignoring
  136.         the cost of reproducing the solution path.
  137.  
  138.         Not shown in the above diagram is the additional structure
  139.         used for the A* algorithm. For A*, the open list must be
  140.         resorted in heuristic order with the best node (lowest Fn)
  141.         available first. Instead of one list, I use a table of
  142.         lists with each list containing nodes having equal heuristic
  143.         value -- the ordering of a particular list does not matter.
  144.         The heuristic function, Fn = Gn + Hn, is the table index.
  145.         In theory, Fn could grow very large but in the limited space
  146.         of a 640k PC, a fixed table size of FN_MAX=199 was found to
  147.         be adequate.  The important point.. no sorting required.
  148.  
  149.         The bidirectional DFID discards most of the forward
  150.         state space.  Therefore, a software switch set by menu
  151.         option "3..Save Result in file", saves all the forward
  152.         nodes in a hash table so the solution path can be
  153.         displayed as well as detected.
  154. //
  155.  
  156.                 COMPARISION OF DFID AND A_STAR
  157.  
  158.  
  159.         Except for very simple problems, Dfid is a loser when
  160.         compared to A*.  A* solves more puzzles, such as puzzle 2
  161.         in appendix I of the class handout, produces fewer node
  162.         expansions, and runs to completion in less time. On a
  163.         slow machine, Dfid fills memory in ten minutes, while A*
  164.         stops after six minutes.
  165.  
  166.  
  167.         Dfid loses time by having to rebuild the state space for
  168.         each iteration. Also, because Depth First Search uses a
  169.         stack, promising paths are often buried by poor ones. On
  170.         the other hand, A* always picks the best candidate from
  171.         the open list... using the Manhattan heuristic in my
  172.         example.
  173.  
  174.  
  175.         Dfid could only search to depth twelve in the memory
  176.         available so is unable to solve puzzle 2 of the handout.
  177.         A* solves this puzzle by searching to depth twenty-six.
  178. //
  179. rem  ...DfidTest.bat...
  180. del  BmResult.tmp       
  181. :xx
  182. Dfid  123-56749AB8DEFC Level_3
  183. Dfid  123456789-ABDEFC Level_3
  184. Dfid  12345-689A7CDEBF Level_4
  185. Dfid  12345-7896BCDAEF Level_4
  186. Dfid  1-2356749AB8DEFC Level_5
  187. Dfid  123456789EAC-DBF Level_5
  188. Dfid  16245-379AB8DEFC Level_6
  189. Dfid  -12456379AB8DEFC Level_6
  190. Dfid  16245A389-7CDEBF Level_7
  191. Dfid  12345678ABC-9DEF Level_7
  192. Dfid  12345678ABEC9DF- Level_8
  193. Dfid  12345678ABEC9-DF Level_8
  194. Dfid  1-34927865BCDAEF Level_9
  195. Dfid  123497-865BCDAEF Level_9
  196. Dfid  -27316B459A8DEFC Level_10
  197. Dfid  124756389-FBDAEC Level_11
  198. Dfid  -247153896ABDEFC Level_12
  199. Dfid  13645A-29B87DEFC Level_13
  200. Dfid  12345678DFEBA9C- puz1_appndxI
  201. Dfid  9513D728E64BAFC- puz2_appndxI_no_room
  202. Dfid  62475FB8A13CD9E- puz3_appndxI_no_room
  203. Dfid  1374958BE62CAEF- puz4_appndxI_no_room
  204. Dfid  256491F7ED38ACB- puz5_appndxI_no_room
  205. Dfid  12345678acbdfe9- puz6_appndxI_no_room
  206. Dfid  1423658be9cfad7- puz7_appndxI_no_room
  207. Dfid  7DB1-4E6852CAF93 puz8_appndxI_no_room
  208. Dfid  FBEC7AD98465321- puz9_appndxI_no_room
  209. Dfid  92DA5C74E1-FB638 puz10_appndxI_no_room
  210. goto xx
  211. //
  212.         This is an example of the optional solution file. A
  213.         PD utility "List.com" is provided for convenient viewing
  214.         and called by the Dfid program.
  215.              
  216.         Nodes Expanded:
  217.            Count of child nodes put on the open lists
  218.  
  219.         Moves Considered:
  220.            Count of moves possible as each node is expanded.
  221.            This exceeds nodes expanded because only unique
  222.            puzzles are created.
  223.  
  224.         Puzzles Generated:
  225.            All the puzzle nodes created for a solution attempt.
  226.  
  227. BiDirectional DFID --- by Bob McIsaac
  228. Clock:    0.0 Seconds
  229. Nodes Expanded: S->G      2  Depth 1
  230. Nodes Expanded: G->S      8  Depth 2
  231. Moves Considered:        12
  232. Puzzles generated:       13
  233. Source= 123-56749AB8DEFC  ** Level_3 **
  234.  
  235. ..Final Closed List..
  236. ..Trace path backwards to source.. 123-56749AB8DEFC
  237. ..from common node 2 1234567-9AB8DEFC
  238.  NodeNum:     1  Gn:    0  Hn:   0  Dad     0  123-56749AB8DEFC
  239.  NodeNum:     3  Gn:    1  Hn:  -1  Dad     1  12-356749AB8DEFC
  240.  NodeNum:     2  Gn:    1  Hn:  -1  Dad     1  1234567-9AB8DEFC
  241. ..Trace path backwards to goal.. 123456789ABCDEF-
  242. ..from common node 12 1234567-9AB8DEFC
  243.  NodeNum:    12  Gn:    2  Hn:  -1  Dad     8  1234567-9AB8DEFC
  244.  NodeNum:    13  Gn:    2  Hn:  -1  Dad     8  123456789A-BDEFC
  245.  NodeNum:     8  Gn:    1  Hn:  -1  Dad     7  123456789AB-DEFC
  246.  NodeNum:    10  Gn:    2  Hn:  -1  Dad     9  123456789A-CDEBF
  247.  NodeNum:    11  Gn:    2  Hn:  -1  Dad     9  123456789ABCD-EF
  248.  NodeNum:     9  Gn:    1  Hn:  -1  Dad     7  123456789ABCDE-F
  249.  NodeNum:     7  Gn:    0  Hn:   0  Dad     0  123456789ABCDEF-
  250.  
  251. rem  ....StarTest.Bat...
  252. del  BmResult.tmp       
  253. :xx
  254. Astar  123-56749AB8DEFC Level_3
  255. Astar  123456789-ABDEFC Level_3
  256. Astar  12345-689A7CDEBF Level_4
  257. Astar  12345-7896BCDAEF Level_4
  258. Astar  1-2356749AB8DEFC Level_5
  259. Astar  123456789EAC-DBF Level_5
  260. Astar  16245-379AB8DEFC Level_6
  261. Astar  -12456379AB8DEFC Level_6
  262. Astar  16245A389-7CDEBF Level_7
  263. Astar  12345678ABC-9DEF Level_7
  264. Astar  12345678ABEC9DF- Level_8
  265. Astar  12345678ABEC9-DF Level_8
  266. Astar  1-34927865BCDAEF Level_9
  267. Astar  123497-865BCDAEF Level_9
  268. Astar  -27316B459A8DEFC Level_10
  269. Astar  124756389-FBDAEC Level_11
  270. Astar  -247153896ABDEFC Level_12
  271. Astar  13645A-29B87DEFC Level_13
  272. Astar  12345678DFEBA9C- puz1_appndxI
  273. Astar  9513D728E64BAFC- puz2_appndxI
  274. Astar  62475FB8A13CD9E- puz3_appndxI_no_room
  275. Astar  1374958BE62CAEF- puz4_appndxI_no_room
  276. Astar  256491F7ED38ACB- puz5_appndxI_no_room
  277. Astar  12345678acbdfe9- puz6_appndxI_no_room
  278. Astar  1423658be9cfad7- puz7_appndxI_no_room
  279. Astar  7DB1-4E6852CAF93 puz8_appndxI_no_room
  280. Astar  FBEC7AD98465321- puz9_appndxI_no_room
  281. Astar  92DA5C74E1-FB638 puz10_appndxI_no_room
  282. goto xx
  283.  
  284. ;            STATE-SPACE HEURISTIC SEARCH ALGORITHM
  285.  
  286. ;   This is a short (very short) description of the control algorithm 
  287. ;used by the heuristic search procedure below. This code is fully described
  288. ;in the "Expert's Toolbox" column of the March 1987 AI-Expert magazine.
  289. ;For a more complete description of heuristic search, and a discussion of 
  290. ;strategies for heuristic functions, see Nils J. Nilsson, "Principles of 
  291. ;Artificial Intelligence",  Tioga Publications, 1980, as well as many other 
  292. ;texts on AI.
  293.  
  294. ;Terminology:
  295. ;   Problems which lend themselves to this kind of solution can be thought 
  296. ;of in terms of a series of STATES.  The INITIAL STATE is known, and some 
  297. ;GOAL STATE is desired.  For example, in chess, the initial state is a board 
  298. ;with no pieces moved, and the goal state is a mate situation for your side.
  299.  
  300. ;   One state can be changed in to another state by some predictable
  301. ;change.  We say that it has SUCCESSORS, or those states which result from 
  302. ;only one of the possible changes.  In chess, the initial state has as many 
  303. ;successors as can be produced by making the possible legal moves for white.
  304.  
  305. ;   Ideally, a program would search through all the possible combinations
  306. ;of moves to find a goal state.  Often however (as in our chess example),
  307. ;there are far too many combinations for the program to consider before its 
  308. ;human operators become impatient or run out of money.
  309.  
  310. ;   That's where the HEURISTIC part comes in.  The heuristic function assigns 
  311. ;a value to each state, which represents how hard it was to reach the state and 
  312. ;how hard it is likely to be to get from there to the goal.  It helps the 
  313. ;program decide which sequence of moves is most likely to lead to the goal 
  314. ;state.  The search doesn't consider unfruitful sequences, and so (hopefully, 
  315. ;if the heuristic function is adequate) finds the goal state in a reasonable 
  316. ;amount of time.  There is a body of theory which deals with evaluating the 
  317. ;quality of heuristic functions.  This is discussed in Nilsson's book, and is
  318. ;beyond the scope of this note.
  319.  
  320. ;   One or two more terms are necessary to understand the algorithm.  If n is 
  321. ;a state, the cost f(n) produced by the heuristic function is f(n) = g(n) + h(n),
  322. ;where g(n) is an estimate of the cost of reaching state n, and h(n) is an 
  323. ;estimate of the cost of reaching the goal from state n.  The actual method of 
  324. ;obtaining g and h varies with the problem.  For chess, it would be some very 
  325. ;elaborate function. For a "Tower of Hanoi" problem, it is a straight-
  326. ;forward estimate of numbers of disk moves.
  327.  
  328. ;   It is worth noting that this can be a very inefficient way of solving a 
  329. ;problem.  If you can come with an algorithmic solution to a problem, it is 
  330. ;almost certainly faster than using a state space search.  For example, Xlisp 
  331. ;on an Apple Macintosh can solve a three disk tower of hanoi with a simple 
  332. ;recursive function in a blink of an eye.  The same problem using heuristic 
  333. ;search takes about two minutes.  However, some problems are (as far as we know) 
  334. ;impossible to solve without a search technique like the one given here.
  335.  
  336.  
  337. ;The Algorithm:
  338.  
  339. ; Uses two lists, OPEN and CLOSED.  For notational convenience,
  340. ; let the cost of getting from state n to state m be represented
  341. ; by C(n,m).
  342.  
  343. ;1.  Put the initial state S1 into OPEN.
  344. ;    Let g(S1) = 0, compute h(S1)
  345.  
  346. ;2.  If OPEN is empty, exit with failure.
  347.  
  348. ;3.  Remove from OPEN the state for which g(n) + h(n) is minumum.
  349. ;    Call it N.
  350. ;    Add N to CLOSED.
  351. ;    If N is a goal state, exit with success.
  352.  
  353. ;4.  For all states m which are successors of N:
  354. ;      if m is not on OPEN or CLOSED
  355. ;         add m to OPEN
  356. ;         set g(m) = g(N) + C(n,m) 
  357. ;         compute h(m)
  358. ;      if m is on OPEN
  359. ;         if current value of g(m) > g(N) + C(N,m)
  360. ;            then reset g(m) = g(N) + C(N,m) [We found a cheaper path]
  361. ;      if m is on CLOSED
  362. ;         if current value of g(m) > g(N) + C(N,m)
  363. ;            then reset g(m) = g(N) + C(N,m)
  364. ;                 move m back to OPEN
  365.  
  366. ;5.  Go to step 2
  367.  
  368. ;   This algorithm is implemented below.  The art of this business is 
  369. ;in defining the problem in such a way that one can express the cost of getting 
  370. ;from one state to another, and in calculating h(n) to be as close to the true 
  371. ;cost as possible without going over.
  372.  
  373. ;   I welcome comments and correspondence concerning these
  374. ;programs.
  375.  
  376. ;Marc Rettig
  377. ;Technical Editor, AI-Expert
  378. ;76703,1037
  379.  
  380.  
  381. ;/******************** GENERIC SEARCH ROUTINES **********************/
  382. ; STATE-SPACE SEARCH PROCEDURE
  383. ;   These functions provide a general control structure for
  384. ; solving problems using heuristic search.  In order to apply
  385. ; this method to a particular problem, you must write the
  386. ; functions: initial-state, goal, successors, and print-solution.
  387. ;
  388. ;   In the programs and comments below,
  389. ; g(n) refers to the best estimate of the cost to get to state n,
  390. ; and h(n) is the best estimate of the cost to reach the goal
  391. ; state from state n.  This corresponds with Nilsson's notation.
  392. ;
  393. ; Algorithm given by Dr. Ralph Grishman, New York University.
  394. ; Adapted for Xlisp by Marc Rettig (76703,1037), 9/86.
  395.  
  396. (defun search ()
  397.     (prog (open closed n m successor-list same)
  398.  
  399.           ; Step 1. Put initial state on open.
  400.           (setq open (list (initial-state)))
  401.  
  402.           ; Step 2. If open is empty, exit with failure.
  403.      expand:
  404.           (cond ((null open) (print 'failure) (return nil)))
  405.  
  406.           ; Step 3. Remove state from open with minimum g + h and
  407.           ;    call it n.  (open is sorted by increasing g + h, so
  408.           ;    this is first element.)  Put n on closed.
  409.           ;    Exit with success if n is a goal node.
  410.           (setq n (car open))
  411.           (setq open (cdr open))
  412.           (setq closed (cons n closed))
  413.           (trace 'expanding n)
  414.           (cond ((goal n) (print-solution n) (return t)))
  415.  
  416.           ; For each m in successors(m):
  417.           (setq successor-list (successors n))
  418.      next-successor:
  419.           (cond ((null successor-list) (go expand:)))
  420.           (setq m (car successor-list))
  421.           (setq successor-list (cdr successor-list))
  422.           (trace 'successor m)
  423.           (cond ((setq same (find m open))
  424.                  ; if m is on open, reset g if new value is smaller
  425.                  (cond
  426.                   ((< (get m 'g) (get same 'g))
  427.                    (setq open (add m (remove same open))))))
  428.                 ((setq same (find m closed))
  429.                  ; If m is on closed and new value of g is smaller,
  430.                  ; remove state from closed and add it to open with new g.
  431.                  (cond
  432.                   ((< (get m 'g) (get same 'g))
  433.                    (setq closed (remove same closed))
  434.                    (setq open (add m open)))))
  435.                 (t 
  436.                   ; else add m to open
  437.                   (setq open (add m open))))
  438.           (go next-successor:)))
  439.  
  440. (defun add (state s-list)
  441.     ; Inserts state into s-list so that list remains ordered
  442.     ; by increasing g + h.
  443.     (cond ((null s-list) (list state))
  444.           ((> (+ (get (car s-list) 'g) (get (car s-list) 'h))
  445.               (+ (get state 'g) (get state 'h)))
  446.            (cons state s-list))
  447.           (t (cons (car s-list) (add state (cdr s-list))))))
  448.  
  449. (defun find (state s-list)
  450.     ; returns first entry on s-list whose position is same
  451.     ; as that of state.
  452.     (cond ((null s-list) nil)
  453.           ((equal (get state 'position)
  454.                   (get (car s-list) 'position))
  455.            (car s-list))
  456.           (t (find state (cdr s-list)))))
  457.  
  458. ;  M I S S I O N A R I E S   A N D   C A N N I B A L S
  459. ;
  460. ;  The following routines, when used in conjunction with the state-space
  461. ;  search procedure, solve the missionaries and cannibals problem.  Three
  462. ;  missionaries and 3 cannibals are located on the right bank of a river,
  463. ;  along with a two-man rowboat.  We must find a way of moving all the
  464. ;  missionaries and cannibals to the left bank.  However, if at any time
  465. ;  there are more cannibals than missionaries on a bank, the cannibals will
  466. ;  exhibit a consuming interest in the misssionaries;  this must be avoided.
  467. ;
  468. ;  Each state is represented by an atom with the following properties:
  469. ;       position -- a list of three elements,
  470. ;               the number of missionaries on the right bank
  471. ;               the number of cannibals on the right bank
  472. ;               the position of the boat (left or right)
  473. ;       g       -- the estimated g for that state
  474. ;       h       -- the estimated h (value of function heuristic) 
  475. ;       parent  -- the preceding state on the path from the initial state
  476. ;                   (the preceding state which gives rise to the least g,
  477. ;                        if there are several)
  478.  
  479. (defun initial-state ()
  480.   ;  return the initial state
  481.   (build-state 3 3 'right 0 nil))
  482.  
  483. (defun successors (state)
  484.   ;  returns the successors of state
  485.   ;  note that procedure try uses state and new-g, and modifies suc
  486.   (setq new-g nil) 
  487.   (setq suc nil)
  488.   (prog ()  
  489.       (setq m (car (get state 'position)))
  490.       (setq c (cadr (get state 'position)))
  491.       (setq boat (caddr (get state 'position)))
  492.     ;  extract parameters of current position and put in m, c, and boat
  493.     ;  g of new state = g of old state + 1 (all crossings are unit cost)
  494.     (setq new-g (+ 1 (get state 'g)))
  495.     (cond ((equal boat 'right)
  496.            (try (- m 2) c 'left state)
  497.            (try (- m 1) c 'left state)
  498.            (try (- m 1) (- c 1) 'left state)
  499.            (try m (- c 1) 'left state)
  500.            (try m (- c 2) 'left state))
  501.           (t  ; boat is on left
  502.            (try (+ m 2) c 'right state)
  503.            (try (+ m 1) c 'right state)
  504.            (try (+ m 1) (+ c 1) 'right state)
  505.            (try m (+ c 1) 'right state)
  506.            (try m (+ c 2) 'right state)))
  507.     (return suc)))
  508.  
  509. (defun try (new-m new-c new-boat state)
  510.   ;  if position(new-m,new-c,new-boat) is valid, add new state to suc
  511.   (cond ((valid new-m new-c)
  512.      (setq suc (cons (build-state new-m new-c new-boat new-g state)
  513.              suc)))))
  514.  
  515. (defun valid (miss cann)
  516.   ;  returns true if having 'miss' missionaries and 'cann' cannibals
  517.   ;  on the right bank is a valid state
  518.   (and (>= miss 0)
  519.        (>= cann 0)
  520.        (< miss 4)
  521.        (< cann 4)
  522.        (or (zerop miss) (>= miss cann))
  523.        (or (zerop (- 3 miss)) (>= (- 3 miss) (- 3 cann)))))
  524.  
  525. (defun build-state (miss cann boat g parent)
  526.   ;  creates a new state with parameters as specified by argument list
  527.   (prog (newstate)
  528.     (setq newstate (gensym))
  529.     (putprop newstate (list miss cann boat) 'position)
  530.     (putprop newstate g 'g)
  531.     (putprop newstate (heuristic miss cann boat) 'h)
  532.     (putprop newstate parent 'parent)
  533.     (return newstate)))
  534.  
  535. (defun heuristic (miss cann boat)
  536.   ;  our heuristic (h) function
  537.   (cond ((equal boat 'left)
  538.      (* 2 (+ miss cann)))
  539.     (t  ;  boat is on right
  540.      (* 2 (max 0 (+ miss cann -2))))))
  541.  
  542. (defun goal (state)
  543.   ;  returns true if state is a goal state (no missionaries or cannibals on right)
  544.   (and (zerop (car (get state 'position)))
  545.        (zerop (cadr (get state 'position)))))
  546.  
  547. (defun print-solution (state)
  548.   ;  invoked by search algorithm with goal state,
  549.   ;  prints sequence of states from initial state to goal.
  550.   (cond ((null state)
  551.       (print 'solution:)
  552.       (print 'miss-cannib-bank))
  553.      (t
  554.       (print-solution (get state 'parent))
  555.       (print (get state 'position))
  556.      ))
  557. )
  558.  
  559. (defun trace (comment state)
  560.   ; if trace-switch is true, printout comment and position
  561.   ; associated with state
  562.   (cond 
  563.     (trace-switch
  564.       (print `(,comment state ,state with position ,(get state 'position)
  565.                h(x) =  ,(get state 'h))))))
  566.  
  567.