Reputation: 17
User input name of the city and also how many landmarks wants to visit. My program outputs all possible landmarks. How can I rewrite my code that it will output the number of landmarks that the user wanted (landmarks should be printed in order as they are initialized). If user input for the city Vienna.
and the number of landmarks user wants to visit 3.
the program should return: Hundertwasser House, Vienna State Opera, Schonbrunn Palace.
landmark("Vienna", "Hundertwasser House").
landmark("Vienna", "Vienna State Opera").
landmark("Vienna", "Schonbrunn Palace").
landmark("Vienna", "The Hofburg").
landmark("Vienna", "Belvedere Palace").
suggest_landmark:-
write('Name of the city interested in: '),
nl,
read(X),
format('City: ~w.', [X]), nl, nl,
write('Number of landmarks: '),
nl,
read(Y),
format('Landmarks: ~w.', [Y]), nl, nl,
landmark(X, Z),
format('Landmarks: ~w.', [Z]), nl,
fail.
Upvotes: 0
Views: 68
Reputation: 4422
Can use call_nth to limit backtracking - example:
p(a).
p(b).
p(c).
example :-
call_nth(p(Letter), Nth),
writeln(Letter),
Nth =@= 2,
% Remove the p(c) choicepoint
!.
Result in swi-prolog:
?- example.
a
b
true.
Applying call_nth
to @TessellatingHeckler's answer:
landmark("Vienna", "Hundertwasser House").
landmark("Vienna", "Vienna State Opera").
landmark("Vienna", "Schonbrunn Palace").
landmark("Vienna", "The Hofburg").
landmark("Vienna", "Belvedere Palace").
landmark_limit(Limit, City, Place) :-
call_nth(landmark(City, Place), Nth),
( Limit @> Nth
-> true
; !
).
suggest_landmark:-
format('Name of the city interested in: ~n'),
read_line_to_string(user_input, City),
format('City: ~w.~n~n', [City]),
format('Number of landmarks: ~n'),
read(Num),
findall(Place, landmark_limit(Num, City, Place), Landmarks),
maplist(format('Landmarks: ~w.~n'), Landmarks).
Result in swi-prolog:
?- suggest_landmark.
Name of the city interested in:
|: Vienna
City: Vienna.
Number of landmarks:
|: 3.
Landmarks: Hundertwasser House.
Landmarks: Vienna State Opera.
Landmarks: Schonbrunn Palace.
true.
This is more efficient (in both performance and memory), if there are e.g. thousands of landmark/2
rules.
Upvotes: 1
Reputation: 28983
Can use findall/3
to get a list of all the landmarks for city X, then use append/3
to unify a list of length Y new variables with the first Y elements of the list of landmarks, i.e. take Y items from the front:
landmark("Vienna", "Hundertwasser House").
landmark("Vienna", "Vienna State Opera").
landmark("Vienna", "Schonbrunn Palace").
landmark("Vienna", "The Hofburg").
landmark("Vienna", "Belvedere Palace").
suggest_landmark:-
format('Name of the city interested in: ~n'),
read_line_to_string(user_input, X),
format('City: ~w.~n~n', [X]),
findall(Place, landmark(X, Place), Landmarks),
format('Number of landmarks: ~n'),
read(Y),
length(Selected, Y),
append(Selected, _, Landmarks),
maplist(format('Landmarks: ~w.~n'), Selected).
I'm using format's ~n
for newlines, read_line_to_string for the name so you aren't read
ing Prolog terms unnecessarily, and maplist to print, to avoid it being a failure driven loop and ending with 'false'.
Upvotes: 1