Programming Assignment #1

Due March 8

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!!!!

The Switch Problem

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.

Representing the Problem in Lisp

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))

Rules of Movement

The following rules describe motion in the train yard (DIRECTION FROM-TRACK TO-TRACK):

• If the connectivity list contains a sublist (x y) and either track x or track y contains the engine, then the first car of track y can be removed from track y and placed at the end of track x.  We call this a "LEFT" move; so if (1 2) is on the connectivity list, we can move from state ((*) (e)) to state ((*e) NIL), or from state ((a*b) (cd)) to state ((a*bc) (d)). We will notate this below as "(left y x)" --note the transposition of y and x-- meaning move one car from the front of track y leftward to the end of track x.

• If the connectivity list contains the sublist (x y) and either track x or track y contains the engine, then the last car of track x an be removed from track x and placed at the front of track y. We call this a "RIGHT" move; so if (1 2) is on the connectivity list, then a legal move from ((*) (e)) is to (NIL (*e)), and a legal move from state ((a*b) (cd)) is to ((a*) (bcd)). Note that only one symbol moves each time (the engine must have pushed car b right and then returned to track 1). We will notate this as "(right x y)" below, meaning move one car rightward from track x to track y.

• No other moves are allowed; cars cannot move without using the engine, jump over other cars, or teleport from one track to another.

PROBLEM 1 [10 pts]

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* *goal-state-1*)
((right 1 2) (right 1 3))

> (possible-moves *yard-1* *initial-state-1*)
((right 1 2) (right 1 3) (left 2 1))

PROBLEM 2 [10 pts]

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 '(left 2 1) *initial-state-1*)
((* E) NIL NIL (B C A) NIL (D))

> (apply-move '(right 1 2) *initial-state-1*)
(NIL (* E) NIL (B C A) NIL (D))

PROBLEM 3 [10 pts]

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!!!

>(expand *initial-state-1* *yard-1*)
((NIL (* E) NIL (B C A) NIL (D))
(NIL (E) (*) (B C A) NIL (D))
((* E) NIL NIL (B C A) NIL (D)))

PROBLEM 4 [30 pts]

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:

PROBLEM 5 [10 pts]

How big is the search space [state space]??

PROBLEM 6 [30 pts]

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.

NOTES

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-3* '((1 2) (1 3)))
(defparameter *init-state-3* '((*) (a) (b)))
(defparameter *goal-state-3* '((* a b) NIL NIL))

(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))