Computer Science 60
Principles of Computer Science
Fall 2006


Assignment 9 "Lite": Some Fun (and Games) with Prolog [75 points]!
Due Wednesday, November 8 by 11:59 PM

Note that the second midterm will be handed out on Wednesday, Nov 8 at 8am and due at 10am on Friday, Nov 10. I STRONGLY suggest that you finish the homework before taking the midterm.

This assignment has 4 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), and member.

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: Lights Out! (15 points)

Please submit your solution to this part in a file called part2.pl.

The game of Lights Out is a puzzle game in which you are given an array of squares (2D in the real game, 1D in our case), each of which is either "on" (1) or "off" (0). The goal of the game is to set all the squares to "off". You can make a move by choosing any particular square to toggle, however toggling a square also toggles its immediate neighbors.

For example, the following example illustrates a winning set of moves:

Start with: [1, 0, 1, 0, 0, 0]
Choose square 2: [1, 1, 0, 1, 0, 0]
Choose square 0: [0, 0, 0, 1, 0, 0]
Choose square 5: [0, 0, 0, 1, 1, 1]
Choose square 4: [0, 0, 0, 0, 0, 0]
Note that at the edges (0 and 5) only 2 squares change.

You have probably written a lights out implementation in another programming class (like CS5). However, now we are going to write a "program" in Prolog that will find winning lists of moves for us!

Your task is to write a predicate lightsOut(Config, Moves) that returns true if applying the moves in the list Moves starting with the configuration Config will yield a winning configuration. You do not have to handle lists of moves that contain "loops", or moves that toggle the lights back to a state you have seen before (i.e., it's OK if prolog says No to such lists of moves). However, your predicate should support the situation where Moves is a variable, hence "tricking" prolog into solving the game for us!  (You can assume Config will always be bound).

For example:

| ?- lightsOut([1, 1, 1, 0, 0, 0], X).

X = [0,1,0] ;

X = [0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,5] ;

X = [0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,4] ;

X = [0,1,0,2,0,1,0,3,0,1,0,2,3] ;

X = [0,1,0,2,2] ;

X = [1] ;

no

Note that there are many possible solutions.  It is not necessary that prolog find all of them or even that prolog find the shortest solution, simply that it finds a finite number of solutions.   Note also that some initial configurations of this game do not have a solution, so prolog may occasionally say no.

A good approach to this problem (and the next one) is to write rules that define the "rules of the game".  What does it mean to make a legal move?  How does a move affect the state of the game?  As in the next problem (and in the fox, lettuce, hare problem from class) you will probably find it useful to write a valid rule that returns true when a particular move is legal.  You can assume for this problem that the board will always be 6 cells long.

Part 3: Towers of Hanoi (25 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 before embarking on this program. I also recommend that you solve problem 2 (lights out!) before solving this problem.  The big ideas in all three 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:



Last modified November 2006 by Christine Alvarado