Selecting parts of a number and checking lists in Prolog - prolog

I have made this knowledge base from information provided in the question:
student(jill,12071992,computer_science,[tennis,lacrosse]).
student(joe,14021993,mathematics,[tennis,rugby,football]).
Which represents, the students name, their birth date, their subject, and the sports they play.
Question 1 -
born_before(N,Y) - student named N was born before year Y
born_before(N,Y):-student(N,____X,_,_), Y > X.
obviously the above doesn't work, my problem is i don't know how to segregate the YYYY from DDMMYYYY term in prolog, to then set it to X, so it can be compared to the Y value.
Question 2 -
plays_sport(N,S) - student named N plays sport S.
my attempt
plays_sport(N,S):-student(N,_,_,[S|Sx]), plays_sport(N,Sx).
this always returns false. I have tried to use tail recursion so that the sport can be matched from the lists of sports in the knowledge base.

For the first part of your question you could write rules to extract the year, the month, and the day from an integer representing the date in the ddmmyyyy format, like this:
extract_year(DDMMYYYY, YYYY) :- YYYY is mod(DDMMYYYY, 10000).
extract_day(DDMMYYYY, DD) :- DD is DDMMYYYY // 1000000.
extract_month(DDMMMYYYY, MM) :- DDMM is DDMMMYYYY // 10000, MM is mod(DDMM, 100).
// operator represents integer division, when the fractional part is dropped from the answer. mod/3 is an operation for finding the remainder of integer division.
You could then combine them back into yyyymmdd format, and compare as integers (demo).
For your second part, you could use memberchk(Element, List) to check if the desired sport is present in the list:
plays_sport(N,S) :- student(N,_,_,AllSports), memberchk(S, AllSports).

Related

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 Between two set times

LONG STORY SHORT
I have a file called timetable.pl that has a pradicate (r,s,t)- r is the name of the train, s is the list of stations it stops at and t is a list of given times for the them stops.
THE file timetable.pl defines a predicate nextTime so that next time(t1,t2) holds if t2 is five minutes after t1.
I have to define a predicate si after t1, t2 holds if t2 is after and before midnight..
I just need some guidance here.
As a starting point, you want to think about a reasonable way to represent times of day.
Prolog lets you use your own functors to structure data as you wish. So you can have name(fred) and process or manipulate this piece of information with code that you write. Prolog doesn't affix any special meaning to it other than knowing it's a functor name and one argument, an atom, fred.
This also works with infix functors. So you can represent a time of day as, HH:MM. For example,
Time = 12:42.
Here, the user-defined functor is : and it has two integer arguments: 12 and 42. This could also be written, ':'(12,42).
If I have a time Time that uses this representation, I can separate out the hours and minutes by unifying it with the functor form:
| ?- Time = 12:42, Time = Hours:Minutes.
Hours = 12
Minutes = 42
Time = 12:42
yes
| ?-
If you have to times, T1 and T2, and they use this representation, you can compare these two times just by comparing their component hours and minutes as integer values. Assuming a 24-hour format, if Time1 = H1:M1 and Time2 = H2:M2, then Time1 is less than Time2 if H1 < H2, or if H1 = H2 and M1 < M2.
This works well for 24-hour time. If you want 12-hour time with an AM/PM designator, you can do it a number of ways, such as, tod(HH:MM, AMPM) (example: tod(12:42, am)), or [HH:MM, AMPM] (example: [12:42, pm]). When having to compare and manipulate times, the 24-hour format is easier. :)

This prolog program shows error and i m unable to detect the error [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am trying to create a Palindrome Programme on Visual Prolog that checks user input number.
I somehow wrote some codes BUT it shows error and it is difficult for me to remove errors.
Please,
I need help on this code.
DOMAINS
Num,Temp,Reverse=integer
PREDICATES
palindrome
CLAUSES
*
palindrome:-
Reverse=:=0,
write("Enter a number to check ."),
readint(Number),
Temp=Number
loop(Temp=/=0) :-
Reverse=Reverse*10,
Reverse=Reverse+ Temp mod 10,
Temp=Temp/10,
false.
(Number=:=Reverse->
write("The Number ",Number," is a Palindrome "),
fail ; Number=/=Reverse->
write("The Number ",Number," is not a Palindrome.") ; .
GOAL
palindrome.
In writing a prolog program, it can be helpful to write down a clear, specific problem statement and decompose the problem. Something like:
A number is palindromic, IF it is an integer,
and IF its digits are identical when reversed, ignoring its sign.
That leads us to this interface predicate which pretty much recapitulates the problem statement, thus:
%---------------------
% the public interface
%---------------------
palindromic_number(X) :- % A number is palindromic if
integer(X) , % - it is an integer, and
X >= 0 , % - it is greater than or equal to zero, and
reverse_digits(X,0,X) % - its decimal value is the same if you reverse its decimal digits
. % ... OR ...
palindromic_number(X) :- % it is palindromic, if
integer(X) , % - it is an integer, and
X < 0 , % - it is less than zero, and
X1 is - X , % - its absolute value
palindromic_number(X) % - is palindromic
. % Easy!
Now, all we have to do is figure out how to reverse the digits of a number. Given that we've eliminated dealing with the sign, above, it's easy: Strip digits from the right end, adding them to the left end of the result, until we hit zero.
A useful idiom in prolog is to have a public predicate that fronts a private workder predicate that often takes an accumulator wherein the final result is built up as you recursively work the problem. Also, in this case (and many others), there is usually a general case and one or a few special cases. Here, our special case, which terminates the compuation is when the source value is zero.
Which leads us to this definition of "how to reverse the digits of a number":
% ---------------------
% The worker predicate
% ---------------------
reverse_digits(0,T,T). % once we hit zero, the accumulator has the reversed number. Unify the accumulator with the desired result.
reverse_digits(X,T,Y) :- % Otherwise...
X > 0 , % - if X > 0,
X1 is X / 10 , % - compute the next X
D is X mod 10 , % - compute the nexst digit
T1 is 10*T + D , % - scale the accumulator and add the digit
reverse_digits(X1,T1,Y) % - recurse down.
. % - easy!
Another approach, of course, would be to convert the number into a string (which is a list of individual characters), reverse that list using the built-in reverse/2 predicate and unify that with the original value. I doubt that is what your instructor is looking for, however.

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

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, !.

Resources