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:
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.
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).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.
no.
?- solve(['+'], [24], 24, Tree).
Tree = 24
?- solve(['+', '*', '-'], [1, 2, 3, 4], 24, Tree).
Tree = [*,1,[*,2,[*,3,4]]]
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.
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:
[ [1, 2], [3, 4], [] ]represents disk 1 on top of disk 2 on peg 1, disk 3 on top of disk 4 on peg 2, and nothing on peg 3.
[ [1, 2, 3, 4], [], [] ]
[ [], [], [1, 2, 3, 4] ]
| ?- valid([ [1, 2, 3], [], [] ], 12, [ [2, 3], [1], [] ]).This is valid because we went from the first configuration to the second configuration via move "12". Here's another example:
yes
| ?- valid([ [1, 2], [], [3] ], 12, [ [2], [], [1, 3] ]).In this case, it's possible to move from the first configuration to the second configuration, but not by move "12". Here's yet another example:
no
| ?- valid([ [1 , 2], [], [3] ], 31, [ [3, 1, 2], [], [] ]).Although we did move a disk from peg 3 to peg 1 here, this move was invalid because disk 3 cannot be placed on top of disk 1.
no
| ?- hanoi([ [1], [2], [3] ], [23, 13]).The answer here is "yes" because move "23" followed by "13" leaves us in the final configuration. Once this function is written, you can do the following:
yes
| ?- hanoi( [ [1, 2, 3], [], [] ], Solution).Your Prolog program may find a different solution. The solution found depends on the order in which the rules were defined. As long as your Prolog program finds a correct solution, that's fine! Also, test out some small examples (1 or 2 disks) to make sure Prolog finds a finite number of solutions, but for more than 2 disks there will probably be too many solutions returned to practically look at them all.
Solution = [12,13,21,13,12,31,12,31,21,23,12,13,21,13]