#include 'course.lp'.
_hasTaken(Student, Course):-
_substitution(Course, Course2), %valid substitutitions in req file
_hasTaken(Student, Course2).
hasNotTaken(Student,Course) :- not _hasTaken(Student, Course).
_t(Student,Course) :- _hasTaken(Student,Course).
_t(Student,Course) :- hasNotTaken(Student,Course).
_takenFor(Student, Course, Req):-
% Use _takenForElective/3 to avoid unnecessary call to _req/2 in _takenForElective/2
% since we assume a course can only satisfy one requirement.
not _takenForElective(Student,Course,Req).
_takenForElective(Student, Course):-
% 'not _takenFor(Student, Course, none)' should always hold because 'none'
% is a placeholder requirement for courses that do not satisfy any requirement.
% So, we can avoid an unnecessary call to the dual of _takenFor/3 and gain some performance.
_req(Course,none).
_takenForElective(Student, Course, Req):-
not _takenFor(Student,Course,Req).
_takenForElective(Student, Course):-
_req(Course, Req),
not _takenFor(Student,Course,Req).
% Succeeds 'Student' student has taken 'Min' hours towards the 'Req' degree requirement.
_meetsHours(Student, Req, Min):-
_countHours(Student,Sum,Req),
Sum >= Min.
% Will always succeed. needsHours(Student, Req, Diff) will appear in the answer set
% if 'Student' has taken 'Sum' hours towards the 'Req' degree requirement with 'Sum' < 'Min' and
% 'Diff' = 'Min' - 'Sum'
_auditHours(Student, Req, Min):-
_taken(Student, CourseList),
_auditHours(Student, Req, CourseList,Min).
_auditHours(Student, Req, Min):-
_countHours(Student, Sum, Req),
Diff is Min - Sum,
needsHours(Student,Req,Diff).
needsHours(Student, Req, Diff).
_auditHours(Student, Req, List, Min):-
Min =< 0.
_auditHours(Student, Req, [Course|Tail], Min):-
_req(Course, Req),
_course(Course, H),
_takenFor(Student, Course, Req),
Min_sub is Min - H,
_auditHours(Student, Req, Tail, Min_sub).
_auditHours(Student, Req, [Course|Tail], Min):-
_auditHours(Student, Req, Tail, Min).
% Counts the number of hours 'Student' has taken towards the 'Req' degree requirement.
_countHours(Student, Sum, Req):-
_taken(Student, List),
_countHours(Student,List,Sum,Req).
_countHours(Student, [], 0, Req).
_countHours(Student, [Course|Tail], Sum, Req):-
_req(Course, Req),
_course(Course, H),
_takenFor(Student,Course,Req),
_countHours(Student,Tail,Sum_Tail,Req),
Sum is H + Sum_Tail.
_countHours(Student,[H|T],Sum,Req):-
_countHours(Student,T,Sum,Req).
% Succeeds if 'Student' has taken 'Min' elective hours.
_meetsElectiveHours(Student, Min):-
_countElectiveHours(Student, Sum),
Sum >= Min.
% Will always succeed. needsElectiveHours(Student, Diff) will appear in the answer set
% if 'Student' has taken 'Sum' elective hours with 'Sum' < 'Min' and
% 'Diff' = 'Min' - 'Sum'
_auditElectiveHours(Student, Min):-
_taken(Student, CourseList),
_auditElectiveHours(Student, CourseList, Min).
_auditElectiveHours(Student, Min):-
_countElectiveHours(Student, Sum),
Diff is Min - Sum,
needsElectiveHours(Student,Diff).
needsElectiveHours(Student,Diff).
_auditElectiveHours(Student, Min):-
_taken(Student, CourseList),
_auditElectiveHours(Student, CourseList, Min).
_auditElectiveHours(Student, List, Min):-
Min =< 0.
_auditElectiveHours(Student, [Course|Tail], Min):-
_course(Course,H),
_takenForElective(Student, Course),
Min_sub is Min - H,
_auditElectiveHours(Student, Tail, Min_sub).
_auditElectiveHours(Student,[Course|Tail], Sum):-
_auditElectiveHours(Student,Tail, Sum).
% Counts the number of elective hours 'Student' has taken.
_countElectiveHours(Student, Sum):-
_taken(Student, List),
_countElectiveHours(Student,List,Sum).
_countElectiveHours(Student, [], 0).
_countElectiveHours(Student, [Course|Tail], Sum):-
_course(Course, H),
_takenForElective(Student,Course),
_countElectiveHours(Student,Tail,Sum_Tail),
Sum is H + Sum_Tail.
_countElectiveHours(Student,[H|T],Sum):-
_countElectiveHours(Student,T,Sum).