How to compare time to a time range specified in Prolog? - time

Let's say i have a structure comparetime(hours,mins),
when a user keys example comparetime(10,40) ,
the structure will make comparison on a time range specified example
timing entered
1) from 10:00 to 12:00 will print a message and
2) from 18:00 to 20:00 will print a message .
if the time keyed is not inside the range, it will also print a message.
how can I do this ?
it's easy to compare words but i'm really having a tough time with comparing time.

It's easy compare words?
You should try it when internationalization is involved to appreciate how difficult could be!
Far easier is compare pair of integers, as from your problem (if I understand the question).
message_on_range(1, 10:00, 12:00, 'it\'s morning!').
message_on_range(2, 18:00, 20:00, 'it\'s evening!').
comparetime(Hours, Mins) :-
message_on_range(_, Start, Stop, Message),
less_equal_time(Start, Hours:Mins),
less_equal_time(Hours:Mins, Stop),
write(Message), nl.
comparetime(_Hours, _Mins) :-
write('please check your clock!'), nl.
less_equal_time(H1:S1, H2:S2) :-
H1 == H2 -> S1 =< S2 ; H1 < H2.
You should be aware of Prolog features: your problem could require a cut after the message has been printed! I.e.
...
less_equal_time(Hours:Mins, Stop),
write(Message), nl, !.

Related

Check if a country reaches the threshold

Hi guys i'm new to prolog and i'm trying to understand something:
I have this database:
countries([belgium, france, germany, italy, luxembourg, netherlands]).
weight(france, 4).
weight(germany, 4).
weight(italy, 4).
weight(belgium, 2).
weight(netherlands, 2).
weight(luxembourg, 1).
threshold(12).
And I made this program to see if a list of countries have enough votes to get over the threshold and i want to use a predicate winning/1
winning([H|T]):-
weight(H, N1),
winning(T),
weight(T, N2),
N is N1 + N2,
N>=X,
threshold(X).
The program runs perfectly up untill the point it has to add up the voting power and conclude whether the votes reach the threshold.
Its difficult because I only want to use a predicate winning/1 can anyone help me out?
The reason it is not adding up N1 and N2 into N is because you are asking the weight-number for the entire Tail, when you should just get the weight of only the head of the Tail. Which at this point you don't have yet.
You want to create a separate (recursive) rule, winning/2 and call it from winning/1:
winning(Countries) :-
winning2(Countries,0).
In this separate winning/2 you call for the weight which you store in N and call back winning/2 recursively until N reaches the threshold.
winning2([],N) :-
threshold(X),
N >= X.
winning2([Country|Tail], N) :-
weight(Country,X),
NewN is X + N,
winning2(Tail, NewN).

Prolog: Difference relation between two objects

I will be honest and preface this by saying it is homework, but I desperately need help.
I am new to Prolog, coming from C++ and Javascript and no matter how hard I try, I'm just not getting it.
What I am supposed to do is to be able to find the difference between two dates (assuming non leap year).
Basically I have a knowledge base with information laid out like:
object(A, B).
object(A, B).
...
where A represents month and B represents total days of the month.
(eg. object(1, 31).)
The expression I am supposed to use for input is this:
Difference(Object(A,B), object(A,B), N).
(N = difference between the objects).
I have tried a few different things (and I know this isn't on the right track) and haven't been able to get further then:
difference(object(A,B), object(A,B),N):-
days(M,D), days(M,D),
Y = 365-D,
N is Y.
I don't understand how to make the two objects register as individual things that I can manipulate and therefore continue with the problem.
Can someone please please please point me in the right direction?
Thanks
Homework Question (AS REQUESTED).
Assume the presence of the days relation that describes how many days are in
each calendar month of a non-leap year.
days(1,31).
days(2,28).
(and so on).
The structure dateObject(M, D) describes a date. For example dateObject(6,5) would denote the 5th of June.
Write the relation difference(From, To, N), where N is the number of days between starting
date From and finishing date To. The From date is not included in the count. For
example:
?- difference(dateobject(2,1),dateobject(2,2),N).
N = 1.
If the day or month values in a date are invalid (e.g. dateobject(4,31), dateobject(13,1) then the
value of N returned should be -1. If the From date is later than To then the -1 error value should also be returned for N.
Here's a really bad solution - I'm sure someone smarter than me will come up with something better.
?- difference(dateobject(1,28),dateobject(6,1),N),write(N),nl.
days(1,31).
days(2,28).
days(3,31).
days(4,30).
days(5,31).
days(6,30).
days(7,31).
days(8,31).
days(9,30).
days(10,31).
days(11,30).
days(12,31).
daysbetween(M,FD,M,TD,N) :- !, N is TD - FD.
daysbetween(FM,FD,TM,TD,N) :-
days(FM,D),
FM2 is FM + 1,
daysbetween(FM2,FD,TM,TD,N2),
N is D + N2.
difference(dateobject(FM,FD),dateobject(TM,TD),N) :-
TM >= FM,
FD >= 1,
days(FM,FDM),
FD =< FDM,
TD >= 1,
days(TM,TDM),
TD =< TDM,
daysbetween(FM,FD,TM,TD,N),
N > 0,
!.
difference(_,_,-1).

combining all possible results in one list in prolog

I'm trying to find the available slot which comes from the predicate quizslots/3 quizslot(Group, Day, Slot).
quizslot(group4, tuesday, 1).
quizslot(group4, thursday, 1).
quizslot(group6, saturday, 5).
This is my hypothesis but it doesn't seem to work fine.
available_timings(G,L):-
setof(X,quizslot(G,X,_),L).
I want the result for (group4,L), L = [tuesday,1,thursday,1].
Syntax of setof:
% Set of every FooResult
?- setof(FooResult,foo(X,Y,FooResult),Result).
[FooResult1, FooResult2, ..]
% Set of tuples of every input X and FooResult
?- setof((X,FooResult),foo(X,Y,FooResult),Result).
[(X1,FooResult1), (X2,FooResult2), ..]
% Set of lists of every input X and FooResult, ommitting input Y
?- setof([X,FooResult],foo(X,_,FooResult),Result).
[[X1,FooResult1], [X2,FooResult2], ..]
I think you get the point. As lurker stated in his answer above, you are trying to have the slot included in the result, however, you tell prolog to find all distinct quizslot-facts of the form:
quizslot(group G, day X, whatever slot)
Since this wildcard will match with any slot, you cannot retrieve the actual variable holding the slot, Prolog didn't bother retrieving the variable for you.
A correct usage would be, for example, one of the following
setof([Day,Slot], quizslot(Group,Day,Slot), Result) % List of lists
setof((Day,Slot), quizslot(Group,Day,Slot), Result) % List of tuples

Prolog oldest Successor

I'm working on a simple program that has a database of people. When given a year it should state the "King" of that year, where the king is the eldest living man.
For simplicity, all people in the database are eligible as long as they are alive at the given year and I'm assuming there are no twins.
My problem is picking the "oldest" person alive during a given year. I can't seem to figure out how to ask Prolog to examine all possible kings and pick the oldest.
male(jack).
male(roy).
male(ele).
born(jack,2000).
born(dave,1999).
born(roy,1980).
born(ele,1990).
died(jack, 2100).
died(dave, 2099).
died(roy, 1990).
died(ele, 1999).
% compare X against all other possibleSuccessors and make sure he was born 1st.
eldest(X,Year):-
born(X,T1),
born((possibleSuccessor(Year,_)),T2),
T1 < T2.
% must be male and have been born before or during the given year and must not be dead.
possibleSuccessor(Year, X):-
male(X),
born(X,B),
died(X,D),
(B =< Year),
(D >= Year).
successor(Year):-
possibleSuccessor(Year,X),
eldest(X,Year),
write(X).
Any help on comparing all possible answers vs one another would be appreciated. I attempted to use findall before but was unsuccessful.
Prolog offers a restricted form of negation (negation by failure) that solve your problem:
eldest(X,Year):-
born(X,Year),
\+((born(_,T), T<Year)).
this says that X is eldest if we can't find any other born before him.
alternatively, setof/3 can be used:
eldest(X,Year):-
setof((Y,K), born(K,Y), [(Year,X)|_]).
this works sorting all pairs (Y,K), then we can pick just the head of the result.
edit this should solve the problem, but I've introduced a service predicate
eldest(X, Year):-
alive(X, Year, B),
\+((alive(_, Year, T), T<B)).
alive(X, Year, B) :- born(X, B), B =< Year, \+ (died(X, D), D < Year).
% must be male and have been born before or durring the given year and must not be dead.
possibleSuccessor(Year,X):-
male(X),
alive(X, Year, _).
successor(Year):-
possibleSuccessor(Year,X),
eldest(X,Year),
write(X).

Hangman Game in SWI Prolog

I'm trying to make a simple hangman game in SWI Prolog.
Since we made this program run can you help me enchance the program with the following:
1) By keeping up with the letters that have been guessed so far. If the user guesses a letter that has already been guessed, the program should say 'You guessed that!' and just continue the game.
2) Lastly, add a counter that counts the number of incorrect guesses and quits the game when a certain number is reached. The program should tell the user that they lose, display what the phrase really was, and terminate. Duplicate guesses should not be counted as wrong.
I would like to thank everyone who helped me so far. This means a lot to me.
I provide you with the code and comments.
% This top-level predicate runs the game. It prints a
% welcome message, picks a phrase, and calls getGuess.
% Ans = Answer
% AnsList = AnswerList
hangman:-
getPhrase(Ans),
!,
write('Welcome to hangman.'),
nl,
name(Ans,AnsList),
makeBlanks(AnsList, BlankList),
getGuess(AnsList,BlankList).
% Randomly returns a phrase from the list of possibilities.
getPhrase(Ans):-
phrases(L),
length(L, X),
R is random(X),
N is R+1,
getNth(L, N, Ans).
% Possible phrases to guess.
phrases(['a_picture_is_worth_a_thousand_words','one_for_the_money','dead_or_alive','computer_science']).
% Asks the user for a letter guess. Starts by writing the
% current "display phrase" with blanks, then asks for a guess and
% calls process on the guess.
getGuess(AnsList, BlankList):-
name(BlankName, BlankList),
write(BlankName),
nl,
write('Enter your guess, followed by a period and return.'),
nl,
read(Guess),
!,
name(Guess, [GuessName]),
processGuess(AnsList,BlankList,GuessName).
% Process guess takes a list of codes representing the answer, a list of codes representing the current
% "display phrase" with blanks in it, and the code of the letter that was just guessed. If the guess
% was right, call substitute to put the letter in the display phrase and check for a win. Otherwise, just
% get another guess from the user.
processGuess(AnsList,BlankList,GuessName):-
member(GuessName,AnsList),
!,
write('Correct!'),
nl,
substitute(AnsList, BlankList, GuessName, NewBlanks),
checkWin(AnsList,NewBlanks).
processGuess(AnsList, BlankList,_):-
write('Nope!'),
nl,
getGuess(AnsList, BlankList).
% Check to see if the phrase is guessed. If so, write 'You win' and if not, go back and get another guess.
checkWin(AnsList, BlankList):-
name(Ans, AnsList),
name(BlankName, BlankList),
BlankName = Ans,
!,
write('You win!').
checkWin(AnsList, BlankList):-
!,
getGuess(AnsList, BlankList).
% getNth(L,N,E) should be true when E is the Nth element of the list L. N will always
% be at least 1.
getNth([H|T],1,H).
getNth([H|T],N,E):-
N1 is N-1,
getNth(T,N1,E1),
E=E1.
% makeBlanks(AnsList, BlankList) should take an answer phrase, which is a list
% of character codes that represent the answer phrase, and return a list
% where all codes but the '_' turn into the code for '*'. The underscores
% need to remain to show where the words start and end. Please note that
% both input and output lists for this predicate are lists of character codes.
% You can test your code with a query like this:
% testMakeBlanks:- name('csc_is_awesome', List), makeBlanks(List, BlankList), name(Towrite, BlankList), write(Towrite).
makeBlanks(AnsCodes, BlankCodes) :-
maplist(answer_blank, AnsCodes, BlankCodes).
answer_blank(Ans, Blank) :-
Ans == 0'_ -> Blank = Ans ; Blank = 0'* .
% substitute(AnsList, BlankList, GuessName, NewBlanks) Takes character code lists AnsList and BlankList,
% and GuessName, which is the character code for the guessed letter. The NewBlanks should again be a
% character code list, which puts all the guesses into the display word and keeps the *'s and _'s otherwise.
% For example, if the answer is 'csc_is_awesome' and the display is 'c*c_**_*******' and the guess is 's', the
% new display should be 'csc_*s_***s***'.
% You can test your predicate with a query like this:
% testSubstitute:- name('csc_is_awesome', AnsList), name('c*c_**_*******', BlankList), name('s',[GuessName]), substitute(AnsList, BlankList, GuessName, NewBlanks),
% name(Towrite, NewBlanks), write(Towrite).
% Also, since the predicate doesn't deal directly with character codes, this should also work:
% substitute(['c','s','c'],['c','*','c'],'s',L). L should be ['c','s','c'].
substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).
place_guess(Guess, Ans, Blank, Display) :-
Guess == Ans -> Display = Ans ; Display = Blank.
maplist/3 & maplist/4 apply their first argument (a predicate of appropriate arity) against all elements of other arguments lists, then your makeBlanks could be:
makeBlanks(AnsCodes, BlankCodes) :-
maplist(answer_blank, AnsCodes, BlankCodes).
answer_blank(Ans, Blank) :-
Ans == 0'_ -> Blank = Ans ; Blank = 0'* .
and substitute:
substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).
place_guess(Guess, Ans, Blank, Display) :-
Guess == Ans -> Display = Ans ; Display = Blank.
edit:
on additional requests: 1) can be solved with an additional predicate:
alreadyGuessed(Guess, AnsCodes) :-
memberchk(Guess, AnsCodes).
while regards 2) getGuess and processGuess together make a loop, that will just terminate when no more calls happen. Remove the last rule of checkWin, add an argument as counter to keep track of failed guesses, and extend processGuess to signal failure:
processGuess(AnsList, BlankList, _, CountFailed) :-
( CountFailed == 5
-> format('Sorry, game over. You didn\'t guess (~s)~n', [AnsList])
; write('Nope!'),
CountFailed1 is CountFailed + 1,
getGuess(AnsList, BlankList, CountFailed1)
).
Why so many cuts? Check out SWI library predicates that may be useful to you: memberchk/2, format/2 and nth1/3.

Resources