%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Initial Code Base for the CS101/Spr08 Prolog Homework % You can run this by % % swipl % ?- [spr09,hw4code]. % ?- loop. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % this is the predicate that loop :- interact,!,loop. interact :- write_prompt, read_request(UserRequest), UserRequest \= [quit], % this allows the user to end the loop by typing quit question(Tree, UserRequest, []), findanswers(Tree,Answer), showanswers(Answer). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % parsing the question into a tree representation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% question(show_courses(Q)) --> [show,courses],qualifiers(Q). qualifiers([]) --> []. qualifiers([dept(Ds)|Qs]) --> [in],depts(Ds),qualifiers(Qs). qualifiers([block(B)|Qs]) --> [in,block],blocks(B),qualifiers(Qs). qualifiers([notblock(B)|Qs]) --> [not,in,block],blocks(B),qualifiers(Qs). qualifiers([instr(I)|Qs]) --> [taught,by],[I],qualifiers(Qs). qualifiers([not_onday(Ds)|Qs]) --> [not,meeting,on],days(Ds),qualifiers(Qs). depts([D]) --> [D]. depts([D|Ds]) --> [D],[or],depts(Ds). days([D]) --> day(D). days([D|Ds]) --> day(D),[or],days(Ds). day(X) --> [X],{member(X,[mon,tue,wed,thu,fri])}. % This is equivalent to the following more verbose DCGs % day(mon) --> [mon]. % day(tue) --> [tue]. % day(wed) --> [wed]. % day(thu) --> [thu]. % day(fri) --> [fri]. blocks([B]) --> block_id(B). blocks([B|Bs]) --> block_id(B), [or], blocks(Bs). block_id(B) --> [B],{block_time(B,_)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Finding the answers to the query % The course predicate has the form: % course(Semester,Year,Dept,Num,Suffix,Section,Title,Enrollment,Instructor) % course(S,Y,D,N,Su,Sc,T,E,I) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% findanswers(show_courses(Qs),courses(L)) :- setof(N,satisfies(N,Qs),L). findanswers(_,[]). % setof fails if there are no answers, findanswers doesn't % first we handle lists of constraints % and a course number must statify everything in the list satisfies(N,[]) :- course_dept(N,_). % any course satisfies the empty constraint satisfies(N,[Q|Qs]) :- satisfies(N,Q), satisfies(N,Qs). % next we handle individual constraints.. % dept(Ds) requires the course dept to be one of the specified departments satisfies(N,dept(Ds)) :- course_dept(N,D),member(D,Ds). % instr(Is) requires the instructor to be in the specified list satisfies(N,instr(I)) :- course_instr(N,I). % block(Bs) succeeds if course N is in one of the specified blocks satisfies(N,block(Bs)) :- course_block(N,B),member(B,Bs). % notblock(Bs) succeeds if course N is not in one of the specified blocks satisfies(N,notblock(Bs)) :- course_block(N,B),not(member(B,Bs)). % not_onday(Ds) takes a list of days satisfies(N,not_onday(Ds)) :- course_free_on_day(N,Ds). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % this shows the answers if they are a set of courses showanswers(courses(L)) :- write_sorted_classes(L). showanswers([]) :- write('Your query had no results'),nl. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % accessor predicates %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% course_dept(ID,Dept) :- course(ID,Dept,_Num,_Suffix,_Sec,_Title,_Block,_LN,_FN). course_num(ID,Num) :- course(ID,_Dept,Num,_Suffix,_Sec,_Title,_Block,_LN,_FN). course_suffix(ID,Suffix) :- course(ID,_Dept,_Num,Suffix,_Sec,_Title,_Block,_LN,_FN). course_block(ID,Block) :- course(ID,_Dept,_Num,_Suffix,_Sec,_Title,Block,_LN,_FN). course_instr(ID,LN) :- course(ID,_Dept,_Num,_Suffix,_Sec,_Title,_Block,LN,_FN). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Code to handle scheduling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Here are all of the blocks and their times ... block_time(a, 'MTWTF 9-10 '). block_time(b, 'MWT 9-10 '). block_time(c, 'MWT 10-11 '). block_time(d, 'MWT 11-12 '). block_time(e, 'MWT 12-1 '). block_time(f, 'MWT 1-2 '). block_time(g, 'TF 9-10:30 '). block_time(h, 'TF 10:30-12 '). block_time(j, 'TF 12-1:30 '). block_time(k, 'TF 2-3:30 '). block_time(l, 'MW 3:30-5 '). block_time(m, 'MW 5-6:30 '). block_time(n, 'TF 1:30-3 '). block_time(p, 'TF 3-4:30 '). block_time(s1,'M 2-5 '). block_time(s2,'T 1:30-4:30 '). block_time(s3,'W 2-5 '). block_time(s4,'F 1:30-4:30 '). block_time(s5,'T 4:30-7:30 '). block_time(s6,'T 9-12 '). block_time(s7,'F 9-12 '). block_time(v,'TT 5-6:30 '). block_time(x1,'M 6:30-9:30 '). block_time(x2,'W 6:30-9:30 '). block_time(x3,'Th 6:30-9:30'). block_time(x4,'T 6:30-9:30 '). block_time(y ,'MW 6:30-8 '). block_time(tba,'TBA'). % Here is the rule to tell when two blocks have a conflict conflicts(X,X). % any course conflicts with itself! conflicts(k,s1). conflicts(l,s1). conflicts(s1,k). conflicts(s1,l). conflicts(k,s3). conflicts(l,s3). conflicts(k,s3). conflicts(l,s3). conflicts(g,s6). conflicts(h,s6). conflicts(s6,g). conflicts(s6,h). conflicts(g,s7). conflicts(h,s7). conflicts(s7,g). conflicts(s7,h). conflicts(n,s2). conflicts(p,s2). conflicts(s2,n). conflicts(s2,p). conflicts(n,s4). conflicts(p,s4). conflicts(s4,n). conflicts(s4,p). conflicts(n,r). conflicts(s2,r). conflicts(s4,r). conflicts(r,n). conflicts(r,s2). conflicts(r,s4). conflicts(v,s5). conflicts(v,s8). conflicts(s5,v). conflicts(s5,x4). conflicts(q,x1). conflicts(q,x2). conflicts(q,x3). conflicts(q,y). conflicts(x1,y). conflicts(x4,5). conflicts(x2,q). conflicts(x2,y). conflicts(x3,q). conflicts(x3,s8). % this tests to see if a course with number N does not meet on day D course_free_on_day(N,D) :- course_block(N,B),free_day(B,D). % this tests if a block B does not meet on some particular day free_day(B,mon) :- member(B,[g,h,j,k,n,p,s2,s3,s4,s5,s6,s7,v,x2,x3,x4]). free_day(B,tue) :- member(B,[b,c,d,e,f,l,m,s1,s3,s4,s7,x1,x2,x3,y]). free_day(B,wed) :- member(B,[g,h,j,k,n,p,s1,s2,s4,s5,s6,s7,v,x1,x3,x4]). free_day(B,thu) :- member(B,[g,h,j,k,n,l,m,n,p,s1,s2,s3,s4,s5,s6,s7,x1,x2,x4,y]). free_day(B,fri) :- member(B,[b,c,d,e,f,l,m,s1,s2,s3,s5,s6,v,x1,x2,x3,x4,y]). % and this extends it to not meet on a list of days... free_day(_,[]). free_day(B,[D|Ds]) :- free_day(B,D),free_day(B,Ds). % this tests if two courses do not conflict courses_no_conflict(N1,N2) :- course_block(N1,B1),course_block(N2,B2),not(conflicts(B1,B2)). % this tests if a course does not conflict with a list of courses course_doesnot_conflict(_N1,[]). course_doesnot_conflict(N1,[N|Ns]) :- course_doesnot_conflict(N1,Ns), courses_no_conflict(N1,N). % this tests if a list of courses has no conflicts no_conflicts([]). no_conflicts([B|Bs]) :- no_conflicts(Bs), course_doesnot_conflict(B,Bs). schedule1(L) :- L=[A,B,C,D], course_dept(A,cosi),course_num(A,N1),N1>100, course_dept(B,cosi),course_num(B,N2),N2>100, course_dept(C,econ), member(X,[eng,hist]),course_dept(D,X), no_conflicts(L). schedule([],[]). schedule([A|As],Cs) :- schedule(As,Bs), ( (course_doesnot_conflict(A,Bs),Cs=[A|Bs]);Cs=Bs). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Auxilliary Procedures for I/O % These are I/O procedures need to read/write strings... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% write_prompt :- write('>> '),flush. read_request(U) :- readLine(U1), tokenize_atom(U1,U). % readLine(L) --- % This procedure uses the Java readLine method on System.in % to read in a line of text from the terminal.... % it corresponds to the Java call % (new java.io.BufferedReader % (new java.io.InputStreamReader( % java.lang.System.in))).readLine() % or equivalently to the JScheme code % (.readLine % (java.io.BufferedReader. % (java.io.InputStreamReader. % java.lang.System.in$)))) % readLine(L) :- jpl_get('java.lang.System','in',In), jpl_new('java.io.InputStreamReader',[In],ISReader), jpl_new('java.io.BufferedReader',[ISReader],BReader), jpl_call(BReader,'readLine',[],L). writelist([]). writelist([A|As]) :- write(A),nl,writelist(As). % this write the list of classes L in order by their block number % it uses the predsort method to specify the ordering to be used write_sorted_classes(L) :- predsort(blockorder,L,S), writeclasses(S). blockorder(<,N1,N2) :- course_block(N1,B1),course_block(N2,B1). blockorder(A,N1,N2) :- course_block(N1,B1),course_block(N2,B2),B1\=B2,compare(A,B1,B2). % this takes a list L of course numbers and writes out the elements in a nice format writeclasses([]). writeclasses([A|As]) :- course(A,Dept,Num,Suf,Sec,Title,Block,Last,First), block_time(Block,Time), write(Time),write(': '), write(course(A,Dept,Num,Suf,Sec,Title,Block,Last,First)),nl, writeclasses(As).