initial project
This commit is contained in:
63
controller/conflict_checker/student_conflict_checker.py
Normal file
63
controller/conflict_checker/student_conflict_checker.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""
|
||||
Verifies that no batch (and therefore no student in that batch) is booked
|
||||
into two courses — lecture or lab — at the same day+slot.
|
||||
|
||||
This is an independent verification pass over the scheduler's output: it
|
||||
does not trust the scheduler's own busy-maps, it re-derives every batch's
|
||||
occupied (day, slot_index) cells directly from the session list and flags
|
||||
any cell used by more than one session.
|
||||
"""
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def check_student_conflicts(sessions):
|
||||
"""
|
||||
Returns a list of conflict dicts, one per (batch, day, slot) where two
|
||||
or more sessions overlap for that batch:
|
||||
{
|
||||
"batch_code": str,
|
||||
"day": str,
|
||||
"slot_index": int,
|
||||
"sessions": [session, session, ...],
|
||||
}
|
||||
Sessions that span multiple slot_indices (labs) occupy every one of
|
||||
their slot_indices, so a lab overlapping a lecture in either of its two
|
||||
slots is caught too.
|
||||
"""
|
||||
# (batch_code, day, slot_index) -> list of sessions occupying that cell
|
||||
occupied = defaultdict(list)
|
||||
|
||||
for session in sessions:
|
||||
day = session["day"]
|
||||
for slot_index in session["slot_indices"]:
|
||||
for batch_code in session["batch_codes"]:
|
||||
occupied[(batch_code, day, slot_index)].append(session)
|
||||
|
||||
conflicts = []
|
||||
for (batch_code, day, slot_index), cell_sessions in occupied.items():
|
||||
if len(cell_sessions) > 1:
|
||||
conflicts.append({
|
||||
"batch_code": batch_code,
|
||||
"day": day,
|
||||
"slot_index": slot_index,
|
||||
"sessions": cell_sessions,
|
||||
})
|
||||
|
||||
conflicts.sort(key=lambda c: (c["batch_code"], c["day"], c["slot_index"]))
|
||||
return conflicts
|
||||
|
||||
|
||||
def format_student_conflicts(conflicts):
|
||||
"""Human-readable lines describing each student/batch conflict."""
|
||||
lines = []
|
||||
for c in conflicts:
|
||||
course_list = ", ".join(
|
||||
f'{s["course_id"]} ({s["course_type"]}) with {s["instructor_name"]} in {s["room_id"]}'
|
||||
for s in c["sessions"]
|
||||
)
|
||||
lines.append(
|
||||
f'Batch {c["batch_code"]} has {len(c["sessions"])} overlapping courses on '
|
||||
f'{c["day"]} slot {c["slot_index"]}: {course_list}'
|
||||
)
|
||||
return lines
|
||||
Reference in New Issue
Block a user