; CS 470 HW 1 Prog 1 "The Farmer and the Animals" COMPLETE VERSION FROM CLASS ; ; ; A famous puzzle, and an historical example AI problem for solution by an ; exhaustive state space search. The creatures: farmer, wolf, goat, cabbage. ; The problem: move everyone from the east side to the west side of the ; river using a boat which can carry only the farmer and one other creature ; at a time (or just the farmer, but the boat cannot cross by itself!). ; The constraints: if left alone (i.e., no farmer) on one side together ; at the same time, the wolf will eat the goat, and/or the goat will eat ; the cabbage. Find a sequence of crossings (moves) to safely get everyone ; across without anyone or anything getting eaten. Try to solve this ; first on your own! Next our job is to automate the planning (let's call ; a sequence of moves a "plan"). ; ; Formalization: define a state as a list such as "(e w w e)", where ; the first element is the side on which stands the farmer, the second ; element describes the wolf's location, the third the goat's, and the ; fourth the cabbage's: (farmer's side, wolf's side, goat's side, cabbage's ; side). Thus the example given, "(e w w e)" would be an "unsafe" state, ; since the wolf would eat the goat. "e" stands for east, and "w" for west. ; The state "(e e e e)" is the initial state. ; We can define one operator, "move", that takes two arguments: creature ; (to move) and the current state: "(move creature state)". Then a ; plan is a sequence of moves: (move wolf (move goat (e e e e)), since ; move returns a (modified) state. ; ; Ultimately, what we want is a function (solve initial goal) which ; returns a plan, given an initial and a goal state, that changes the ; initial state into the goal state through a sequence of LEGAL and ; SAFE moves. Legal moves are those which can actually take place ; (i.e., the farmer, and consequently the boat, are on the same side ; as the creature to be moved), while a safe move is one which results ; in a safe state (i.e., the wolf and goat are not left on the same side ; without the farmer, nor are the goat and cabbage). Thus ; "(solve '(e e e e) '(w e w e))" should return "(move 'goat '(e e e e))". ; And "(solve '(e e e e) '(w w w w))" is the full problem. ; ; Below I include scheme code for some of the functions. You can rewrite ; these in Lisp, modify them, or not use them at all, but I suggest you ; do use them, and concentrate on the "missing" functions. What I ; include below are the more tedious and detailed functions, such as ; "move", and the actual breadth-first search (managing the queue of search ; states, etc.). I also include the simple function "side" for you to ; use (so you don't have deal with "caddr" and "cadddr", etc.). ; Return the side ('e' or 'w') that the given creature is on in the ; current state (define (side creature state) (cond ((equal? creature 'farmer) (car state)) ((equal? creature 'wolf) (cadr state)) ((equal? creature 'goat) (caddr state)) (#t (cadddr state)) ) ) (define (changeside side) (if (equal? side 'e) 'w 'e) ) ; Return the new state after moving the given creature from its ; current side in the given state to the opposite side (i.e., "e" to "w" ; or "w" to "e"). Do not bother to check if this is a legal or safe ; move. Assume that is done elsewhere! (define (move creature state) (list ; Create a list of the four sides: (changeside (side 'farmer state)) ; The farmer's side always changes, (if (equal? creature 'wolf) ; Change the wolf's side if it is the (changeside (side 'wolf state)) ; one being moved, otherwise (side 'wolf state)) ; keep the solf's side the same. (if (equal? creature 'goat) ; Same for goat. (changeside (side 'goat state)) (side 'goat state)) (if (equal? creature 'cabbage) ; Same for cabbage. (changeside (side 'cabbage state)) (side 'cabbage state)) ) ) ; The main function to call. Given an initial and a goal state, solve ; returns a plan to change the initial to the goal, if possible. It ; calls search to do a breadth-first search of all possible successor ; states (offspring) of the initial state. (define (solve initial goal) (search (list (list 'quote initial)) goal)) ; Success returns true if the EVALUATED (i.e., executed) plan returns the goal ; state. (define (success? plan goal) (equal? (eval plan) goal)) ; Search is given a queue of plans (i.e., a list of plans) and the goal state. ; Search then checks if the head of the queue (first element) is a successful ; plan. If so, it returns that plan. Otherwise, it generates all legal and ; safe offspring of that plan (offspring are successor states, which are ; moves from the given state). These offspring are themselves plans, one move ; longer than their parent plan. These are then added (appended) to the tail ; of the plan queue (i.e., the end of the list of plans). This implements ; a breadth-first search of the state space tree, with NO checking for duplicates ; (i.e., cycles) or other possible speedups (e.g., heuristics). (define (search plans-q goal) (if (success? (car plans-q) goal) ; If first plan works, return it. Done. (car plans-q) (search (append (cdr plans-q) ; Otherwise, continue search, recursively. (offspring (car plans-q)) ) goal ) ) ) ; Return a list of all successor plans of the given plan, but only those ; successors that involve one additional LEGAL and SAFE move! (define (offspring plan) (append (if (and (legalmove? 'cabbage (eval plan)) ; If moving the cabbage is (safemove? 'cabbage (eval plan)) ; is safe and legal, ) ; then add the augmented (list (list 'move ''cabbage plan)) ; plan to the list to return. '() ) (if (and (legalmove? 'goat (eval plan)) ; Same for moving the goat. (safemove? 'goat (eval plan)) ) (list (list 'move ''goat plan)) '() ) (if (and (legalmove? 'wolf (eval plan)) ; Same for moving the wolf. (safemove? 'wolf (eval plan)) ) (list (list 'move ''wolf plan)) '() ) (if (and (legalmove? 'farmer (eval plan)) ; Same for moving the farmer. (safemove? 'farmer (eval plan)) ; (by himself) ) (list (list 'move ''farmer plan)) '() ) ) ) ; MISSING FUNCTIONS: ; ; (legalmove? creature state) returns true if and only if it is possible to move ; the creature in the current state (i.e., farmer is on same side as creature in state). ; Returns false otherwise. ; ; (safemove? creature state) returns true if and only if moving the creature in the ; current state results in a safe state (wolf and goat not left alone, AND goat and ; cabbage not left alone). ; ; (changeside side) returns the opposite side from the given side. (i.e., "w" <--> "e") ; ; ; Again, you may rewrite any of the given functions above. Ultimately, what you really ; must do is implement a program that supports (solve initial goal) as described ; above. That is, given any initial and any goal state, it will return the (minimum ; length) plan to get from initial to goal (if a finite length plan exists!). If ; no finite plan exists, or if bad input is given (i.e., unsafe initial or goal ; states!) the behavior of your program is not specified here! (i.e., just assume ; a finite, legal, safe, plan exists, and that the input is error-free (safe initial ; and goal states, correct syntax). At least make sure you're program works on simple ; planning tasks (e.g., "(solve '(w w w w) '(w w w w))" or "(solve '(e e e e) '(w e w e))") ; and on the original problem "(solve '(e e e e) '(w w w w))" (or equivalently, ; "(solve '(w w w w) '(e e e e))"). (define (unsafestate? state) (or (and (equal? (side 'wolf state) (side 'goat state)) (not (equal? (side 'farmer state) (side 'wolf state)))) (and (equal? (side 'cabbage state) (side 'goat state)) (not (equal? (side 'farmer state) (side 'goat state)))) ) ) (define (safestate? state) (not (unsafestate? state)) ) (define (safemove? creature state) (safestate? (move creature state)) ) (define (legalmove? creature state) (equal? (side 'farmer state) (side creature state)) )