60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
"""
|
|
Verifies that no instructor is booked into two sessions at the same
|
|
day+slot (whether both are lectures, both labs, or a mix of either).
|
|
|
|
Like student_conflict_checker, this re-derives occupancy directly from the
|
|
session list rather than trusting the scheduler's internal busy-maps.
|
|
"""
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
def check_teacher_conflicts(sessions):
|
|
"""
|
|
Returns a list of conflict dicts, one per (instructor_code, day, slot)
|
|
where two or more sessions overlap for that instructor:
|
|
{
|
|
"instructor_code": str,
|
|
"day": str,
|
|
"slot_index": int,
|
|
"sessions": [session, session, ...],
|
|
}
|
|
"""
|
|
# (instructor_code, day, slot_index) -> list of sessions occupying that cell
|
|
occupied = defaultdict(list)
|
|
|
|
for session in sessions:
|
|
day = session["day"]
|
|
instructor_code = session["instructor_code"]
|
|
for slot_index in session["slot_indices"]:
|
|
occupied[(instructor_code, day, slot_index)].append(session)
|
|
|
|
conflicts = []
|
|
for (instructor_code, day, slot_index), cell_sessions in occupied.items():
|
|
if len(cell_sessions) > 1:
|
|
conflicts.append({
|
|
"instructor_code": instructor_code,
|
|
"day": day,
|
|
"slot_index": slot_index,
|
|
"sessions": cell_sessions,
|
|
})
|
|
|
|
conflicts.sort(key=lambda c: (c["instructor_code"], c["day"], c["slot_index"]))
|
|
return conflicts
|
|
|
|
|
|
def format_teacher_conflicts(conflicts):
|
|
"""Human-readable lines describing each teacher conflict."""
|
|
lines = []
|
|
for c in conflicts:
|
|
course_list = ", ".join(
|
|
f'{s["course_id"]} ({s["course_type"]}) for batch(es) {"+".join(s["batch_codes"])} in {s["room_id"]}'
|
|
for s in c["sessions"]
|
|
)
|
|
instructor_name = c["sessions"][0]["instructor_name"]
|
|
lines.append(
|
|
f'Instructor {instructor_name} ({c["instructor_code"]}) is double-booked on '
|
|
f'{c["day"]} slot {c["slot_index"]}: {course_list}'
|
|
)
|
|
return lines
|