Computer Science 60
Principles of Computer Science
Fall 2007


Assignment 9: Fun (and Games) with Prolog [100 points]!
Due Monday, November 12 by 11:59 PM

This assignment has 3 parts. Please be sure to name your prolog rules exactly as we've specified in the assignment. This is important since some of your code will be tested by an automatic code tester which will look for precisely these names.

Recall Prolog's built-in rules that may be useful here:

Again, you may also want to define your own helper rules as needed or other predicates that we defined in class, e.g., permutation (that generates permutations).

Finally, remember that it's fine if your prolog rule finds the same solution more than once as long as it doesn't find it an infinite number of times! In other words, your prolog rules should halt, but may find the same solution a finite number of time.

Part 1: The Game of 24! (35 Points)

This problem asks you to use Prolog to provide a solver for a generalized version of the game "Twenty-Four". In the original game, players view a card with four numbers on it and try to make an arithmetic combination of the numbers using the operators +, -, *, / so that the result is 24 (parentheses are allowed but are implicit). Each number must be used exactly once. Each operator can be used any number of times.

In our generalization of the game, the fixed number 24 is replaced with an arbitrary value, the set of operators is specified in a list, and the list of numbers can have any length, not just 4. (By definition, no result can be made if the list is empty.)

Define a 4-ary rule called solve such that

 solve(Operators, Numbers, Result, Tree)
will solve for an arithmetic tree named Tree using operators Operators among the integers in Numbers to give the final value Result. You may assume that when we use the solve rule the operators, numbers, and result will always be specified but that the fourth argument, the tree itself, may be left as a variable. For example,
 | ?- solve(['+'], [1, 2, 3], 6, ['+', 1, ['+', 2, 3]]).
yes

| ?- solve(['+', '*', '-'], [2, 3, 4, 5], 24, Tree).

Tree = [*,[+,[-,3,2],5],4]

This means that we have found a solution Tree using operators +, *, and - on that will combine with set of numbers [2, 3, 4, 5] to yield 24. You may assume that the set of operators will always be a subset of ['+', '*', '-', '/'] and that '/' denotes integer division. In prolog, '/' is performed using // (which is why 1-line comments in prolog are prefaced by % and not //).

We provide an eval predicate that will be quite useful in solving this problem. Here it is:

eval(R, R) :- number(R).
eval(['+', A, B], R) :- eval( A, R1 ), eval( B, R2 ), R is R1 + R2.
eval(['-', A, B], R) :- eval( A, R1 ), eval( B, R2 ), R is R1 - R2.
eval(['*', A, B], R) :- eval( A, R1 ), eval( B, R2 ), R is R1 * R2.
eval(['/', A, B], R) :- eval( A, R1 ), eval( B, R2 ), R is R1 // R2.

You may also use any of Prolog's built-in rules and any helper rules that you like (including those that we wrote in class).

Here are some other examples of solve in action:

 ?- solve(['+'], [1, 1, 1, 1], 24, Tree).

no.


?- solve(['+'], [24], 24, Tree).

Tree = 24


?- solve(['+', '*', '-'], [1, 2, 3, 4], 24, Tree).

Tree = [*,1,[*,2,[*,3,4]]]
Notice that a plain integer (e.g. 24) is the simplest possible solution tree (not [24]), and there are many more answers to the third example above.

This problem will require that you to think very carefully about the order in which rules are specified in your prolog rules. Remember from class that order matters!

A very good approach to this problem is to write a helper rule called tree that takes as input a list Operations of valid operations to be used, a list Numbers of numbers to be used and a Tree which is a tree in which the leaves of the tree are the numbers, where each number is used exactly once, the internal nodes in the tree are selected from Operations (with operations permitted to be used more than once). In fact, you might find it convenient to stipulate that the numbers at the leaves must occur exactly in the order (from left-to-right) that they are given in Numbers. (You can deal with permuting these numbers someplace else.) For example:

| ?- tree(['+', '*'], [1, 2, 3, 4], ['*', ['+', 1, 2], ['*', 3, 4]]).
yes

| ?- tree(['+', '*'], [1, 2, 3], X).

X = [+,1,[+,2,3]] ;
X = [+,1,[*,2,3]] ;
X = [+,[+,1,2],3] ;
X = [+,[*,1,2],3] ;
X = [*,1,[+,2,3]] ;
X = [*,1,[*,2,3]] ;
X = [*,[+,1,2],3] ;
X = [*,[*,1,2],3] ;
no

Notice that in the first case we gave tree all three lists and it verified that the third list (a tree) could be constructed from the operations in the first list and the numbers in the second list. Then, in the second case, we "tricked" prolog into generating all possible trees with a given set of operations and numbers. Once you can do this, you're nearly done!

Please submit this part of the assignment in a file called part1.pl.

Part 2: SudoGraph (35 points)

Please submit your solution to this part in a file called part2.pl.   You should download the file part2.pl from the website because it contains some helpful starter code.

In this problem you will construct a Sudograph solver. Sudograph is a generalization of the popular sudoku puzzles.
 
 A single puzzle specifies
The objective is to find a solution of the puzzle, which is defined to be an assignment of a color to each node, such that no two nodes in any constraint are assigned the same color.

You should write a predicate sudograph( Nodes, Contraints, Colors ) that is true when the nodes are assigned legal colors according to the constraints and the list of available colors.  For example:

sudograph( [A, B, C, D, E, F, G],
                    [[A, B, C], [B, C, D], [C, D, E], [D, E, F], [E, F, G], [G, A, B]],
                  [red, blue, green, yellow] )

Should yield the solution:
A = red,
B = blue,
C = green,
D = red,
E = blue,
F = green,
G = yellow ;

A = red,
B = blue,
C = green,
D = red,
E = blue,
F = yellow,
G = green

[Many more solutions omitted]
Yes.

To make testing this predicate easier, we have provided some helpful test code in the provided file along withone sample test.  You should divise at least 3 more tests (include at least one test that fails) and include them in your solution.  Construct your tests just like the one we provide, but call them:

myTestSudoGraph(1)
myTestSudoGraph(2)
myTestSudoGraph(3)

(like we have called our one test testSudoGraph(1)). You should also provide in a comment what you expect this test to result in.  Note that you do NOT have to test to make sure this predicate generates ALL solutions (one will do).
 

Part 3: Towers of Hanoi (30 Points)

In this part of the assignment, you will write a Prolog program to solve the Towers of Hanoi puzzle. Please submit your solution in a file called part3.pl. You should carefully review the "fox, lettuce, hare" solution that we examined in class (on Thursday) before embarking on this program. The big ideas in these two programs are very similar. Fortunately though, this Hanoi program is considerably shorter than the fox, lettuce, hare problem. (You should expect your program to be about 20 lines of Prolog code, not including comments and spacing between rules.) Your solution should specify valid moves in this puzzle and Prolog should use these rules to infer correct solutions to the puzzle. Here are the details: