;;; -*- Package: USER; Mode: LISP; Base: 10; Syntax: Common-Lisp -*-

(in-package "USER")

;;;; +=========================================================+
;;;; | Source code for the farmer, wolf, goat, cabbage problem |
;;;; |     from Luger's "Artificial Intelligence, 4th Ed."     |
;;;; |  In order to execute, run the function CROSS-THE-RIVER  |
;;;; +=========================================================+

;;; +=============================================+
;;; | State definitions and associated predicates |
;;; +=============================================+

(defun make-state (f w g c) 
  (list f w g c))

(defun farmer-side (state)
  (nth 0 state))

(defun wolf-side (state)
  (nth 1 state))

(defun goat-side (state)
  (nth 2 state))

(defun cabbage-side (state)
  (nth 3 state))

;;; +======================+
;;; | Operator definitions |
;;; +======================+

(defun farmer-takes-self (state)
  (safe (make-state (opposite (farmer-side state))
		    (wolf-side state)
		    (goat-side state)
		    (cabbage-side state))))

(defun farmer-takes-wolf (state)
  (cond ((equal (farmer-side state) (wolf-side state))
	 (safe (make-state (opposite (farmer-side state))
			   (opposite (wolf-side state))
			   (goat-side state)
			   (cabbage-side state))))
	(t nil)))

(defun farmer-takes-goat (state)
  (cond ((equal (farmer-side state) (goat-side state))
	 (safe (make-state (opposite (farmer-side state))
			   (wolf-side state)
			   (opposite (goat-side state))
			   (cabbage-side state))))
	(t nil)))

(defun farmer-takes-cabbage (state)
  (cond ((equal (farmer-side state) (cabbage-side state))
	 (safe (make-state (opposite (farmer-side state))
			   (wolf-side state)
			   (goat-side state)
			   (opposite (cabbage-side state)))))
	(t nil)))

;;; +===================+
;;; | Utility functions |
;;; +===================+

(defun opposite (side)
  (cond ((equal side 'e) 'w)
	((equal side 'w) 'e)))

(defun safe (state)
  (cond ((and (equal (goat-side state) (wolf-side state))
	      (not (equal (farmer-side state) (wolf-side state))))
	 nil)
	((and (equal (goat-side state) (cabbage-side state))
	      (not (equal (farmer-side state) (goat-side state))))
	 nil)
	(t state)))

;;; +========+
;;; | Search |
;;; +========+


;;; Does not check states that have been visited outside the current
;;; path 
(defun path (state goal &optional (been-list nil))
  (cond ((null state) nil)
	((equal state goal) (reverse (cons state been-list)))
	((not (member state been-list :test #'equal))
	 (or (path (farmer-takes-self state) goal (cons state been-list))
	     (path (farmer-takes-wolf state) goal (cons state been-list))
	     (path (farmer-takes-goat state) goal (cons state been-list))
	     (path (farmer-takes-cabbage state) goal (cons state been-list)))
	 )))

;;; +==================+
;;; | Canned Execution |
;;; +==================+

(defun cross-the-river ()
  (let ((start (make-state 'e 'e 'e 'e))
	(goal (make-state 'w 'w 'w 'w)))
    (path start goal)))
