;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Function tree-search (defun tree-search (goalp queue successors combiner) "Uninformed search of a tree for a goal. (tree-search goalp queue successors combiner) goalp function predicate returns t or nil given a state queue initial queue of paths, such as (list (list initial-state)) successors function that returns successors from given state; input is reverse path, so (first path) is current state; result is list of new paths, each one extended one state combiner given list of old paths and new paths returns list of old and new paths combined" (cond ((endp queue) nil) (t (let ((firstpath (first queue))) (if (funcall goalp (first firstpath)) (reverse firstpath) ;;else (tree-search goalp (funcall combiner (rest queue) (funcall successors firstpath)) successors combiner)))))) ;;; This way defines three functions, goalp, successors, and combiner that ;;; you can call individually to test and that you can do trace on. (defun pathproblem1 (start goal map) (defun goalp (s) (eql s goal)) (defun successors (path) (mapcar #'(lambda (n) (cons n path)) (cdr (assoc (first path) map)))) (defun combiner (old new) (append old new)) (tree-search #'goalp (list (list start)) #'successors #'combiner)) ;;; This way defines the three functions local to the pathproblem function. ;;; Advantage is it doesn't redefine other functions at the top level of the ;;; same name. ;;; Disadvantage is you can't call them separately at the top level to test ;;; them, nor can you trace them. (defun pathproblem2 (start goal map) (labels ((goalp (s) (eql s goal)) (successors (path) (mapcar #'(lambda (n) (cons n path)) (cdr (assoc (first path) map)))) (combiner (old new) (append old new))) (tree-search #'goalp (list (list start)) #'successors #'combiner))) ;;; This way defines the three functions anonymously using lambda functions (defun pathproblem3 (start goal map) (tree-search ;; goalp #'(lambda (s) (eql s goal)) ;; initial queue (list (list start)) ;; successors #'(lambda (path) (mapcar #'(lambda (n) (cons n path)) (cdr (assoc (first path) map)))) ;; combiner #'(lambda (old new) (append new old)))) ;;; Example map search (setf bigmap '((a b c d z) (b e f) (c g h) (d i j) (e k z))) (format t "~%Example map search.~&Map is ~s~&Path from A to Z is ~s." bigmap (pathproblem3 'a 'z bigmap)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Movement of robot in a grid. (defun robot-xy (start goal world-size) (tree-search ;;goalp #'(lambda (s) (equal s goal)) ;; initial queue (list (list start)) ;; successors #'(lambda (path) (let* ((s (first path)) (x (first s)) (y (second s)) (succ (list (list x (+ y 1)) (list x (- y 1)) (list (+ 1 x) y) (list (- x 1) y))) (legal-succ (remove-if #'(lambda (s) (let ((x (first s)) (y (second s))) (or (< x 1) (> x world-size) (< y 1) (> y world-size)))) succ))) (mapcar #'(lambda (newone) (cons newone path)) legal-succ))) ;; combiner #'(lambda (old new) (append old new)))) ;;; Example robot searches (format t "~%~%Example robot searches. World is 5x5.") (format t "~& Path from (1 1) to (4 4) is ~s." (robot-xy '(1 1) '(4 4) 5)) (format t "~& Path from (3 2) to (1 4) is ~s." (robot-xy '(3 2) '(1 4) 5)) (format t "~%~%") #| Explanations and answers to questions that require a typed response can be entered this way as a multi-line comment. 7. answer to 7 8. answer to 8 9. answer to 9 |#