more complex

This commit is contained in:
Talhadeveloperr
2026-09-09 18:29:08 +05:00
parent 0f1e3adbb1
commit 868bcbe175
266 changed files with 2825 additions and 137 deletions

View File

@@ -14,10 +14,10 @@ DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
HEADER_FILL = PatternFill(start_color="1F4E78", end_color="1F4E78", fill_type="solid")
HEADER_FONT = Font(color="FFFFFF", bold=True)
LUNCH_FILL = PatternFill(start_color="D9D9D9", end_color="D9D9D9", fill_type="solid")
GENERAL_FILL = PatternFill(start_color="FFF2CC", end_color="FFF2CC", fill_type="solid")
LAB_FILL = PatternFill(start_color="D9EAD3", end_color="D9EAD3", fill_type="solid")
THEORY_FILL = PatternFill(start_color="DDEBF7", end_color="DDEBF7", fill_type="solid")
LONG_LECTURE_FILL = PatternFill(start_color="F4CCCC", end_color="F4CCCC", fill_type="solid")
THIN_BORDER = Border(
left=Side(style="thin"), right=Side(style="thin"),
top=Side(style="thin"), bottom=Side(style="thin"),
@@ -28,6 +28,8 @@ CENTER = Alignment(horizontal="center", vertical="center", wrap_text=True)
def cell_fill_for(session):
if session is None:
return None
if session.get("duration_minutes") == 120:
return LONG_LECTURE_FILL
if session.get("is_general"):
return GENERAL_FILL
if session.get("course_type") == "lab":
@@ -35,16 +37,21 @@ def cell_fill_for(session):
return THEORY_FILL
def build_grid_sheet(ws, title, subtitle, time_slots, sessions_by_day_slot, cell_text_fn):
def build_grid_sheet(ws, title, subtitle, display_rows, sessions_by_cell, cell_text_fn):
"""
Renders one timetable grid onto worksheet `ws`.
time_slots: ordered list of dicts: {"label": str, "start": str, "end": str,
"is_lunch": bool}
sessions_by_day_slot: dict[(day, slot_index)] -> session dict (or list of
session dicts for slots spanning a double/lab period), used
only to decide fill color via cell_fill_for().
cell_text_fn: function(day, slot_index) -> str to render into the cell.
display_rows: ordered list of dicts, one per rendered row:
{"label": str, "start": str, "end": str,
"slot_index": int, "duration_minutes": int}
The special 08:30-10:30 long-lecture row and the normal
09:00-10:30 row both use slot_index 0 (they clash-track
against the same slot) but are distinguished by
duration_minutes (120 vs 90) so they render as separate rows.
sessions_by_cell: dict[(day, slot_index, duration_minutes)] -> session
dict, used only to decide fill color via cell_fill_for().
cell_text_fn: function(day, slot_index, duration_minutes) -> str to
render into the cell.
"""
invalid_chars = ':\\/?*[]'
sheet_name = "".join(c for c in title if c not in invalid_chars)
@@ -74,14 +81,12 @@ def build_grid_sheet(ws, title, subtitle, time_slots, sessions_by_day_slot, cell
c.alignment = CENTER
c.border = THIN_BORDER
for row_offset, slot in enumerate(time_slots):
for row_offset, slot in enumerate(display_rows):
row = header_row + 1 + row_offset
time_cell = ws.cell(row=row, column=1, value=f'{slot["start"]} - {slot["end"]}')
time_cell.font = Font(bold=True, size=9)
time_cell.alignment = CENTER
time_cell.border = THIN_BORDER
if slot.get("is_lunch"):
time_cell.fill = LUNCH_FILL
for col, day in enumerate(DAYS, start=2):
cell = ws.cell(row=row, column=col)
@@ -89,15 +94,10 @@ def build_grid_sheet(ws, title, subtitle, time_slots, sessions_by_day_slot, cell
cell.alignment = CENTER
cell.font = Font(size=9)
if slot.get("is_lunch"):
cell.fill = LUNCH_FILL
cell.value = "LUNCH BREAK"
continue
text = cell_text_fn(day, row_offset)
text = cell_text_fn(day, slot["slot_index"], slot["duration_minutes"])
cell.value = text if text else ""
session = sessions_by_day_slot.get((day, row_offset))
session = sessions_by_cell.get((day, slot["slot_index"], slot["duration_minutes"]))
fill = cell_fill_for(session)
if fill:
cell.fill = fill
@@ -106,7 +106,7 @@ def build_grid_sheet(ws, title, subtitle, time_slots, sessions_by_day_slot, cell
for col in range(2, 2 + len(DAYS)):
ws.column_dimensions[get_column_letter(col)].width = 26
for row_offset in range(len(time_slots)):
for row_offset in range(len(display_rows)):
ws.row_dimensions[header_row + 1 + row_offset].height = 42

View File

@@ -20,6 +20,12 @@ earlier phase, later phases can never reuse it.
sorted batch_code order: for each batch, every one of its remaining
offerings is placed and locked before the next batch is considered.
Time grid: 5 normal 90-minute slots, 09:00-16:30, no lunch break. Labs use
180-minute double-slots (09:00-12:00 and 12:00-15:00). A course whose
lecture_duration_minutes is 120 ("2 hours once a week") is instead placed
in a special fixed 08:30-10:30 slot, which overlaps normal slot 0
(09:00-10:30) in wall-clock time and is tracked as clashing with it.
Room selection always tries a course's preferred lecture_room_id /
lab_room_id first, falling back to another same-type room only if the
preferred one is busy for that day/slot.
@@ -32,24 +38,49 @@ DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__
DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Theory grid: 5 x 90-minute slots with a lunch break, 08:30-16:30
# Normal theory grid: 5 x 90-minute slots, 09:00-16:30, no lunch break.
# Every placeable session (normal lecture, lab, or the special long
# lecture) is expressed as one or more of these slot indices (0-4) for
# clash-tracking purposes — see LONG_LECTURE_SLOT below for why the long
# lecture also uses index 0 despite rendering at a different clock time.
TIME_SLOTS = [
{"label": "S1", "start": "08:30", "end": "10:00", "is_lunch": False},
{"label": "S2", "start": "10:00", "end": "11:30", "is_lunch": False},
{"label": "S3", "start": "11:30", "end": "13:00", "is_lunch": False},
{"label": "LUNCH", "start": "13:00", "end": "13:30", "is_lunch": True},
{"label": "S1", "start": "09:00", "end": "10:30", "is_lunch": False},
{"label": "S2", "start": "10:30", "end": "12:00", "is_lunch": False},
{"label": "S3", "start": "12:00", "end": "13:30", "is_lunch": False},
{"label": "S4", "start": "13:30", "end": "15:00", "is_lunch": False},
{"label": "S5", "start": "15:00", "end": "16:30", "is_lunch": False},
]
# Indices into TIME_SLOTS that are real teaching slots (skip lunch)
# Indices into TIME_SLOTS that are real teaching slots (no lunch to skip
# anymore, but kept for readability at call sites)
TEACHING_SLOT_INDICES = [i for i, s in enumerate(TIME_SLOTS) if not s["is_lunch"]]
# Consecutive pairs of teaching slots usable as a 180-minute lab double-slot
LAB_SLOT_PAIRS = [
(a, b)
for a, b in zip(TEACHING_SLOT_INDICES, TEACHING_SLOT_INDICES[1:])
if TIME_SLOTS[b]["start"] == TIME_SLOTS[a]["end"]
# Consecutive pairs of normal slots usable as a 180-minute lab double-slot:
# 09:00-12:00 (S1+S2) and 12:00-15:00 (S3+S4).
LAB_SLOT_PAIRS = [(0, 1), (2, 3)]
# The special fixed slot for courses whose lecture is "2 hours once a
# week": 08:30-10:30. This overlaps 09:00-10:30 (normal slot index 0) in
# wall-clock time, so a long-lecture session is tracked as occupying slot
# index 0 too (same key _is_free/_mark_busy use) — that's what makes it
# correctly clash with anything else placed in normal slot 0 that day for
# the same room/instructor/batch. duration_minutes on the session dict is
# what distinguishes it from a normal 90-minute slot-0 session at render time.
LONG_LECTURE_SLOT_INDEX = 0
LONG_LECTURE_START = "08:30"
LONG_LECTURE_END = "10:30"
# Rows to render on every generated timetable grid: the special long-lecture
# row first (it starts earliest, 08:30), then the 5 normal 90-minute rows.
# Templates/xlsx_grid_helper key session lookups on (day, slot_index,
# duration_minutes) using these rows' slot_index/duration_minutes pairs.
DISPLAY_ROWS = [
{"label": "Long", "start": LONG_LECTURE_START, "end": LONG_LECTURE_END,
"slot_index": LONG_LECTURE_SLOT_INDEX, "duration_minutes": 120},
] + [
{"label": s["label"], "start": s["start"], "end": s["end"],
"slot_index": i, "duration_minutes": 90}
for i, s in enumerate(TIME_SLOTS)
]
@@ -82,6 +113,7 @@ def load_data():
c["lectures_per_week"] = int(c["lectures_per_week"])
c["labs_per_week"] = int(c["labs_per_week"])
c["is_general"] = c["is_general"].lower() == "yes"
c["lecture_duration_minutes"] = int(c.get("lecture_duration_minutes") or 90)
courses_by_id[c["course_id"]] = c
# normalize offerings: expand "batch1|batch2" section batch groups into
@@ -183,16 +215,23 @@ class Scheduler:
rest = [r for r in room_pool if r["room_id"] != preferred_room_id]
return ([preferred] if preferred else []) + rest
def _add_session(self, offering, day, slot_indices, room):
def _add_session(self, offering, day, slot_indices, room, is_long_lecture=False):
course = offering["course"]
start = TIME_SLOTS[slot_indices[0]]["start"]
end = TIME_SLOTS[slot_indices[-1]]["end"]
session_type = "lab" if len(slot_indices) > 1 else "theory"
if is_long_lecture:
start, end = LONG_LECTURE_START, LONG_LECTURE_END
duration_minutes = 120
session_type = "theory"
else:
start = TIME_SLOTS[slot_indices[0]]["start"]
end = TIME_SLOTS[slot_indices[-1]]["end"]
duration_minutes = 90 * len(slot_indices)
session_type = "lab" if len(slot_indices) > 1 else "theory"
session = {
"day": day,
"slot_indices": slot_indices,
"start": start,
"end": end,
"duration_minutes": duration_minutes,
"course_id": offering["course_id"],
"course_name": course["course_name"],
"course_type": session_type,
@@ -208,7 +247,7 @@ class Scheduler:
return session
def _place_theory_session(self, offering, room_candidates, day_order):
"""Finds and locks a free single-slot session; returns the session dict or None."""
"""Finds and locks a free normal 90-minute single-slot session; returns the session dict or None."""
for day in day_order:
for slot_index in TEACHING_SLOT_INDICES:
for room in room_candidates:
@@ -217,6 +256,26 @@ class Scheduler:
return self._add_session(offering, day, [slot_index], room)
return None
def _place_long_lecture(self, offering, room_candidates, day_order):
"""
Finds and locks a free 08:30-10:30 long-lecture session (for
courses with lecture_duration_minutes=120). Occupies the same
clash-tracking slot index as normal slot 0 since they overlap in
wall-clock time (09:00-10:30). Returns the session dict or None.
"""
for day in day_order:
for room in room_candidates:
if self._is_free(day, LONG_LECTURE_SLOT_INDEX, room["room_id"], offering["instructor_code"], offering["batch_codes"]):
self._mark_busy(day, LONG_LECTURE_SLOT_INDEX, room["room_id"], offering["instructor_code"], offering["batch_codes"])
return self._add_session(offering, day, [LONG_LECTURE_SLOT_INDEX], room, is_long_lecture=True)
return None
def _place_lecture(self, offering, room_candidates, day_order):
"""Dispatches to the long (120-min) or normal (90-min) lecture placement based on the course's lecture_duration_minutes."""
if offering["course"]["lecture_duration_minutes"] == 120:
return self._place_long_lecture(offering, room_candidates, day_order)
return self._place_theory_session(offering, room_candidates, day_order)
def phase_1_general_courses(self, preferred_days=("Tuesday", "Thursday"), max_repair_attempts=20):
"""
Places every general-course offering's weekly lectures, preferring
@@ -233,7 +292,7 @@ class Scheduler:
course = offering["course"]
room_candidates = self._room_candidates(course["lecture_room_id"], self.classrooms)
for _ in range(course["lectures_per_week"]):
session = self._place_theory_session(offering, room_candidates, preferred_order)
session = self._place_lecture(offering, room_candidates, preferred_order)
if session is None:
print(f"WARNING: could not place a lecture for general course {offering['course_id']} section {offering['section_id']}")
@@ -266,7 +325,7 @@ class Scheduler:
phase_sessions.remove(losing_session)
room_candidates = self._room_candidates(offering["course"]["lecture_room_id"], self.classrooms)
new_session = self._place_theory_session(offering, room_candidates, any_day_order)
new_session = self._place_lecture(offering, room_candidates, any_day_order)
if new_session is None:
print(f"WARNING: could not repair general-course conflict for {offering['course_id']} section {offering['section_id']}")
return
@@ -326,7 +385,7 @@ class Scheduler:
course = offering["course"]
room_candidates = self._room_candidates(course["lecture_room_id"], self.classrooms)
for _ in range(course["lectures_per_week"]):
session = self._place_theory_session(offering, room_candidates, DAYS)
session = self._place_lecture(offering, room_candidates, DAYS)
if session is None:
print(f"WARNING: could not place a lecture for course {offering['course_id']} section {offering['section_id']} ({offering['batch_codes']})")

View File

@@ -2,3 +2,6 @@ batch_code,department,program,session
25021519,CS,BSCS,25
25021520,CS,BSSE,25
25031519,EE,BSEE,25
25031520,EE,BSCE,25
25041519,BBA,BBA,25
25041520,BBA,BSAF,25
1 batch_code department program session
2 25021519 CS BSCS 25
3 25021520 CS BSSE 25
4 25031519 EE BSEE 25
5 25031520 EE BSCE 25
6 25041519 BBA BBA 25
7 25041520 BBA BSAF 25

View File

@@ -2,3 +2,6 @@ batch_code,department,program,session
26021519,CS,BSCS,26
26021520,CS,BSSE,26
26031519,EE,BSEE,26
26031520,EE,BSCE,26
26041519,BBA,BBA,26
26041520,BBA,BSAF,26
1 batch_code department program session
2 26021519 CS BSCS 26
3 26021520 CS BSSE 26
4 26031519 EE BSEE 26
5 26031520 EE BSCE 26
6 26041519 BBA BBA 26
7 26041520 BBA BSAF 26

View File

@@ -1,2 +1,3 @@
block_id,block_name
A,Block A
B,Block B
1 block_id block_name
2 A Block A
3 B Block B

View File

@@ -5,3 +5,6 @@ A-103,Room 103,A,classroom,50
A-201,Room 201,A,classroom,60
A-L01,Computer Lab 1,A,lab,35
A-L02,Computer Lab 2,A,lab,35
B-101,Room 101 (B),B,classroom,50
B-102,Room 102 (B),B,classroom,50
B-L01,Electronics Lab,B,lab,30
1 room_id room_name block_id room_type capacity
5 A-201 Room 201 A classroom 60
6 A-L01 Computer Lab 1 A lab 35
7 A-L02 Computer Lab 2 A lab 35
8 B-101 Room 101 (B) B classroom 50
9 B-102 Room 102 (B) B classroom 50
10 B-L01 Electronics Lab B lab 30

View File

@@ -1,15 +1,47 @@
course_id,section_id,batch_codes,instructor_code
CS101,A,25021519,1001
CS201,A,25021519,1002
CS301,A,25021519,1003
CS302,A,25021519,1001
CS101,B,25021520,1001
CS201,B,25021520,1002
CS301,B,25021520,1003
CS302,B,25021520,1001
EE101,A,25031519,1004
EE201,A,25031519,1005
EE301,A,25031519,1004
EE101,B,25031520,1004
EE201,B,25031520,1005
EE301,B,25031520,1004
BBA101,A,25041519,1007
BBA201,A,25041519,1008
BBA301,A,25041519,1007
BBA101,B,25041520,1007
BBA201,B,25041520,1008
BBA301,B,25041520,1007
CS101,C,26021519,1001
CS201,C,26021519,1002
CS301,C,26021519,1003
CS302,C,26021519,1001
CS101,D,26021520,1001
CS201,D,26021520,1002
EE101,B,26031519,1004
GEN101,A,25021519|25021520|25031519,1002
GEN102,A,25021519|25021520|25031519,1006
GEN101,B,26021519|26021520|26031519,1002
GEN102,B,26021519|26021520|26031519,1006
CS301,D,26021520,1003
CS302,D,26021520,1001
EE101,C,26031519,1004
EE201,C,26031519,1005
EE301,C,26031519,1004
EE101,D,26031520,1004
EE201,D,26031520,1005
EE301,D,26031520,1004
BBA101,C,26041519,1007
BBA201,C,26041519,1008
BBA301,C,26041519,1007
BBA101,D,26041520,1007
BBA201,D,26041520,1008
BBA301,D,26041520,1007
GEN101,ALL,25021519|25021520|25031519|25031520|25041519|25041520,1002
GEN102,ALL,25021519|25021520|25031519|25031520|25041519|25041520,1006
GEN103,ALL,25021519|25021520|25031519|25031520|25041519|25041520,1006
GEN101,ALL,26021519|26021520|26031519|26031520|26041519|26041520,1002
GEN102,ALL,26021519|26021520|26031519|26031520|26041519|26041520,1006
GEN103,ALL,26021519|26021520|26031519|26031520|26041519|26041520,1006
1 course_id section_id batch_codes instructor_code
2 CS101 A 25021519 1001
3 CS201 A 25021519 1002
4 CS301 A 25021519 1003
5 CS302 A 25021519 1001
6 CS101 B 25021520 1001
7 CS201 B 25021520 1002
8 CS301 B 25021520 1003
9 CS302 B 25021520 1001
10 EE101 A 25031519 1004
11 EE201 A 25031519 1005
12 EE301 A 25031519 1004
13 EE101 B 25031520 1004
14 EE201 B 25031520 1005
15 EE301 B 25031520 1004
16 BBA101 A 25041519 1007
17 BBA201 A 25041519 1008
18 BBA301 A 25041519 1007
19 BBA101 B 25041520 1007
20 BBA201 B 25041520 1008
21 BBA301 B 25041520 1007
22 CS101 C 26021519 1001
23 CS201 C 26021519 1002
24 CS301 C 26021519 1003
25 CS302 C 26021519 1001
26 CS101 D 26021520 1001
27 CS201 D 26021520 1002
28 EE101 CS301 B D 26031519 26021520 1004 1003
29 GEN101 CS302 A D 25021519|25021520|25031519 26021520 1002 1001
30 GEN102 EE101 A C 25021519|25021520|25031519 26031519 1006 1004
31 GEN101 EE201 B C 26021519|26021520|26031519 26031519 1002 1005
32 GEN102 EE301 B C 26021519|26021520|26031519 26031519 1006 1004
33 EE101 D 26031520 1004
34 EE201 D 26031520 1005
35 EE301 D 26031520 1004
36 BBA101 C 26041519 1007
37 BBA201 C 26041519 1008
38 BBA301 C 26041519 1007
39 BBA101 D 26041520 1007
40 BBA201 D 26041520 1008
41 BBA301 D 26041520 1007
42 GEN101 ALL 25021519|25021520|25031519|25031520|25041519|25041520 1002
43 GEN102 ALL 25021519|25021520|25031519|25031520|25041519|25041520 1006
44 GEN103 ALL 25021519|25021520|25031519|25031520|25041519|25041520 1006
45 GEN101 ALL 26021519|26021520|26031519|26031520|26041519|26041520 1002
46 GEN102 ALL 26021519|26021520|26031519|26031520|26041519|26041520 1006
47 GEN103 ALL 26021519|26021520|26031519|26031520|26041519|26041520 1006

View File

@@ -1,6 +1,14 @@
course_id,course_name,credit_hours,lectures_per_week,labs_per_week,is_general,lecture_room_id,lab_room_id
CS101,Programming Fundamentals,4,2,1,no,A-101,A-L01
CS201,Data Structures,4,2,1,no,A-102,A-L01
EE101,Basic Electronics,4,2,1,no,A-201,A-L02
GEN101,Functional English,3,2,0,yes,A-103,
GEN102,Islamic Studies,2,1,0,yes,A-103,
course_id,course_name,credit_hours,lectures_per_week,labs_per_week,is_general,lecture_room_id,lab_room_id,lecture_duration_minutes
CS101,Programming Fundamentals,4,2,1,no,A-101,A-L01,90
CS201,Data Structures,4,2,1,no,A-102,A-L01,90
CS301,Operating Systems,3,1,1,no,A-101,A-L02,120
CS302,Database Systems,4,2,2,no,A-102,A-L02,90
EE101,Basic Electronics,4,2,1,no,A-201,A-L02,90
EE201,Digital Logic Design,4,2,1,no,B-101,B-L01,90
EE301,Signals and Systems,3,1,0,no,B-102,,120
BBA101,Principles of Management,3,2,0,no,B-101,,90
BBA201,Financial Accounting,3,2,0,no,B-102,,90
BBA301,Marketing Management,3,1,0,no,A-103,,120
GEN101,Functional English,3,2,0,yes,A-103,,90
GEN102,Islamic Studies,2,1,0,yes,A-103,,90
GEN103,Pakistan Studies,2,1,0,yes,B-101,,120
1 course_id course_name credit_hours lectures_per_week labs_per_week is_general lecture_room_id lab_room_id lecture_duration_minutes
2 CS101 Programming Fundamentals 4 2 1 no A-101 A-L01 90
3 CS201 Data Structures 4 2 1 no A-102 A-L01 90
4 EE101 CS301 Basic Electronics Operating Systems 4 3 2 1 1 no A-201 A-101 A-L02 120
5 GEN101 CS302 Functional English Database Systems 3 4 2 0 2 yes no A-103 A-102 A-L02 90
6 GEN102 EE101 Islamic Studies Basic Electronics 2 4 1 2 0 1 yes no A-103 A-201 A-L02 90
7 EE201 Digital Logic Design 4 2 1 no B-101 B-L01 90
8 EE301 Signals and Systems 3 1 0 no B-102 120
9 BBA101 Principles of Management 3 2 0 no B-101 90
10 BBA201 Financial Accounting 3 2 0 no B-102 90
11 BBA301 Marketing Management 3 1 0 no A-103 120
12 GEN101 Functional English 3 2 0 yes A-103 90
13 GEN102 Islamic Studies 2 1 0 yes A-103 90
14 GEN103 Pakistan Studies 2 1 0 yes B-101 120

View File

@@ -1,6 +1,11 @@
"""
Generates small illustrative dummy CSV datasets under data/dummy/ so the
timetable template generator has something to schedule and render.
Generates a larger, deliberately harder dummy CSV dataset under data/dummy/
so the timetable template generator has something non-trivial to schedule
and render — more departments/batches/sections than the previous small
dataset, tighter room and instructor contention (fewer rooms/instructors
relative to demand), a second block, and mixed lecture durations (90 vs
120 minutes) so weaknesses in the scheduler surface as WARNINGs/conflicts
instead of everything trivially fitting.
Run once:
python data/dummy/generate_dummy_data.py
@@ -23,13 +28,18 @@ def write_csv(relative_path, header, rows):
def main():
# ---- blocks & rooms (Building/Block A only) ----
# ---- blocks: two blocks now, Block A (bigger) and Block B (smaller) ----
write_csv(
"blocks/blocks.csv",
["block_id", "block_name"],
[["A", "Block A"]],
[
["A", "Block A"],
["B", "Block B"],
],
)
# ---- rooms: deliberately tight relative to demand (see offerings
# below) so room contention is real, spread across both blocks ----
write_csv(
"blocks/rooms.csv",
["room_id", "room_name", "block_id", "room_type", "capacity"],
@@ -40,21 +50,32 @@ def main():
["A-201", "Room 201", "A", "classroom", 60],
["A-L01", "Computer Lab 1", "A", "lab", 35],
["A-L02", "Computer Lab 2", "A", "lab", 35],
["B-101", "Room 101 (B)", "B", "classroom", 50],
["B-102", "Room 102 (B)", "B", "classroom", 50],
["B-L01", "Electronics Lab", "B", "lab", 30],
],
)
# ---- departments / programs / batches ----
# batch_code = session(2) + program_id(6) e.g. 25021519
batches_25 = [
["25021519", "CS", "BSCS", "25"],
["25021520", "CS", "BSSE", "25"],
["25031519", "EE", "BSEE", "25"],
]
batches_26 = [
["26021519", "CS", "BSCS", "26"],
["26021520", "CS", "BSSE", "26"],
["26031519", "EE", "BSEE", "26"],
]
# ---- departments / programs / batches: 3 departments, 2 programs
# each, 2 sessions (25/26) -> 12 batches total (was 6) ----
department_programs = {
"CS": ["BSCS", "BSSE"],
"EE": ["BSEE", "BSCE"],
"BBA": ["BBA", "BSAF"],
}
program_codes = {
"BSCS": "021519", "BSSE": "021520",
"BSEE": "031519", "BSCE": "031520",
"BBA": "041519", "BSAF": "041520",
}
batches_25 = []
batches_26 = []
for department, programs in department_programs.items():
for program in programs:
code = program_codes[program]
batches_25.append([f"25{code}", department, program, "25"])
batches_26.append([f"26{code}", department, program, "26"])
write_csv(
"batch_codes/25/batches.csv",
@@ -70,62 +91,86 @@ def main():
all_batches = batches_25 + batches_26
# ---- courses ----
# One row per subject: lectures/labs per week are counted separately so
# a single course can carry both, and each course names its preferred
# lecture/lab room (the scheduler falls back to another same-type room
# only if the preferred one is busy).
# is_general courses are shared across every batch of the same session
# (so they can be scheduled together on Tuesday first, with no clash).
# course_id, course_name, credit_hours, lectures_per_week,
# labs_per_week, is_general, lecture_room_id, lab_room_id,
# lecture_duration_minutes
#
# Mixed lecture durations: most courses are 90-min x N/week, but a few
# are the special "2 hours once a week" case (lecture_duration_minutes
# 120, lectures_per_week 1). Labs vary 0/1/2 per week. Deliberately
# more courses per department than the room/instructor pool can
# comfortably absorb without contention.
courses = [
# course_id, course_name, credit_hours, lectures_per_week, labs_per_week, is_general, lecture_room_id, lab_room_id
["CS101", "Programming Fundamentals", 4, 2, 1, "no", "A-101", "A-L01"],
["CS201", "Data Structures", 4, 2, 1, "no", "A-102", "A-L01"],
["EE101", "Basic Electronics", 4, 2, 1, "no", "A-201", "A-L02"],
["GEN101", "Functional English", 3, 2, 0, "yes", "A-103", ""],
["GEN102", "Islamic Studies", 2, 1, 0, "yes", "A-103", ""],
# CS department courses
["CS101", "Programming Fundamentals", 4, 2, 1, "no", "A-101", "A-L01", 90],
["CS201", "Data Structures", 4, 2, 1, "no", "A-102", "A-L01", 90],
["CS301", "Operating Systems", 3, 1, 1, "no", "A-101", "A-L02", 120],
["CS302", "Database Systems", 4, 2, 2, "no", "A-102", "A-L02", 90],
# EE department courses
["EE101", "Basic Electronics", 4, 2, 1, "no", "A-201", "A-L02", 90],
["EE201", "Digital Logic Design", 4, 2, 1, "no", "B-101", "B-L01", 90],
["EE301", "Signals and Systems", 3, 1, 0, "no", "B-102", "", 120],
# BBA department courses
["BBA101", "Principles of Management", 3, 2, 0, "no", "B-101", "", 90],
["BBA201", "Financial Accounting", 3, 2, 0, "no", "B-102", "", 90],
["BBA301", "Marketing Management", 3, 1, 0, "no", "A-103", "", 120],
# General (shared) courses
["GEN101", "Functional English", 3, 2, 0, "yes", "A-103", "", 90],
["GEN102", "Islamic Studies", 2, 1, 0, "yes", "A-103", "", 90],
["GEN103", "Pakistan Studies", 2, 1, 0, "yes", "B-101", "", 120],
]
write_csv(
"courses/courses.csv",
[
"course_id", "course_name", "credit_hours", "lectures_per_week",
"labs_per_week", "is_general", "lecture_room_id", "lab_room_id",
"lecture_duration_minutes",
],
courses,
)
# ---- course offerings: course + section (a section groups the batches
# taking that section together) + who teaches it ----
# A course can have many sections; here each CS/EE batch of a session is
# its own section (Section A/B/...), while general courses have a single
# section "ALL" grouping every batch of that session.
offerings = []
dept_course = {"CS": ["CS101", "CS201"], "EE": ["EE101"]}
# ---- course offerings: course + section (batches in that section) +
# instructor ----
# Deliberately tight instructor pool reused across many sections/
# courses (some instructors will end up wanted in overlapping slots),
# forcing real contention in Phase 2/Phase 3.
dept_courses = {
"CS": ["CS101", "CS201", "CS301", "CS302"],
"EE": ["EE101", "EE201", "EE301"],
"BBA": ["BBA101", "BBA201", "BBA301"],
}
# Small pools relative to (department batches x courses) demand.
dept_instructors = {
"CS": ["1001", "1002", "1003", "1006"],
"CS": ["1001", "1002", "1003"],
"EE": ["1004", "1005"],
"BBA": ["1007", "1008"],
}
offerings = []
section_letters = ["A", "B", "C", "D"]
dept_section_counter = {"CS": 0, "EE": 0}
dept_section_counter = {"CS": 0, "EE": 0, "BBA": 0}
for batch_code, department, program, session in all_batches:
section_id = section_letters[dept_section_counter[department] % len(section_letters)]
dept_section_counter[department] += 1
for i, course_id in enumerate(dept_course[department]):
instr_pool = dept_instructors[department]
instr_pool = dept_instructors[department]
for i, course_id in enumerate(dept_courses[department]):
# Deliberately narrow instructor rotation (2-3 instructors
# covering 3-4 courses per department) so the same instructor
# teaches multiple courses/sections -> instructor contention.
instr = instr_pool[i % len(instr_pool)]
offerings.append([course_id, section_id, batch_code, instr])
# general courses: one offering per (course, session), section "ALL"
# grouping every batch code sharing that session, separated by "|"
# grouping every batch code sharing that session
for session, batch_group in (
("25", [b[0] for b in batches_25]),
("26", [b[0] for b in batches_26]),
):
offerings.append(["GEN101", "ALL", "|".join(batch_group), "1002"])
offerings.append(["GEN102", "ALL", "|".join(batch_group), "1006"])
offerings.append(["GEN103", "ALL", "|".join(batch_group), "1006"])
write_csv(
"courses/course_offering.csv",
@@ -143,6 +188,8 @@ def main():
"1004": "Dr. Farah Iqbal",
"1005": "Mr. Usman Ali",
"1006": "Ms. Hira Shah",
"1007": "Dr. Nadia Farooq",
"1008": "Mr. Kamran Sheikh",
}
instructors = []
for course_id, section_id, batch_codes, instr_code in offerings:
@@ -154,10 +201,10 @@ def main():
instructors,
)
# ---- students (roll_no = batch_code-seq) ----
# ---- students (roll_no = batch_code-seq): 18 per batch (was 5) ----
students = []
for batch_code, department, program, session in all_batches:
for seq in range(1, 6): # 5 sample students per batch
for seq in range(1, 19):
roll_no = f"{batch_code}-{seq:03d}"
students.append([roll_no, batch_code, f"Student {roll_no}"])

View File

@@ -1,15 +1,47 @@
instructor_code,instructor_name,course_id,section_id
1001,Dr. Ahsan Raza,CS101,A
1002,Ms. Sana Tariq,CS201,A
1003,Mr. Bilal Khan,CS301,A
1001,Dr. Ahsan Raza,CS302,A
1001,Dr. Ahsan Raza,CS101,B
1002,Ms. Sana Tariq,CS201,B
1003,Mr. Bilal Khan,CS301,B
1001,Dr. Ahsan Raza,CS302,B
1004,Dr. Farah Iqbal,EE101,A
1005,Mr. Usman Ali,EE201,A
1004,Dr. Farah Iqbal,EE301,A
1004,Dr. Farah Iqbal,EE101,B
1005,Mr. Usman Ali,EE201,B
1004,Dr. Farah Iqbal,EE301,B
1007,Dr. Nadia Farooq,BBA101,A
1008,Mr. Kamran Sheikh,BBA201,A
1007,Dr. Nadia Farooq,BBA301,A
1007,Dr. Nadia Farooq,BBA101,B
1008,Mr. Kamran Sheikh,BBA201,B
1007,Dr. Nadia Farooq,BBA301,B
1001,Dr. Ahsan Raza,CS101,C
1002,Ms. Sana Tariq,CS201,C
1003,Mr. Bilal Khan,CS301,C
1001,Dr. Ahsan Raza,CS302,C
1001,Dr. Ahsan Raza,CS101,D
1002,Ms. Sana Tariq,CS201,D
1004,Dr. Farah Iqbal,EE101,B
1003,Mr. Bilal Khan,CS301,D
1001,Dr. Ahsan Raza,CS302,D
1004,Dr. Farah Iqbal,EE101,C
1005,Mr. Usman Ali,EE201,C
1004,Dr. Farah Iqbal,EE301,C
1004,Dr. Farah Iqbal,EE101,D
1005,Mr. Usman Ali,EE201,D
1004,Dr. Farah Iqbal,EE301,D
1007,Dr. Nadia Farooq,BBA101,C
1008,Mr. Kamran Sheikh,BBA201,C
1007,Dr. Nadia Farooq,BBA301,C
1007,Dr. Nadia Farooq,BBA101,D
1008,Mr. Kamran Sheikh,BBA201,D
1007,Dr. Nadia Farooq,BBA301,D
1002,Ms. Sana Tariq,GEN101,ALL
1006,Ms. Hira Shah,GEN102,ALL
1006,Ms. Hira Shah,GEN103,ALL
1002,Ms. Sana Tariq,GEN101,ALL
1006,Ms. Hira Shah,GEN102,ALL
1006,Ms. Hira Shah,GEN103,ALL
1 instructor_code instructor_name course_id section_id
2 1001 Dr. Ahsan Raza CS101 A
3 1002 Ms. Sana Tariq CS201 A
4 1003 Mr. Bilal Khan CS301 A
5 1001 Dr. Ahsan Raza CS302 A
6 1001 Dr. Ahsan Raza CS101 B
7 1002 Ms. Sana Tariq CS201 B
8 1003 Mr. Bilal Khan CS301 B
9 1001 Dr. Ahsan Raza CS302 B
10 1004 Dr. Farah Iqbal EE101 A
11 1005 Mr. Usman Ali EE201 A
12 1004 Dr. Farah Iqbal EE301 A
13 1004 Dr. Farah Iqbal EE101 B
14 1005 Mr. Usman Ali EE201 B
15 1004 Dr. Farah Iqbal EE301 B
16 1007 Dr. Nadia Farooq BBA101 A
17 1008 Mr. Kamran Sheikh BBA201 A
18 1007 Dr. Nadia Farooq BBA301 A
19 1007 Dr. Nadia Farooq BBA101 B
20 1008 Mr. Kamran Sheikh BBA201 B
21 1007 Dr. Nadia Farooq BBA301 B
22 1001 Dr. Ahsan Raza CS101 C
23 1002 Ms. Sana Tariq CS201 C
24 1003 Mr. Bilal Khan CS301 C
25 1001 Dr. Ahsan Raza CS302 C
26 1001 Dr. Ahsan Raza CS101 D
27 1002 Ms. Sana Tariq CS201 D
28 1004 1003 Dr. Farah Iqbal Mr. Bilal Khan EE101 CS301 B D
29 1001 Dr. Ahsan Raza CS302 D
30 1004 Dr. Farah Iqbal EE101 C
31 1005 Mr. Usman Ali EE201 C
32 1004 Dr. Farah Iqbal EE301 C
33 1004 Dr. Farah Iqbal EE101 D
34 1005 Mr. Usman Ali EE201 D
35 1004 Dr. Farah Iqbal EE301 D
36 1007 Dr. Nadia Farooq BBA101 C
37 1008 Mr. Kamran Sheikh BBA201 C
38 1007 Dr. Nadia Farooq BBA301 C
39 1007 Dr. Nadia Farooq BBA101 D
40 1008 Mr. Kamran Sheikh BBA201 D
41 1007 Dr. Nadia Farooq BBA301 D
42 1002 Ms. Sana Tariq GEN101 ALL
43 1006 Ms. Hira Shah GEN102 ALL
44 1006 Ms. Hira Shah GEN103 ALL
45 1002 Ms. Sana Tariq GEN101 ALL
46 1006 Ms. Hira Shah GEN102 ALL
47 1006 Ms. Hira Shah GEN103 ALL

View File

@@ -4,28 +4,214 @@ roll_no,batch_code,student_name
25021519-003,25021519,Student 25021519-003
25021519-004,25021519,Student 25021519-004
25021519-005,25021519,Student 25021519-005
25021519-006,25021519,Student 25021519-006
25021519-007,25021519,Student 25021519-007
25021519-008,25021519,Student 25021519-008
25021519-009,25021519,Student 25021519-009
25021519-010,25021519,Student 25021519-010
25021519-011,25021519,Student 25021519-011
25021519-012,25021519,Student 25021519-012
25021519-013,25021519,Student 25021519-013
25021519-014,25021519,Student 25021519-014
25021519-015,25021519,Student 25021519-015
25021519-016,25021519,Student 25021519-016
25021519-017,25021519,Student 25021519-017
25021519-018,25021519,Student 25021519-018
25021520-001,25021520,Student 25021520-001
25021520-002,25021520,Student 25021520-002
25021520-003,25021520,Student 25021520-003
25021520-004,25021520,Student 25021520-004
25021520-005,25021520,Student 25021520-005
25021520-006,25021520,Student 25021520-006
25021520-007,25021520,Student 25021520-007
25021520-008,25021520,Student 25021520-008
25021520-009,25021520,Student 25021520-009
25021520-010,25021520,Student 25021520-010
25021520-011,25021520,Student 25021520-011
25021520-012,25021520,Student 25021520-012
25021520-013,25021520,Student 25021520-013
25021520-014,25021520,Student 25021520-014
25021520-015,25021520,Student 25021520-015
25021520-016,25021520,Student 25021520-016
25021520-017,25021520,Student 25021520-017
25021520-018,25021520,Student 25021520-018
25031519-001,25031519,Student 25031519-001
25031519-002,25031519,Student 25031519-002
25031519-003,25031519,Student 25031519-003
25031519-004,25031519,Student 25031519-004
25031519-005,25031519,Student 25031519-005
25031519-006,25031519,Student 25031519-006
25031519-007,25031519,Student 25031519-007
25031519-008,25031519,Student 25031519-008
25031519-009,25031519,Student 25031519-009
25031519-010,25031519,Student 25031519-010
25031519-011,25031519,Student 25031519-011
25031519-012,25031519,Student 25031519-012
25031519-013,25031519,Student 25031519-013
25031519-014,25031519,Student 25031519-014
25031519-015,25031519,Student 25031519-015
25031519-016,25031519,Student 25031519-016
25031519-017,25031519,Student 25031519-017
25031519-018,25031519,Student 25031519-018
25031520-001,25031520,Student 25031520-001
25031520-002,25031520,Student 25031520-002
25031520-003,25031520,Student 25031520-003
25031520-004,25031520,Student 25031520-004
25031520-005,25031520,Student 25031520-005
25031520-006,25031520,Student 25031520-006
25031520-007,25031520,Student 25031520-007
25031520-008,25031520,Student 25031520-008
25031520-009,25031520,Student 25031520-009
25031520-010,25031520,Student 25031520-010
25031520-011,25031520,Student 25031520-011
25031520-012,25031520,Student 25031520-012
25031520-013,25031520,Student 25031520-013
25031520-014,25031520,Student 25031520-014
25031520-015,25031520,Student 25031520-015
25031520-016,25031520,Student 25031520-016
25031520-017,25031520,Student 25031520-017
25031520-018,25031520,Student 25031520-018
25041519-001,25041519,Student 25041519-001
25041519-002,25041519,Student 25041519-002
25041519-003,25041519,Student 25041519-003
25041519-004,25041519,Student 25041519-004
25041519-005,25041519,Student 25041519-005
25041519-006,25041519,Student 25041519-006
25041519-007,25041519,Student 25041519-007
25041519-008,25041519,Student 25041519-008
25041519-009,25041519,Student 25041519-009
25041519-010,25041519,Student 25041519-010
25041519-011,25041519,Student 25041519-011
25041519-012,25041519,Student 25041519-012
25041519-013,25041519,Student 25041519-013
25041519-014,25041519,Student 25041519-014
25041519-015,25041519,Student 25041519-015
25041519-016,25041519,Student 25041519-016
25041519-017,25041519,Student 25041519-017
25041519-018,25041519,Student 25041519-018
25041520-001,25041520,Student 25041520-001
25041520-002,25041520,Student 25041520-002
25041520-003,25041520,Student 25041520-003
25041520-004,25041520,Student 25041520-004
25041520-005,25041520,Student 25041520-005
25041520-006,25041520,Student 25041520-006
25041520-007,25041520,Student 25041520-007
25041520-008,25041520,Student 25041520-008
25041520-009,25041520,Student 25041520-009
25041520-010,25041520,Student 25041520-010
25041520-011,25041520,Student 25041520-011
25041520-012,25041520,Student 25041520-012
25041520-013,25041520,Student 25041520-013
25041520-014,25041520,Student 25041520-014
25041520-015,25041520,Student 25041520-015
25041520-016,25041520,Student 25041520-016
25041520-017,25041520,Student 25041520-017
25041520-018,25041520,Student 25041520-018
26021519-001,26021519,Student 26021519-001
26021519-002,26021519,Student 26021519-002
26021519-003,26021519,Student 26021519-003
26021519-004,26021519,Student 26021519-004
26021519-005,26021519,Student 26021519-005
26021519-006,26021519,Student 26021519-006
26021519-007,26021519,Student 26021519-007
26021519-008,26021519,Student 26021519-008
26021519-009,26021519,Student 26021519-009
26021519-010,26021519,Student 26021519-010
26021519-011,26021519,Student 26021519-011
26021519-012,26021519,Student 26021519-012
26021519-013,26021519,Student 26021519-013
26021519-014,26021519,Student 26021519-014
26021519-015,26021519,Student 26021519-015
26021519-016,26021519,Student 26021519-016
26021519-017,26021519,Student 26021519-017
26021519-018,26021519,Student 26021519-018
26021520-001,26021520,Student 26021520-001
26021520-002,26021520,Student 26021520-002
26021520-003,26021520,Student 26021520-003
26021520-004,26021520,Student 26021520-004
26021520-005,26021520,Student 26021520-005
26021520-006,26021520,Student 26021520-006
26021520-007,26021520,Student 26021520-007
26021520-008,26021520,Student 26021520-008
26021520-009,26021520,Student 26021520-009
26021520-010,26021520,Student 26021520-010
26021520-011,26021520,Student 26021520-011
26021520-012,26021520,Student 26021520-012
26021520-013,26021520,Student 26021520-013
26021520-014,26021520,Student 26021520-014
26021520-015,26021520,Student 26021520-015
26021520-016,26021520,Student 26021520-016
26021520-017,26021520,Student 26021520-017
26021520-018,26021520,Student 26021520-018
26031519-001,26031519,Student 26031519-001
26031519-002,26031519,Student 26031519-002
26031519-003,26031519,Student 26031519-003
26031519-004,26031519,Student 26031519-004
26031519-005,26031519,Student 26031519-005
26031519-006,26031519,Student 26031519-006
26031519-007,26031519,Student 26031519-007
26031519-008,26031519,Student 26031519-008
26031519-009,26031519,Student 26031519-009
26031519-010,26031519,Student 26031519-010
26031519-011,26031519,Student 26031519-011
26031519-012,26031519,Student 26031519-012
26031519-013,26031519,Student 26031519-013
26031519-014,26031519,Student 26031519-014
26031519-015,26031519,Student 26031519-015
26031519-016,26031519,Student 26031519-016
26031519-017,26031519,Student 26031519-017
26031519-018,26031519,Student 26031519-018
26031520-001,26031520,Student 26031520-001
26031520-002,26031520,Student 26031520-002
26031520-003,26031520,Student 26031520-003
26031520-004,26031520,Student 26031520-004
26031520-005,26031520,Student 26031520-005
26031520-006,26031520,Student 26031520-006
26031520-007,26031520,Student 26031520-007
26031520-008,26031520,Student 26031520-008
26031520-009,26031520,Student 26031520-009
26031520-010,26031520,Student 26031520-010
26031520-011,26031520,Student 26031520-011
26031520-012,26031520,Student 26031520-012
26031520-013,26031520,Student 26031520-013
26031520-014,26031520,Student 26031520-014
26031520-015,26031520,Student 26031520-015
26031520-016,26031520,Student 26031520-016
26031520-017,26031520,Student 26031520-017
26031520-018,26031520,Student 26031520-018
26041519-001,26041519,Student 26041519-001
26041519-002,26041519,Student 26041519-002
26041519-003,26041519,Student 26041519-003
26041519-004,26041519,Student 26041519-004
26041519-005,26041519,Student 26041519-005
26041519-006,26041519,Student 26041519-006
26041519-007,26041519,Student 26041519-007
26041519-008,26041519,Student 26041519-008
26041519-009,26041519,Student 26041519-009
26041519-010,26041519,Student 26041519-010
26041519-011,26041519,Student 26041519-011
26041519-012,26041519,Student 26041519-012
26041519-013,26041519,Student 26041519-013
26041519-014,26041519,Student 26041519-014
26041519-015,26041519,Student 26041519-015
26041519-016,26041519,Student 26041519-016
26041519-017,26041519,Student 26041519-017
26041519-018,26041519,Student 26041519-018
26041520-001,26041520,Student 26041520-001
26041520-002,26041520,Student 26041520-002
26041520-003,26041520,Student 26041520-003
26041520-004,26041520,Student 26041520-004
26041520-005,26041520,Student 26041520-005
26041520-006,26041520,Student 26041520-006
26041520-007,26041520,Student 26041520-007
26041520-008,26041520,Student 26041520-008
26041520-009,26041520,Student 26041520-009
26041520-010,26041520,Student 26041520-010
26041520-011,26041520,Student 26041520-011
26041520-012,26041520,Student 26041520-012
26041520-013,26041520,Student 26041520-013
26041520-014,26041520,Student 26041520-014
26041520-015,26041520,Student 26041520-015
26041520-016,26041520,Student 26041520-016
26041520-017,26041520,Student 26041520-017
26041520-018,26041520,Student 26041520-018
1 roll_no batch_code student_name
4 25021519-003 25021519 Student 25021519-003
5 25021519-004 25021519 Student 25021519-004
6 25021519-005 25021519 Student 25021519-005
7 25021519-006 25021519 Student 25021519-006
8 25021519-007 25021519 Student 25021519-007
9 25021519-008 25021519 Student 25021519-008
10 25021519-009 25021519 Student 25021519-009
11 25021519-010 25021519 Student 25021519-010
12 25021519-011 25021519 Student 25021519-011
13 25021519-012 25021519 Student 25021519-012
14 25021519-013 25021519 Student 25021519-013
15 25021519-014 25021519 Student 25021519-014
16 25021519-015 25021519 Student 25021519-015
17 25021519-016 25021519 Student 25021519-016
18 25021519-017 25021519 Student 25021519-017
19 25021519-018 25021519 Student 25021519-018
20 25021520-001 25021520 Student 25021520-001
21 25021520-002 25021520 Student 25021520-002
22 25021520-003 25021520 Student 25021520-003
23 25021520-004 25021520 Student 25021520-004
24 25021520-005 25021520 Student 25021520-005
25 25021520-006 25021520 Student 25021520-006
26 25021520-007 25021520 Student 25021520-007
27 25021520-008 25021520 Student 25021520-008
28 25021520-009 25021520 Student 25021520-009
29 25021520-010 25021520 Student 25021520-010
30 25021520-011 25021520 Student 25021520-011
31 25021520-012 25021520 Student 25021520-012
32 25021520-013 25021520 Student 25021520-013
33 25021520-014 25021520 Student 25021520-014
34 25021520-015 25021520 Student 25021520-015
35 25021520-016 25021520 Student 25021520-016
36 25021520-017 25021520 Student 25021520-017
37 25021520-018 25021520 Student 25021520-018
38 25031519-001 25031519 Student 25031519-001
39 25031519-002 25031519 Student 25031519-002
40 25031519-003 25031519 Student 25031519-003
41 25031519-004 25031519 Student 25031519-004
42 25031519-005 25031519 Student 25031519-005
43 25031519-006 25031519 Student 25031519-006
44 25031519-007 25031519 Student 25031519-007
45 25031519-008 25031519 Student 25031519-008
46 25031519-009 25031519 Student 25031519-009
47 25031519-010 25031519 Student 25031519-010
48 25031519-011 25031519 Student 25031519-011
49 25031519-012 25031519 Student 25031519-012
50 25031519-013 25031519 Student 25031519-013
51 25031519-014 25031519 Student 25031519-014
52 25031519-015 25031519 Student 25031519-015
53 25031519-016 25031519 Student 25031519-016
54 25031519-017 25031519 Student 25031519-017
55 25031519-018 25031519 Student 25031519-018
56 25031520-001 25031520 Student 25031520-001
57 25031520-002 25031520 Student 25031520-002
58 25031520-003 25031520 Student 25031520-003
59 25031520-004 25031520 Student 25031520-004
60 25031520-005 25031520 Student 25031520-005
61 25031520-006 25031520 Student 25031520-006
62 25031520-007 25031520 Student 25031520-007
63 25031520-008 25031520 Student 25031520-008
64 25031520-009 25031520 Student 25031520-009
65 25031520-010 25031520 Student 25031520-010
66 25031520-011 25031520 Student 25031520-011
67 25031520-012 25031520 Student 25031520-012
68 25031520-013 25031520 Student 25031520-013
69 25031520-014 25031520 Student 25031520-014
70 25031520-015 25031520 Student 25031520-015
71 25031520-016 25031520 Student 25031520-016
72 25031520-017 25031520 Student 25031520-017
73 25031520-018 25031520 Student 25031520-018
74 25041519-001 25041519 Student 25041519-001
75 25041519-002 25041519 Student 25041519-002
76 25041519-003 25041519 Student 25041519-003
77 25041519-004 25041519 Student 25041519-004
78 25041519-005 25041519 Student 25041519-005
79 25041519-006 25041519 Student 25041519-006
80 25041519-007 25041519 Student 25041519-007
81 25041519-008 25041519 Student 25041519-008
82 25041519-009 25041519 Student 25041519-009
83 25041519-010 25041519 Student 25041519-010
84 25041519-011 25041519 Student 25041519-011
85 25041519-012 25041519 Student 25041519-012
86 25041519-013 25041519 Student 25041519-013
87 25041519-014 25041519 Student 25041519-014
88 25041519-015 25041519 Student 25041519-015
89 25041519-016 25041519 Student 25041519-016
90 25041519-017 25041519 Student 25041519-017
91 25041519-018 25041519 Student 25041519-018
92 25041520-001 25041520 Student 25041520-001
93 25041520-002 25041520 Student 25041520-002
94 25041520-003 25041520 Student 25041520-003
95 25041520-004 25041520 Student 25041520-004
96 25041520-005 25041520 Student 25041520-005
97 25041520-006 25041520 Student 25041520-006
98 25041520-007 25041520 Student 25041520-007
99 25041520-008 25041520 Student 25041520-008
100 25041520-009 25041520 Student 25041520-009
101 25041520-010 25041520 Student 25041520-010
102 25041520-011 25041520 Student 25041520-011
103 25041520-012 25041520 Student 25041520-012
104 25041520-013 25041520 Student 25041520-013
105 25041520-014 25041520 Student 25041520-014
106 25041520-015 25041520 Student 25041520-015
107 25041520-016 25041520 Student 25041520-016
108 25041520-017 25041520 Student 25041520-017
109 25041520-018 25041520 Student 25041520-018
110 26021519-001 26021519 Student 26021519-001
111 26021519-002 26021519 Student 26021519-002
112 26021519-003 26021519 Student 26021519-003
113 26021519-004 26021519 Student 26021519-004
114 26021519-005 26021519 Student 26021519-005
115 26021519-006 26021519 Student 26021519-006
116 26021519-007 26021519 Student 26021519-007
117 26021519-008 26021519 Student 26021519-008
118 26021519-009 26021519 Student 26021519-009
119 26021519-010 26021519 Student 26021519-010
120 26021519-011 26021519 Student 26021519-011
121 26021519-012 26021519 Student 26021519-012
122 26021519-013 26021519 Student 26021519-013
123 26021519-014 26021519 Student 26021519-014
124 26021519-015 26021519 Student 26021519-015
125 26021519-016 26021519 Student 26021519-016
126 26021519-017 26021519 Student 26021519-017
127 26021519-018 26021519 Student 26021519-018
128 26021520-001 26021520 Student 26021520-001
129 26021520-002 26021520 Student 26021520-002
130 26021520-003 26021520 Student 26021520-003
131 26021520-004 26021520 Student 26021520-004
132 26021520-005 26021520 Student 26021520-005
133 26021520-006 26021520 Student 26021520-006
134 26021520-007 26021520 Student 26021520-007
135 26021520-008 26021520 Student 26021520-008
136 26021520-009 26021520 Student 26021520-009
137 26021520-010 26021520 Student 26021520-010
138 26021520-011 26021520 Student 26021520-011
139 26021520-012 26021520 Student 26021520-012
140 26021520-013 26021520 Student 26021520-013
141 26021520-014 26021520 Student 26021520-014
142 26021520-015 26021520 Student 26021520-015
143 26021520-016 26021520 Student 26021520-016
144 26021520-017 26021520 Student 26021520-017
145 26021520-018 26021520 Student 26021520-018
146 26031519-001 26031519 Student 26031519-001
147 26031519-002 26031519 Student 26031519-002
148 26031519-003 26031519 Student 26031519-003
149 26031519-004 26031519 Student 26031519-004
150 26031519-005 26031519 Student 26031519-005
151 26031519-006 26031519 Student 26031519-006
152 26031519-007 26031519 Student 26031519-007
153 26031519-008 26031519 Student 26031519-008
154 26031519-009 26031519 Student 26031519-009
155 26031519-010 26031519 Student 26031519-010
156 26031519-011 26031519 Student 26031519-011
157 26031519-012 26031519 Student 26031519-012
158 26031519-013 26031519 Student 26031519-013
159 26031519-014 26031519 Student 26031519-014
160 26031519-015 26031519 Student 26031519-015
161 26031519-016 26031519 Student 26031519-016
162 26031519-017 26031519 Student 26031519-017
163 26031519-018 26031519 Student 26031519-018
164 26031520-001 26031520 Student 26031520-001
165 26031520-002 26031520 Student 26031520-002
166 26031520-003 26031520 Student 26031520-003
167 26031520-004 26031520 Student 26031520-004
168 26031520-005 26031520 Student 26031520-005
169 26031520-006 26031520 Student 26031520-006
170 26031520-007 26031520 Student 26031520-007
171 26031520-008 26031520 Student 26031520-008
172 26031520-009 26031520 Student 26031520-009
173 26031520-010 26031520 Student 26031520-010
174 26031520-011 26031520 Student 26031520-011
175 26031520-012 26031520 Student 26031520-012
176 26031520-013 26031520 Student 26031520-013
177 26031520-014 26031520 Student 26031520-014
178 26031520-015 26031520 Student 26031520-015
179 26031520-016 26031520 Student 26031520-016
180 26031520-017 26031520 Student 26031520-017
181 26031520-018 26031520 Student 26031520-018
182 26041519-001 26041519 Student 26041519-001
183 26041519-002 26041519 Student 26041519-002
184 26041519-003 26041519 Student 26041519-003
185 26041519-004 26041519 Student 26041519-004
186 26041519-005 26041519 Student 26041519-005
187 26041519-006 26041519 Student 26041519-006
188 26041519-007 26041519 Student 26041519-007
189 26041519-008 26041519 Student 26041519-008
190 26041519-009 26041519 Student 26041519-009
191 26041519-010 26041519 Student 26041519-010
192 26041519-011 26041519 Student 26041519-011
193 26041519-012 26041519 Student 26041519-012
194 26041519-013 26041519 Student 26041519-013
195 26041519-014 26041519 Student 26041519-014
196 26041519-015 26041519 Student 26041519-015
197 26041519-016 26041519 Student 26041519-016
198 26041519-017 26041519 Student 26041519-017
199 26041519-018 26041519 Student 26041519-018
200 26041520-001 26041520 Student 26041520-001
201 26041520-002 26041520 Student 26041520-002
202 26041520-003 26041520 Student 26041520-003
203 26041520-004 26041520 Student 26041520-004
204 26041520-005 26041520 Student 26041520-005
205 26041520-006 26041520 Student 26041520-006
206 26041520-007 26041520 Student 26041520-007
207 26041520-008 26041520 Student 26041520-008
208 26041520-009 26041520 Student 26041520-009
209 26041520-010 26041520 Student 26041520-010
210 26041520-011 26041520 Student 26041520-011
211 26041520-012 26041520 Student 26041520-012
212 26041520-013 26041520 Student 26041520-013
213 26041520-014 26041520 Student 26041520-014
214 26041520-015 26041520 Student 26041520-015
215 26041520-016 26041520 Student 26041520-016
216 26041520-017 26041520 Student 26041520-017
217 26041520-018 26041520 Student 26041520-018

View File

@@ -1,3 +1,12 @@
Timetable generation log - started 2026-09-09T18:10:11.467126
Timetable generation log - started 2026-09-09T18:19:44.655145
================================================================================
[18:10:11] INFO: clear_all: schedule state, result templates, and log have been reset. Run phase_1 to start over.
[18:19:44] INFO: clear_all: schedule state, result templates, and log have been reset. Run phase_1 to start over.
[18:19:48] INFO: Phase 1/3: scheduling general courses (Tue/Thu preferred)...
[18:19:48] INFO: [Phase 1 (general courses)] No conflicts found — clash-free.
[18:19:48] INFO: phase_1 complete: 8 session(s) added this phase, 8 total so far. State saved to D:\projects\UORM\timetable\result\schedule_state.json.
[18:19:57] INFO: Phase 2/3: scheduling labs (on top of phase_1's fixed placements)...
[18:19:57] INFO: [Phase 2 (general courses + labs)] No conflicts found — clash-free.
[18:19:57] INFO: phase_2 complete: 23 session(s) added this phase, 31 total so far. State saved to D:\projects\UORM\timetable\result\schedule_state.json.
[18:20:05] INFO: Phase 3/3: scheduling remaining courses (batch by batch)...
[18:20:05] INFO: [Phase 3 (full schedule)] No conflicts found — clash-free.
[18:20:05] INFO: phase_3 complete: 51 session(s) added this phase, 82 total so far. State saved to D:\projects\UORM\timetable\result\schedule_state.json.

2305
result/schedule_state.json Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More