Skip to content

Commit

Permalink
working copy of Fall 2023, but code needs to be revised before merge …
Browse files Browse the repository at this point in the history
…to main
  • Loading branch information
carmen904c committed Sep 20, 2023
1 parent 305d7c2 commit b8ca269
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 53 deletions.
2 changes: 1 addition & 1 deletion vsvs_scheduler/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
COLUMN_NAMES
29 changes: 12 additions & 17 deletions vsvs_scheduler/applicants/classroom.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class Classroom:

def __init__(self, group_number: int, teacher: Teacher, start_time: str, end_time: str, weekdays: []):
def __init__(self, group_number: int, teacher: Teacher, start_time: str, end_time: str):
"""
Classroom object that holds information about a classroom and its volunteers.
Expand All @@ -18,14 +18,11 @@ def __init__(self, group_number: int, teacher: Teacher, start_time: str, end_tim
self.group_number = group_number
self.teacher = teacher

self.weekdays = weekdays
self.weekday_idx = 0 # index of the weekday in weekdays
self.weekday = weekdays[self.weekday_idx] # weekday the class is held on

self.volunteers = []
self.possible_volunteers = 0
self.possible_partner_groups = 0
self.team_leader = False
self.team_leader = False
self.weekday = None

self.start_time = datetime.strptime(start_time, '%I:%M:%S %p')
self.end_time = datetime.strptime(end_time, '%I:%M:%S %p')
Expand Down Expand Up @@ -53,22 +50,20 @@ def unassign_volunteers(self):
self.volunteers = []
self.team_leader = False

def change_to_next_preferred_day(self):
""" Updates the weekday to the next weekday preference. """

self.teacher.next_weekday()

def freeze_weekday(self):
""" Freezes the weekday to the current weekday preference. """
if self.weekday is None:
self.weekday = self.teacher.weekday

def duration(self):
""" Returns the duration of the class in minutes. (includes travel time) """
return (self.end_time - self.start_time + timedelta(hours=1)).seconds/60



def change_to_next_preferred_day(self):
""" Changes the weekday to the next preferred day."""
possible_weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday"]
if self.weekday_idx < 3 and self.weekdays[self.weekday_idx + 1] in possible_weekdays:
self.weekday_idx += 1
self.weekday = self.weekdays[self.weekday_idx]



def __repr__(self):
return f"{self.teacher.name} at {self.teacher.school} on {self.weekday} ({self.start_time.strftime( '%I:%M %p')} - {strftime(self.end_time.strftime('%I:%M %p'))})\n"
return f"{self.teacher.name} at {self.teacher.school} on {self.teacher.weekday} ({self.start_time.strftime( '%I:%M %p')} - {strftime(self.end_time.strftime('%I:%M %p'))})\n"
10 changes: 7 additions & 3 deletions vsvs_scheduler/applicants/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ def find_free_time_duration(self, availability: dict):



def can_make_class(self, classroom: Classroom):
def can_make_class(self, classroom: Classroom, last_round: bool = False) -> bool:
""" Returns True if the volunteer can make the class, False otherwise."""

if last_round and classroom.weekday != None:
weekday = classroom.weekday
else:
weekday = classroom.teacher.weekday

# Standardize the start time to the nearest 15 minute interval
time_deviation = classroom.start_time.minute % 15
if time_deviation != 0:
Expand All @@ -94,7 +98,7 @@ def can_make_class(self, classroom: Classroom):
start_time = classroom.start_time

# Volunteer schedule for the day of the class
weekday_schedule = self.processed_schedule[classroom.weekday]
weekday_schedule = self.processed_schedule[weekday]

if start_time in weekday_schedule:
return weekday_schedule[start_time] >= classroom.duration()
Expand Down
28 changes: 27 additions & 1 deletion vsvs_scheduler/applicants/teacher.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@

class Teacher:

def __init__(self, name: str, phone: str, school: str, email: str) -> None:
def __init__(self, name: str, phone: str, school: str, email: str, weekday_preferences: list) -> None:
""" Teacher object that holds information about a teacher."""

self.name = name
self.phone = phone #USE REGEX
self.school = school
self.email = email #USE REGEX
self.weekdays = weekday_preferences
self.weekday_idx = 0
self.weekday = self.weekdays[self.weekday_idx]
self.classrooms = []

def next_weekday(self) -> None:
""" Updates the weekday to the next weekday preference. """
possible_weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday"]
if self.weekday_idx < 3 and self.weekdays[self.weekday_idx + 1] in possible_weekdays:
self.weekday_idx += 1
self.weekday = self.weekdays[self.weekday_idx]

def add_classrooms(self, classroom) -> None:
""" Adds classrooms to the teacher's list of classrooms. """
self.classrooms.append(classroom)

def unassign_volunteers(self) -> None:
""" Unassigns volunteers from the classroom and resets their group number and assigned_leader status."""
for classroom in self.classrooms:
classroom.unassign_volunteers()

def reset_weekday(self) -> None:
""" Resets the weekday to the first weekday preference. """
self.weekday_idx = 0
self.weekday = self.weekdays[self.weekday_idx]


3 changes: 3 additions & 0 deletions vsvs_scheduler/applicants/volunteer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ def can_make_class(self, classroom: Classroom):

return self.availability.can_make_class(classroom)

def can_make_class_last_round(self, classroom: Classroom):
"""Returns boolean of whether volunteer can make a classroom based on the schedule parameter."""

return self.availability.can_make_class(classroom, last_round=True)

def assign_classroom(self, classroom: Classroom):
"""Assigns the volunteer to the classroom and updates the volunteer's group number."""
Expand Down
25 changes: 12 additions & 13 deletions vsvs_scheduler/class_data_uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,31 @@ def __init__(self):
def process_row_data(self, row: dict):
""" Process row data from csv/excel file into Classroom objects."""

number_of_classes = row['Number of Classes']
number_of_classes = int(row['Number of Classes'])
teacher = Teacher (
name= row['Name'],
phone= row['Cell Phone Number'],
school= row['School'],
email= row['Email Address']
)
email= row['Email Address'],
weekday_preferences=[
row[f'Days (Class {number_of_classes} of {number_of_classes}) [1st Preference]'],
row[f'Days (Class {number_of_classes} of {number_of_classes}) [2nd Preference]'],
row[f'Days (Class {number_of_classes} of {number_of_classes}) [3rd Preference]'],
row[f'Days (Class {number_of_classes} of {number_of_classes}) [4th Preference]']
]
)

# for each class a teacher has, create a classroom object and add it to the list 'applicants'
for i in range(int(number_of_classes)):
for i in range(number_of_classes):
self.group_num += 1
class_num = i + 1 # class_num keeps track of which class out of the total being created
classroom = Classroom(
group_number=self.group_num,
teacher=teacher,
start_time=row[f'Start Time (Class {class_num} of {number_of_classes})'],
end_time=row[f'End Time (Class {class_num} of {number_of_classes})'],
weekdays=[
row[f'Days (Class {class_num} of {number_of_classes}) [1st Preference]'],
row[f'Days (Class {class_num} of {number_of_classes}) [2nd Preference]'],
row[f'Days (Class {class_num} of {number_of_classes}) [3rd Preference]'],
row[f'Days (Class {class_num} of {number_of_classes}) [4th Preference]'],
]

end_time=row[f'End Time (Class {class_num} of {number_of_classes})']
)

teacher.add_classrooms(classroom)
self.applicants.append(classroom)


Expand Down
2 changes: 1 addition & 1 deletion vsvs_scheduler/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def main():
'',
classroom.start_time.strftime('%I:%M %p'),
classroom.end_time.strftime('%I:%M %p'),
classroom.weekday
classroom.teacher.weekday
]
)
csv_writer.writerow(['']*6)
Expand Down
75 changes: 58 additions & 17 deletions vsvs_scheduler/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,42 @@ def create_assignments(self):
num_days_to_try = 4

while num_days_to_try > 0 and self.incomplete_classrooms:
updated_teachers = []
for classroom in self.incomplete_classrooms:
classroom.unassign_volunteers()
classroom.change_to_next_preferred_day()
self.assign_volunteers()
if classroom.teacher not in updated_teachers:
classroom.change_to_next_preferred_day()
updated_teachers.append(classroom.teacher)
self.assign_volunteers()
num_days_to_try -= 1

num_days_to_try = 4
updated_teachers = []
for classroom in self.incomplete_classrooms:
if classroom.teacher not in updated_teachers:
classroom.teacher.reset_weekday()
updated_teachers.append(classroom.teacher)

while num_days_to_try > 0 and self.incomplete_classrooms:
updated_teachers = []
for classroom in self.incomplete_classrooms:
classroom.unassign_volunteers()
if classroom.teacher not in updated_teachers:
classroom.change_to_next_preferred_day()
updated_teachers.append(classroom.teacher)
self.assign_volunteers("second_to_last_round")
num_days_to_try -= 1

self.assign_volunteers("last_round")
for classroom in self.classrooms:
classroom.freeze_weekday()

if missing_team_leaders:
warnings.warn(f'WARNING: Classrooms are missing team leaders: {missing_team_leaders}')
if self.incomplete_classrooms:
warnings.warn(f'WARNING: Classrooms without necessary number of volunteers {self.incomplete_classrooms}')
return {"unassigned": self.unassigned_partners}



def assign_partners(self):
"""Assigns partners to classrooms and returns a list of unassigned partners."""

Expand Down Expand Up @@ -94,26 +114,47 @@ def assign_volunteers(self, volunteer_type: str = "default"):
idx = 0
while volunteer.group_number == -1 and idx < len(self.classrooms):
classroom = self.classrooms[idx]
if volunteer.can_make_class(classroom) and (len(classroom.volunteers) < self.max_size):
if volunteer.can_make_class_last_round(classroom) and (len(classroom.volunteers) < self.max_size):
classroom.assign_volunteer(volunteer)
volunteer.assign_classroom(classroom)
else:
idx += 1
elif volunteer_type == "second_to_last_round":
for volunteer in volunteer_list:
idx = 0
while volunteer.group_number == -1 and idx < len(self.incomplete_classrooms):
classroom = self.incomplete_classrooms[idx]
if volunteer.can_make_class(classroom) and (volunteer_type == "default" or not classroom.team_leader):
classroom.assign_volunteer(volunteer)
volunteer.assign_classroom(classroom)
if len(classroom.volunteers) >= self.min_size:
self.incomplete_classrooms.remove(classroom)
classroom.freeze_weekday()
else:
idx += 1
else:
for volunteer in volunteer_list:
idx = 0
while volunteer.group_number == -1 and idx < len(self.incomplete_classrooms):
classroom = self.incomplete_classrooms[idx]
if volunteer.can_make_class(classroom) and (volunteer_type == "default" or not classroom.team_leader):
classroom.assign_volunteer(volunteer)
volunteer.assign_classroom(classroom)
if len(classroom.volunteers) >= self.min_size:
self.incomplete_classrooms.remove(classroom)
else:
idx += 1
self.unassign_volunteers_for_incomplete_classes()


for volunteer in volunteer_list:
idx = 0
while volunteer.group_number == -1 and idx < len(self.incomplete_classrooms):
classroom = self.incomplete_classrooms[idx]
if volunteer.can_make_class(classroom) and (volunteer_type == "default" or not classroom.team_leader):
classroom.assign_volunteer(volunteer)
volunteer.assign_classroom(classroom)
if len(classroom.volunteers) >= self.min_size:
self.incomplete_classrooms.remove(classroom)
else:
idx += 1
self.incomplete_classrooms.sort(key=lambda classroom: len(classroom.volunteers), reverse=True)


def unassign_volunteers_for_incomplete_classes(self):
for classroom in self.incomplete_classrooms:
classroom.teacher.unassign_volunteers()
for room in classroom.teacher.classrooms:
if room not in self.incomplete_classrooms:
self.incomplete_classrooms.append(room)


def find_possible_classroom_and_partners_matches(self):
Expand Down

0 comments on commit b8ca269

Please sign in to comment.