=========================================================================== CSC 324 Tutorials Notes for Week 13 Winter 2009 =========================================================================== ------------------------- Towers of Hanoi in Prolog ------------------------- Recall the Towers of Hanoi puzzle: you have N disks of increasing diameter stacked onto one of three pegs, and your task is to move all of the disks onto another peg, subject to the restrictions that you are allowed to move only one disk at a time (from one peg to another) and no disk may ever be placed onto a disk with smaller diameter. Q: Write a Prolog program that solves this, for any number of disks. A: First step: Many ways to represent this; consider predicate hanoi(+N,+X,+Y,+Z) that succeeds iff there is a sequence of valid moves for N disks from peg X to peg Y using peg Z as intermediary -- with side-effect that it prints each move in the sequence (instead, could include a fourth list argument that gets instantiated, but this way will give some practice with write/1). Final solution: % hanoi(N,X,Y,Z) succeeds by printing a sequence of moves for % N disks from peg X to peg Y, using peg Z as intermediary. % Invoke with query such as: hanoi(7,left,right,middle). hanoi(1,X,Y,_) :- write('Move top disk from '), write(X), write(' to '), write(Y), write('.'), nl. hanoi(N,X,Y,Z) :- N > 1, N1 is N-1, hanoi(N1,X,Z,Y), hanoi(1,X,Y,_), hanoi(N1,Z,Y,X). -------------------- Simple expert system -------------------- Q: Write a simple expert system for capitals of the world. The system should start with a short list of known capitals, then have a main loop that asks the user for the name of a country, reports the capital if it is known, and asks the user to enter the information if it is unknown. A: Start with facts. For example, in file 'knowncapitals.pl': % Need ':-' otherwise this would be interpreted as % an attempt to redefine predicate dynamic/1. :- dynamic(capital/2). % Known capitals. capital(canada,ottawa). capital(usa,washington). capital(france,paris). capital(england,london). Next, add loop to read input from user and process it. find_capitals :- write('Country? '), read(Country), answer(Country). answer(stop) :- write('Thank you for using this system...'), !. answer(Country) :- capital(Country,City), !, % capital is known write('The capital of '), write(Country), write(' is' ), write(City), write('.'), nl, nl, find_capitals. answer(Country) :- write('I don''t know the capital of '), write(Country), write('.'), nl, write('Please tell me.'), nl, write('Capital? '), read(City), write('Thank you.'), nl, nl, assertz(capital(Country,City)), find_capitals. In order to get things started, need one more predicate to read in 'knowncapitals.pl' (don't want to do this after every interaction, which is why it's not part of find_capitals): interact :- reconsult('knowncapitals.pl'), nl, write('Please type names entirely in lower case, '), write('followed by a period.'), nl, write('Type "stop." (without the quotes) to quit.'), nl, nl, find_capitals. System can be run simply by typing query: interact. With additional predicates, we could have the code re-write the file 'knowncapitals.pl' when the user enters "stop.", to include all new facts (so that the program retains new knowledge from one run to the next).