Reminder: Don't ever run more than one lisp process. Always make sure you kill your lisp process before you log out (Use "ps" to see processes, and "kill -9" to kill them). You WILL use up your quota on Strauss if you do not make sure that your processes are DEAD!! Don't print large files on the EECIS printers in the middle of the day, and when you do print something, pick it up immediately!
THIS PROGRAM WILL TAKE MOST STUDENTS NON-TRIVIAL AMOUNTS OF TIME. START EARLY!!!!
Consider the problem of manuvering railroad cars in a train yard. Many cars must be assembled into a tain of cars in a given order, but the cars start out dispersed throughout the yard, and can only move in prescribed ways on existing track.
Below is an example of a small train yard with sufficient connectivity to arrange railroad cars into any desired sequence. The different sections of track have been numbered from 1 to 6. The figure also shows the starting position for a small train, where each car is represented by a lowercase letter, and the engine is represented by an asterisk "*". Finally, we show the same cars in the goal position, with the cars lined up in order for a departure to the west.
We can represent train yard connectivity in a Lisp list. The simple nature of train yards used in this assignment allows us to describe the yard as a list of right and left edges connected by vertices (in the real world, such vertices are called "switches" :-) Thus, because the right edge of track 1 connects to the left edges of tracks 2 and 3, we find the sublists (1 2) and (1 3) included on our yard vertex list.
(defparameter *yard-1* '((1 2) (1 3) (3 5) (4 5) (2 6) (5 6)))
The state information can be kept as a list of the cars on each section of the track in their respective orders. The first element is (*), indicating only the engine is on track 1, and the sixth element is (d) because only car d is on track 6. Note that when there's more than one car on a track, they are listed left-to-right.
(defparameter *initial-state-1* '((*) (e) NIL (b c a) NIL (d)))
(defparameter *goal-state-1* '((* a b c d e) NIL NIL NIL NIL NIL))
The following rules describe motion
in the train yard (DIRECTION FROM-TRACK TO-TRACK):
Write a Lisp function possible-moves that generates a list of all moves possible in a given train yard and in a given state. Run your function on at least three different yards and two different states for each yard, including the two large yards and initial states described pictorially in this handout.
Hints: A move might be represented
by a triple (right 4 5) that means "move the car at the right
end of track 4 to the left end of track 5, and a triple like (left 5 3)
for movement in the other direction. One way to find possible moves is to use
the venerable AI technique "generate and test"--- generate all possible
moves and then test to see if they are actually legal. If you write a function
to generate all moves (all-moves state), and a predicate to test if
a move is legal (illegal-move-p move yard state), then the lisp function
remove-if supplies the final filter procedure ("filtering"
is a common programming paradigm taught in CISC-280). In fact, if you do it
this way, then "possible-moves" is only one line long :-)
> (possible-moves *yard-1* *initial-state-1*)
((right 1 2) (right 1 3) (left 2 1))
Write a Lisp function (apply-move move state) that takes two inputs, a move like "(left 5 3)" and a state (as defined above) and produced the NEW STATE that will result after actually doing the input move in the input state. Be certain that you do NOT accidentally modify the input state variable!!! Also, I've never seen a "clean" solution to this, you just have to do it by cases. It's ugly! Sorry!
> (apply-move '(right 1 2) *initial-state-1*)
(NIL (* E) NIL (B C A) NIL (D))
Write a Lisp function (expand state
yard) that takes two inputs, a state and a yard, and returns a list of all states
that can be reached in one move (operator) from the input state. This
is a trivial extension of Problems 1 and 2. TEST YOUR SOLUTION ON SEVERAL
YARDS AND STATES!!!
Write a program that takes a connectivity list (yard), an initial state, and a goal state as inputs, and generates a list of moves that take the cars in the initial state into the goal state.
Use a blind search method. Briefly justify your choice.
Test your program on the following problem, *yard-2*. NOTE: You should of course try the little tiny yards, yard-3 and yard-4, listed at the bottom of this assignment, before trying yard-2. Do NOT try to do yard-1 with blind search!!!
Picture of Yard 2:
How big is the search space [state space]??
Now describe at least one heuristic. Write a new search program to do a heuristic search (A* or IDA*). Run your program again on the same yards. You should expect a speedup of at least 2 or 3 times. You might want to take advantage of symmetry, checking for repeated states, etc. My A* search on yard-2 takes a bit under 30 seconds. You might not be able to solve yard-1 at all unless your heuristic is very good or you are very efficient. (Undergraduates don't have to solve yard-1).
The lisp function (time x) can be used to time how long it takes to compute x, for example (time (my-search *yard-2* *initial-state-2* *goal-state-2*)).
In order to keep track of the number of states expanded in your two algorithms, you could use a global variable *expansions*, incf'd from within the expand lisp fn, and set to 0 at the start of your searches.
These problems are "hard" computationally. Make sure your code works on simple train yards of your own devising first. Also, you'll need to compile your code. Interpreted (evaluated) code will never solve the larger problems. Make sure to DEBUG your code BEFORE compiling it!!!
Here's two simpler problem to test code on before trying a hard problem. Don't EVEN think of trying *yard-1* or *yard-2* unless you can solve these trivial yards!!!
(defparameter *yard-4* '((1 2) (1 3) (1 4)))
(defparameter *init-state-4* '((*) (a) (b c) (d)))
(defparameter *goal-state-4* '((* a b c d) NIL NIL NIL))
(defparameter *yard-5* '((1
2) (1 3) (1 4)))
(defparameter *init-state-5* '((*) (a) (c b) (d))) ;Note c and b out of order
(defparameter *goal-state-5* '((* a b c d) NIL NIL NIL))
Comment you code appropriately. That's part of your grade here.
Provide output traces, even if you can only solve smaller problems than the ones here. YOU MUST TURN IN HARDCOPY FOR GRADING.
Unprotect your file and tell us where the code is, or send an email copy to our TA, so that he can run it. Your code should run on similar inputs other than the 4 shown here!!!