aneesqumar commited on
Commit
640f1cf
·
verified ·
1 Parent(s): e8c04a4

Update timetable.py

Browse files
Files changed (1) hide show
  1. timetable.py +83 -59
timetable.py CHANGED
@@ -2,80 +2,104 @@ import pandas as pd
2
  import random
3
 
4
  DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
 
5
  TIME_SLOTS = ["9:00-10:00", "10:00-11:00", "11:00-12:30", "12:30-1:30", "1:30-3:00"]
 
 
6
 
7
- def split_course_hours(courses_df):
8
- """
9
- Split total weekly hours into chunks of max 1.5 hours per day.
10
- Returns a list of dicts with course, teacher, duration.
11
- """
 
 
 
 
 
 
 
 
 
 
12
  course_blocks = []
13
- for _, row in courses_df.iterrows():
14
- remaining = row['Hours']
15
- while remaining > 0:
16
- dur = 1.5 if remaining >= 1.5 else 1.0
17
  course_blocks.append({
18
  "Course": row['Course'],
19
  "Teacher": row['Teacher'],
20
  "Duration": dur
21
  })
22
- remaining -= dur
23
- return course_blocks
24
 
 
25
 
26
- def generate_timetable(courses_path, rooms_path):
27
- courses = pd.read_csv(courses_path)
28
- rooms = pd.read_csv(rooms_path)["Room"].tolist()
 
29
 
30
- course_blocks = split_course_hours(courses)
 
 
 
 
31
 
32
- # Initialize timetable dictionary: one list per day
33
- timetable = {day: [] for day in DAYS}
34
- teacher_last_slot = {t: None for t in courses['Teacher'].unique()}
35
 
36
- for day in DAYS:
37
- available_slots = TIME_SLOTS.copy()
38
- random.shuffle(course_blocks) # Randomize to reduce conflicts
39
- day_schedule = []
40
-
41
- i = 0
42
- while i < len(course_blocks) and available_slots:
43
- block = course_blocks[i]
44
- teacher = block['Teacher']
45
-
46
- # Check teacher consecutive slot
47
- if teacher_last_slot[teacher] == day and available_slots:
48
- i += 1
49
- continue
50
-
51
- slot = available_slots.pop(0)
52
- room = rooms[i % len(rooms)]
53
-
54
- day_schedule.append({
55
- "Time": slot,
56
- "Course": block['Course'],
57
- "Teacher": teacher,
58
- "Room": room
59
- })
60
 
61
- teacher_last_slot[teacher] = day
62
- # Remove block from list if allocated
63
- course_blocks.pop(i)
64
- timetable[day] = day_schedule
 
 
65
 
66
- # Convert timetable dict to printable DataFrame
67
- max_columns = max(len(v) for v in timetable.values())
68
- table_data = []
69
 
 
 
 
 
70
  for day in DAYS:
71
- row = [day]
72
- for cls in timetable[day]:
73
- row.append(f"{cls['Course']} ({cls['Teacher']})\n{cls['Time']}")
74
- # Fill remaining columns with empty
75
- while len(row) <= max_columns:
76
- row.append("")
77
- table_data.append(row)
78
-
79
- columns = ["Day"] + [f"Slot {i+1}" for i in range(max_columns)]
80
- df = pd.DataFrame(table_data, columns=columns)
81
  return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import random
3
 
4
  DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
5
+ # Time slots with duration in hours
6
  TIME_SLOTS = ["9:00-10:00", "10:00-11:00", "11:00-12:30", "12:30-1:30", "1:30-3:00"]
7
+ MAX_SLOT_DURATION = {"9:00-10:00": 1.0, "10:00-11:00":1.0, "11:00-12:30":1.5,
8
+ "12:30-1:30":1.0, "1:30-3:00":1.5}
9
 
10
+ def split_course_hours(hours):
11
+ """Split weekly hours into chunks <=1.5 per day"""
12
+ chunks = []
13
+ remaining = hours
14
+ while remaining > 0:
15
+ dur = 1.5 if remaining >= 1.5 else 1.0
16
+ chunks.append(dur)
17
+ remaining -= dur
18
+ return chunks
19
+
20
+ def generate_class_timetable(class_courses, rooms, teacher_schedule, room_schedule):
21
+ """Generate timetable for a single class"""
22
+ timetable = {day: [None]*len(TIME_SLOTS) for day in DAYS}
23
+
24
+ # Prepare course blocks
25
  course_blocks = []
26
+ for _, row in class_courses.iterrows():
27
+ chunks = split_course_hours(row['Hours'])
28
+ for dur in chunks:
 
29
  course_blocks.append({
30
  "Course": row['Course'],
31
  "Teacher": row['Teacher'],
32
  "Duration": dur
33
  })
 
 
34
 
35
+ random.shuffle(course_blocks)
36
 
37
+ for block in course_blocks:
38
+ allocated = False
39
+ random_days = DAYS.copy()
40
+ random.shuffle(random_days)
41
 
42
+ for day in random_days:
43
+ for idx, slot in enumerate(TIME_SLOTS):
44
+ slot_max = MAX_SLOT_DURATION[slot]
45
+ if timetable[day][idx] is None and block['Duration'] <= slot_max:
46
+ teacher = block['Teacher']
47
 
48
+ # Check teacher availability
49
+ if teacher_schedule.get((teacher, day, idx), False):
50
+ continue
51
 
52
+ # Check room availability
53
+ available_room = None
54
+ for room in rooms:
55
+ if not room_schedule.get((room, day, idx), False):
56
+ available_room = room
57
+ break
58
+ if not available_room:
59
+ continue
60
+
61
+ # Assign course
62
+ timetable[day][idx] = f"{block['Course']} ({teacher}) [{available_room}]"
63
+
64
+ # Mark teacher and room as busy
65
+ teacher_schedule[(teacher, day, idx)] = True
66
+ room_schedule[(available_room, day, idx)] = True
 
 
 
 
 
 
 
 
 
67
 
68
+ allocated = True
69
+ break
70
+ if allocated:
71
+ break
72
+ if not allocated:
73
+ print(f"⚠️ Could not allocate: {block['Course']} ({block['Teacher']})")
74
 
75
+ return timetable
 
 
76
 
77
+ def timetable_to_dataframe(timetable, class_name):
78
+ """Convert timetable dict to DataFrame"""
79
+ max_slots = len(TIME_SLOTS)
80
+ data = []
81
  for day in DAYS:
82
+ row = [day] + [timetable[day][i] if timetable[day][i] else "" for i in range(max_slots)]
83
+ data.append(row)
84
+
85
+ columns = ["Day"] + [f"Slot {i+1}" for i in range(max_slots)]
86
+ df = pd.DataFrame(data, columns=columns)
87
+ df.insert(0, "Class/Program", class_name)
 
 
 
 
88
  return df
89
+
90
+ def generate_full_timetable(courses_path, rooms_path):
91
+ courses_df = pd.read_csv(courses_path)
92
+ rooms_df = pd.read_csv(rooms_path)
93
+ rooms = rooms_df['Room'].tolist()
94
+
95
+ full_df = pd.DataFrame()
96
+ teacher_schedule = {} # Track teacher occupied slots across all classes
97
+ room_schedule = {} # Track room occupied slots across all classes
98
+
99
+ for class_name in courses_df['Class'].unique():
100
+ class_courses = courses_df[courses_df['Class']==class_name]
101
+ timetable = generate_class_timetable(class_courses, rooms, teacher_schedule, room_schedule)
102
+ df = timetable_to_dataframe(timetable, class_name)
103
+ full_df = pd.concat([full_df, df], ignore_index=True)
104
+
105
+ return full_df