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):
= Student("z143", "Catherine", "Smith", "Senior")
s1 = Student("z352", "Niraj", "Kumar", "Sophomore")
s2 = GraduateStudent("z785", "Divya", "Bharti")
s3 = GraduateStudent("z982", "James", "O'Brien")
s4
= Instructor("a421", "Jennifer", "Martinez", "Professor")
i1 = Instructor("a572", "Jonathan", "Jones", "Instructor")
i2
= Course("CSCI", 1543, "Programming Principles in Python", 1, 3, [("Mon", 10, 12), ("Wed", 10, 12)])
c1 = Course("CSCI", 1342, "Computer Networks", 2, 4, [("Tue", 14, 16), ("Thu", 14, 16), ("Fri", 12, 13)])
c2 = Course("CSCI", 1352, "Computer Graphics", 1, 3, [("Tue", 10, 12), ("Thu", 10, 12)])
c3 = Course("SOCI", 1230, "Introduction to Sociology", 1, 3, [("Mon", 11, 13), ("Thu", 11, 13)])
c4 = Course("POLS", 1100, "American Politics", 2, 3, [("Tue", 10, 12), ("Thu", 10, 12)])
c5 = Course("SOCI", 1450, "Classical Sociological Theory", 1, 3, [("Mon", 12, 13), ("Wed", 12, 13), ("Fri", 12, 13)])
c6
= Registrar()
r
r.add_persons([s1,s2,s3,s4,i1,i2]) r.add_courses([c1,c2,c3,c4,c5, c6])
"a572", "SOCI", 1230, 1)
r.add_person_to_course("a572", "POLS", 1100, 2) # error due to conflict r.add_person_to_course(
"SOCI", 1230, 1, [("Mon", 9, 11), ("Wed", 9, 11)])
r.change_course_time("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 credits r.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 conflict r.add_person_to_course(
"SOCI", 1230, 1, [("Tue", 11, 13), ("Thu", 11, 13)]) # error due to conflict r.change_course_time(
"SOCI", 1230, 1, [("Tue", 12, 14), ("Thu", 12, 14)])
r.change_course_time( "z143", "SOCI", 1230, 1) r.add_person_to_course(