Bestfirst Search
Bestfirst Search
; (setq *moves* ; '(farmer-takes-self farmer-takes-wolf ; farmer-takes-goat farmer-takes-cabbage)) ;;; Also, the algorithm requires that a simple heuristic be used to evaluate ;;; states. For the farmer, wolf, goat and cabbage rules, a simple heuristic ;;; counts the number of players not in their goal positions: ; (defun heuristic (state) ; (declare (special *goal*)) ; (heuristic-eval state *goal*)) ; (defun heuristic-eval (state goal) ; (cond ((null state) 0) ; ((equal (car state) (car goal)) ; (heuristic-eval (cdr state) (cdr goal))) ; (t (1+ (heuristic-eval (cdr state) (cdr goal)))))) ; ;;; Once these have been defined, evaluate: ;;; ;;; (run-best '(e e e e) '(w w w w))
;;; insert-by-weight will add new child states to an ordered list of ;;; states-to-try. (defun insert-by-weight (children sorted-list) (cond ((null children) sorted-list) (t (insert (car children) (insert-by-weight (cdr children) sorted-list))))) (defun insert (item sorted-list) (cond ((null sorted-list) (list item)) ((< (get-weight item) (get-weight (car sorted-list))) (cons item sorted-list)) (t (cons (car sorted-list) (insert item (cdr sorted-list)))))) ;;; run-best is a simple top-level "calling" function to run bestfirst-search (defun run-best (start goal) (declare (special *goal*) (special *open*) (special *closed*)) (setq *goal* goal) (setq *open* (list (build-record start nil 0 (heuristic start))))
(setq *closed* nil) (best-first)) ;;; These functions handle the creation and access of (state parent) ;;; pairs. (defun build-record (state parent depth weight) (list state parent depth weight)) (defun get-state (state-tuple) (nth 0 state-tuple)) (defun get-parent (state-tuple) (nth 1 state-tuple)) (defun get-depth (state-tuple) (nth 2 state-tuple)) (defun get-weight (state-tuple) (nth 3 state-tuple)) (defun retrieve-by-state (state list) (cond ((null list) nil) ((equal state (get-state (car list))) (car list)) (t (retrieve-by-state state (cdr list))))) ;; best-first defines the actual best-first search algorithm ;;; it uses "global" open and closed lists. (defun best-first () (declare (special *goal*) (special *open*) (special *closed*) (special *moves*)) (print "open =") (print *open*) (print "closed =") (print *closed*) (cond ((null *open*) nil) (t (let ((state (car *open*))) (setq *closed* (cons state *closed*)) (cond ((equal (get-state state) *goal*) (reverse (buildsolution *goal*))) (t (setq *open* (insert-by-weight (generate-descendants (get-state state) (1+ (getdepth state)) *moves*) (cdr *open*))) (best-first))))))) ;;; generate-descendants produces all the descendants of a state (defun generate-descendants (state depth moves) (declare (special *closed*) (special *open*)) (cond ((null moves) nil) (t (let ((child (funcall (car moves) state)) (rest (generate-descendants state depth (cdr moves))))
(cond ((null child) rest) ((retrieve-by-state child rest) rest) ((retrieve-by-state child *open*) rest) ((retrieve-by-state child *closed*) rest) (t (cons (build-record child state depth (+ depth (heuristic child))) rest))))))) (defun build-solution (state) (declare (special *closed*)) (cond ((null state) nil) (t (cons state (build-solution (get-parent (retrieve-by-state state *closed*)))))))
OUTPUT:
;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; Open: ((S)) Closed: NIL Open: ((A S) (D S)) Closed: (S) Open: ((B A S) (D A S) (D S)) Closed: (A S) Open: ((C B A S) (E B A S) (D A S) (D S)) Closed: (B A S) Open: ((E B A S) (D A S) (D S)) Closed: (C B A S) Open: ((D E B A S) (F E B A S) (D A S) (D S)) Closed: (E C B A S) Open: ((F E B A S) (D A S) (D S)) Closed: (D E C B A S) Open: ((G F E B A S) (D A S) (D S)) Closed: (F D E C B A S) (G F E B A S)