The goal of this assignment is to work with object-oriented programming in Python.
You will be doing your work in a Jupyter notebook for this
assignment. You may choose to work on this assignment on a hosted
environment (e.g. tiger)
or on your own local installation of Jupyter and Python. You should use
Python 3.12 for your work. (Older versions may work, but your code will
be checked with Python 3.12.) To use tiger, use the credentials you
received. If you work remotely, make sure to download the .ipynb file to
turn in. If you choose to work locally, Anaconda or miniforge are
probably the easiest ways to install and manage Python. If you work
locally, you may launch Jupyter Lab either from the Navigator
application (anaconda) or via the command-line as
jupyter-lab or jupyter lab.
In this assignment, we will be implementing a collection of classes that work together to orchestrate course scheduling in a university setting. There will be a central registrar that coordinates scheduling for students and professors with methods to add and remove persons from courses. You will need to test your classes to make sure they work properly (See Section 6 for a summary of the items to be implemented and some non-comprehensive test code).
The assignment is due at 11:59pm on Friday, November 8.
You should submit the completed notebook file required for this
assignment on Blackboard. The
filename of the notebook should be a6.ipynb.
Please make sure to follow instructions to receive full credit. Because you will be writing classes and adding to them, you do not need to separate each part of the assignment. Please document any shortcomings with your code. You may put the code for each part into one or more cells. Note that CS 503 Students must complete Section 5 which is optional for CS 490 students.
The first cell of your notebook should be a markdown cell with a line for your name and a line for your Z-ID. If you wish to add other information (the assignment name, a description of the assignment), you may do so after these two lines.
Create four classes related to the people involved in university
course scheduling: Academic, Student,
GraduateStudent, and Instructor.
Academic is the base class which has a first name, last
name, and campus_id. It also has a field max_credits which
should be initialized to a default value based on the type of person
(more on this later in the paragraph). While it will be used as an
abstract base class (not intended to be instantiated),
we didn’t cover the specifics of such a definition
so you do not need to define it differently. Student is an
Academic that has a level (“Freshman”, “Sophomore”,
“Junior”, “Senior”, “Graduate”), and GraduateStudent is a
Student whose level is always “Graduate”.
Instructor is an Academic that has a rank
(“Assistant Professor”, “Associate Professor”, “Professor”,
“Instructor”). You must use inheritance properly here.
Each student should have a default maximum number of credits of 16, each
graduate student has a default maximum of 12, and each instructor has a
default maximum of 9. Use a class attribute, MAX_CREDITS,
to store this default, but only one place in the code
should assign to the max_credits field.
self will
look up attributes based on the MRO so with multiple definitions of
MAX_CREDITS, it will “do the expected thing”.Create a Course class that stores information about a
course: department, course number, course name, section, number of
credits, times. The course class also keeps track of the instructor
(which may be unassigned) and all students enrolled. Note that times
will be submitted as a list of tuples of the form (day :
str, start_time : int, end_time : int). Add a
method to produce a string representation that lists the department,
course number, course name, section, number of credits, and times. The
class should have enroll and drop methods to
add/remove a student from the course, and a change_time
method to update the times of the course.
Create a Schedule class that tracks all courses an
Academic is involved in. The constructor should take an optional list of
courses to be added to the schedule. It should have a
credits property (getter only) that
returns the sum of the number of credits in all courses. It should have
an add_course method that adds the course to the
schedule.
Update the Academic class to add a schedule to each
instance plus add_course and remove_course
methods. The add_course method should first check if the
course to be added will exceed the maximum number of credits for the
person. If it doesn’t, the course should be added to the schedule. If it
does conflict, raise an exception. Override the add_course
method in the Student class to enroll (add) the student to
the Course and in the Instructor class to set the
instructor of the Course. The remove_course method in the
Student class should drop a student from the Course, and in
the Instructor class should unset the instructor of the
course. Also, add support for adding and dropping courses using the
+ and - operators.
super() to use the Academic
add/remove_course methods while also doing the (different)
extra steps for students/instructors.Create a Registrar class that orchestrates the
scheduling process. The registrar should keep track of all academic
persons and all courses. It should have add_persons,
add_courses, add_person_to_course, and
remove_person_from_course methods. The add/remove person
to/from course methods should take a campus id, department,
course_number, and section, and then add the person referenced by the id
to the course referenced by the three other pieces of information. You
should call the add/remove_course methods, but note that polymorphism
will be in effect here, meaning the method called will be different for
students and instructors.
We will now add logic to change course times and raises an exception
if this is not possible. Add a check_time_conflicts
static method to the Course class that
given two time structures (list of tuples), checks if any times
conflict, returning True if the two lists conflict and
False otherwise. Two times conflict if they have meetings
on the same day such that the starting time of one meeting is in between
the starting and ending times of another meeting. For example, (“Mon”,
11, 13) and (“Mon”, 12, 14) conflict, but (“Mon”, 11, 13) and (“Mon”,
13, 15) do not.
In the Schedule class, update the
add_course method to check whether the course conflicts
with the person’s current schedule before adding the course, raising an
exception if it does.
In the Registrar class, add a
change_course_time method that calls the
change_time method implemented in the Course
class, and that Course method must check that the proposed new time does
not cause any conflicts with any currently enrolled students’ or the
assigned instructor’s schedules. If it does, the method should raise an
exception. If it doesn’t, the time of the course should be changed.
Registrar.change_course_time must check enrolled
students and the instructor.a < b < c checks that
b is between a and c.The final list of classes and methods/properties to be added. Note that all classes should have constructors that properly initialize objects, and the instance fields are not listed here.
The following code should help you test your work (for 490 students,
the errors for conflicts will not show up, and you will not have
change_course_time methods):
s1 = Student("z143", "Catherine", "Smith", "Senior")
s2 = Student("z352", "Niraj", "Kumar", "Sophomore")
s3 = GraduateStudent("z785", "Divya", "Bharti")
s4 = GraduateStudent("z982", "James", "O'Brien")
i1 = Instructor("a421", "Jennifer", "Martinez", "Professor")
i2 = Instructor("a572", "Jonathan", "Jones", "Instructor")
c1 = Course("CSCI", 1543, "Programming Principles in Python", 1, 3, [("Mon", 10, 12), ("Wed", 10, 12)])
c2 = Course("CSCI", 1342, "Computer Networks", 2, 4, [("Tue", 14, 16), ("Thu", 14, 16), ("Fri", 12, 13)])
c3 = Course("CSCI", 1352, "Computer Graphics", 1, 3, [("Tue", 10, 12), ("Thu", 10, 12)])
c4 = Course("SOCI", 1230, "Introduction to Sociology", 1, 3, [("Mon", 11, 13), ("Thu", 11, 13)])
c5 = Course("POLS", 1100, "American Politics", 2, 3, [("Tue", 10, 12), ("Thu", 10, 12)])
c6 = Course("SOCI", 1450, "Classical Sociological Theory", 1, 3, [("Mon", 12, 13), ("Wed", 12, 13), ("Fri", 12, 13)])
r = Registrar()
r.add_persons([s1,s2,s3,s4,i1,i2])
r.add_courses([c1,c2,c3,c4,c5, c6])r.add_person_to_course("a572", "SOCI", 1230, 1)
r.add_person_to_course("a572", "POLS", 1100, 2) # error due to conflictr.change_course_time("SOCI", 1230, 1, [("Mon", 9, 11), ("Wed", 9, 11)])
r.add_person_to_course("a572", "SOCI", 1450, 1)
r.add_person_to_course("a421", "CSCI", 1543, 1)
r.add_person_to_course("a421", "CSCI", 1342, 2)
r.add_person_to_course("a421", "CSCI", 1352, 1) # error due to max creditsr.add_person_to_course("z785", "SOCI", 1230, 1)
r.add_person_to_course("z785", "CSCI", 1352, 1)
r.add_person_to_course("z143", "CSCI", 1543, 1)
r.add_person_to_course("z143", "CSCI", 1342, 2)
r.add_person_to_course("z143", "SOCI", 1230, 1) # error due to conflictr.change_course_time( "SOCI", 1230, 1, [("Tue", 11, 13), ("Thu", 11, 13)]) # error due to conflictr.change_course_time( "SOCI", 1230, 1, [("Tue", 12, 14), ("Thu", 12, 14)])
r.add_person_to_course("z143", "SOCI", 1230, 1)