Water Jug Solution
Lisp code to for goalp and new-states
;;; Solve the Water Jug problem
(in-package "USER")
(defvar *start* '(0 0))
(defun first-jug (state) (car state))
(defun second-jug (state) (cadr state))
(defun mk-state (f s) (list f s))
(defun goalp (state)
(eq (first-jug state) 2))
(defun new-states (state)
(remove-null
(list
(fill-first state)
(fill-second state)
(pour-first-second state)
(pour-second-first state)
(empty-first state)
(empty-second state))))
(defun remove-null (x)
(cond
((null x) nil)
((null (car x)) (remove-null (cdr x)))
((cons (car x) (remove-null (cdr x))))))
(defun fill-first (state)
(cond
((< (first-jug state) 4) (mk-state 4 (second-jug state))))))
(defun fill-second (state)
(cond
((< (second-jug state) 3) (mk-state (first-jug state) 3))))
(defun pour-first-second (state)
(let ( (f (first-jug state))
(s (second-jug state)))
(cond
((zerop f) nil) ; Cant pour nothing
((= s 3) nil) ; Second full
((<= (+ f s) 3) ; Empty first into second
(mk-state 0 (+ f s)))
(t ; Fill second from first
(mk-state (- (+ f s) 3) 3)))))
(defun pour-second-first (state)
(let ( (f (first-jug state))
(s (second-jug state)))
(cond
((zerop s) nil) ; Cant pour nothing
((= f 4) nil) ; First full
((<= (+ f s) 4) ; Empty second into first
(mk-state (+ f s) 0))
(t ; Fill first from second
(mk-state 4 (- (+ f s) 4))))))
(defun empty-first (state)
(cond
((> (first-jug state) 0) (mk-state 0 (second-jug state)))))
(defun empty-second (state)
(cond
((> (second-jug state) 0) (mk-state (first-jug state) 0))))
Code for Depth First Search
;;; Depth first search with state limit
(in-package "USER")
(defun dfs (state depth limit)
(setf *nodes* 0)
(setf *expanded* 0)
(setf *branches* 0)
(setf *limit* limit)
(setf *result* (dfs1 state depth))
(print (list *nodes* *expanded* *branches*))
*result*
)
;;; dfs1 expands a node and calls dfs2 to recurse on it
(defun dfs1 (state depth)
(setf *nodes* (+ 1 *nodes*))
(cond
((goalp state) (list state))
((zerop depth) nil)
((> *nodes* *limit*) nil)
((let ((children (new-states state)))
(setf *expanded* (+ 1 *expanded*))
(setf *branches* (+ (length children) *branches*))
(let ((result (dfs2 children (- depth 1))))
(and result (cons state result)))))))
;;; dfs2 recurses on each sibling from a single node, calling dfs1
(defun dfs2 (states depth)
(cond
((null states) nil)
((dfs1 (car states) depth))
((dfs2 (cdr states) depth))))
Code for Breadth First Search
;;; Solve by breadth-first search
(in-package "USER")
(defun bfs (state limit)
(setf *nodes* 0)
(setf *expanded* 0)
(setf *branches* 0)
(setf *limit* limit)
(setf *result* (bfs1 (list (list state))))
(print (list *nodes* *expanded* *branches*))
(reverse *result*))
(defun bfs1 (queue)
(setf *nodes* (+ 1 *nodes*))
(cond
((null queue) nil)
((goalp (caar queue)) (car queue))
((> *nodes* *limit*) nil)
((let ((children (new-states (caar queue))))
(setf *expanded* (+ 1 *expanded*))
(setf *branches* (+ (length children) *branches*))
(bfs1
(append
(cdr queue)
(mapcar
#'(lambda (state)
(cons state (car queue)))
children)))))))
Sample Run
;;; Sun Common Lisp, Development Environment 4.0.0 , 6 July 1990
;;; Sun-4 Version for SunOS 4.0.x and sunOS 4.1
> (compile-file "wj.lisp")
#P"/usr2/mlm/wj.sbin"
> (compile-file "bfs")
#P"/usr2/mlm/bfs.sbin"
> (compile-file "dfs")
#P"/usr2/mlm/dfs.sbin"
> (load "wj")
> (load "dfs")
> (load "bfs")
> *start*
(0 0)
> (new-states *start*)
((4 0) (0 3))
> (dfs *start* 7 100000)
(584 206 591) ; Branching factor 2.86 (591/206)
((0 0) (4 0) (1 3) (1 0) (0 1) (4 1) (2 3))
> (bfs *start* 100000)
(341 340 981) ; Branching factor 2.88 (981/340)
((0 0) (4 0) (1 3) (1 0) (0 1) (4 1) (2 3))
Last updated 10-Oct-94 by fuzzy@cmu.edu