mirror of
https://github.com/sabazadam/Se302.git
synced 2025-12-31 12:21:22 +00:00
For ScheduleConfiguration.java:
feat(scheduling): add MINIMIZE_CLASSROOMS and BALANCE_CLASSROOMS strategies Extended optimization strategies to include classroom-focused options. Completes Task 1.5 enum requirements. For ScheduleGeneratorService.java: feat(scheduling): implement optimization strategy logic in CSP algorithm - MINIMIZE_DAYS: Pack exams into fewest days (fills early days first) - BALANCED_DISTRIBUTION: Spread exams evenly across all days (round-robin) - MINIMIZE_CLASSROOMS: Reuse same classrooms (prefer most-used rooms) - BALANCE_CLASSROOMS: Distribute across classrooms (prefer least-used rooms)
This commit is contained in:
@@ -28,14 +28,21 @@ public class ScheduleConfiguration {
|
|||||||
* Optimization strategies for the scheduling algorithm.
|
* Optimization strategies for the scheduling algorithm.
|
||||||
*/
|
*/
|
||||||
public enum OptimizationStrategy {
|
public enum OptimizationStrategy {
|
||||||
/** Minimize total number of days used */
|
/** Minimize total number of days used - pack exams into fewest days */
|
||||||
MINIMIZE_DAYS,
|
MINIMIZE_DAYS,
|
||||||
/** Spread exams evenly across days */
|
|
||||||
|
/** Spread exams evenly across days - balanced distribution */
|
||||||
BALANCED_DISTRIBUTION,
|
BALANCED_DISTRIBUTION,
|
||||||
/** Minimize consecutive exams for students */
|
|
||||||
|
/** Minimize number of classrooms used - reuse same classrooms */
|
||||||
|
MINIMIZE_CLASSROOMS,
|
||||||
|
|
||||||
|
/** Balance classroom usage across days - even distribution */
|
||||||
|
BALANCE_CLASSROOMS,
|
||||||
|
|
||||||
|
/** Minimize consecutive exams for students (bonus strategy) */
|
||||||
STUDENT_FRIENDLY,
|
STUDENT_FRIENDLY,
|
||||||
/** Maximize classroom utilization */
|
|
||||||
MAXIMIZE_ROOM_USAGE,
|
|
||||||
/** Default balanced approach */
|
/** Default balanced approach */
|
||||||
DEFAULT
|
DEFAULT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,40 +102,41 @@ public class ScheduleGeneratorService {
|
|||||||
|
|
||||||
ExamAssignment assignment = scheduleState.getAssignment(currentCourse.getCourseCode());
|
ExamAssignment assignment = scheduleState.getAssignment(currentCourse.getCourseCode());
|
||||||
|
|
||||||
// Try each day and time slot
|
// Get time slots ordered by strategy
|
||||||
for (int day = 0; day < config.getNumDays(); day++) {
|
List<DaySlotPair> orderedTimeSlots = getTimeSlotsOrderedByStrategy(config, scheduleState);
|
||||||
for (int slot = 0; slot < config.getSlotsPerDay(); slot++) {
|
|
||||||
if (cancelled.get()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get suitable classrooms for this day/slot
|
// Try each time slot
|
||||||
List<Classroom> suitableClassrooms = getSuitableClassrooms(
|
for (DaySlotPair timeSlot : orderedTimeSlots) {
|
||||||
currentCourse, day, slot, scheduleState);
|
if (cancelled.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Try each classroom
|
// Get suitable classrooms for this day/slot (ordered by strategy)
|
||||||
for (Classroom classroom : suitableClassrooms) {
|
List<Classroom> suitableClassrooms = getSuitableClassroomsOrdered(
|
||||||
// Temporarily assign
|
currentCourse, timeSlot.day, timeSlot.slot, scheduleState, config);
|
||||||
assignment.setDay(day);
|
|
||||||
assignment.setTimeSlotIndex(slot);
|
|
||||||
assignment.setClassroomId(classroom.getClassroomId());
|
|
||||||
|
|
||||||
// Validate assignment
|
// Try each classroom
|
||||||
ConstraintValidator.ValidationResult validationResult =
|
for (Classroom classroom : suitableClassrooms) {
|
||||||
validator.validateAssignment(assignment, scheduleState);
|
// Temporarily assign
|
||||||
|
assignment.setDay(timeSlot.day);
|
||||||
|
assignment.setTimeSlotIndex(timeSlot.slot);
|
||||||
|
assignment.setClassroomId(classroom.getClassroomId());
|
||||||
|
|
||||||
if (validationResult.isValid()) {
|
// Validate assignment
|
||||||
// Assignment is valid, try to assign remaining courses
|
ConstraintValidator.ValidationResult validationResult =
|
||||||
if (backtrack(scheduleState, courses, courseIndex + 1, config)) {
|
validator.validateAssignment(assignment, scheduleState);
|
||||||
return true; // Success!
|
|
||||||
}
|
if (validationResult.isValid()) {
|
||||||
|
// Assignment is valid, try to assign remaining courses
|
||||||
|
if (backtrack(scheduleState, courses, courseIndex + 1, config)) {
|
||||||
|
return true; // Success!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backtrack: reset assignment
|
|
||||||
assignment.setDay(-1);
|
|
||||||
assignment.setTimeSlotIndex(-1);
|
|
||||||
assignment.setClassroomId(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backtrack: reset assignment
|
||||||
|
assignment.setDay(-1);
|
||||||
|
assignment.setTimeSlotIndex(-1);
|
||||||
|
assignment.setClassroomId(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +161,53 @@ public class ScheduleGeneratorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get classrooms suitable for a course at a specific day and time slot.
|
* Get time slots ordered by optimization strategy.
|
||||||
*/
|
*/
|
||||||
private List<Classroom> getSuitableClassrooms(Course course,
|
private List<DaySlotPair> getTimeSlotsOrderedByStrategy(ScheduleConfiguration config, ScheduleState scheduleState) {
|
||||||
int day,
|
List<DaySlotPair> timeSlots = new ArrayList<>();
|
||||||
int timeSlotIndex,
|
|
||||||
ScheduleState scheduleState) {
|
// Generate all day/slot combinations
|
||||||
|
for (int day = 0; day < config.getNumDays(); day++) {
|
||||||
|
for (int slot = 0; slot < config.getSlotsPerDay(); slot++) {
|
||||||
|
timeSlots.add(new DaySlotPair(day, slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order based on strategy
|
||||||
|
switch (config.getOptimizationStrategy()) {
|
||||||
|
case MINIMIZE_DAYS:
|
||||||
|
// Already in order (day 0 slot 0, day 0 slot 1, ... day 1 slot 0, ...)
|
||||||
|
// This fills earlier days first
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BALANCED_DISTRIBUTION:
|
||||||
|
// Round-robin across days: day 0 slot 0, day 1 slot 0, day 2 slot 0, ... day 0 slot 1, ...
|
||||||
|
timeSlots.sort(Comparator.comparingInt((DaySlotPair p) -> p.slot)
|
||||||
|
.thenComparingInt(p -> p.day));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STUDENT_FRIENDLY:
|
||||||
|
// Try to space out exams - prefer later slots on same day to avoid consecutive
|
||||||
|
// (This is a simple heuristic - more sophisticated would track student conflicts)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// DEFAULT or others: chronological order
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get classrooms suitable for a course at a specific day and time slot,
|
||||||
|
* ordered according to optimization strategy.
|
||||||
|
*/
|
||||||
|
private List<Classroom> getSuitableClassroomsOrdered(Course course,
|
||||||
|
int day,
|
||||||
|
int timeSlotIndex,
|
||||||
|
ScheduleState scheduleState,
|
||||||
|
ScheduleConfiguration config) {
|
||||||
List<Classroom> suitable = new ArrayList<>();
|
List<Classroom> suitable = new ArrayList<>();
|
||||||
|
|
||||||
for (Classroom classroom : scheduleState.getAvailableClassrooms()) {
|
for (Classroom classroom : scheduleState.getAvailableClassrooms()) {
|
||||||
@@ -191,12 +233,63 @@ public class ScheduleGeneratorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by capacity (prefer smaller classrooms that fit)
|
// Order based on strategy
|
||||||
suitable.sort(Comparator.comparingInt(Classroom::getCapacity));
|
switch (config.getOptimizationStrategy()) {
|
||||||
|
case MINIMIZE_CLASSROOMS:
|
||||||
|
// Prefer classrooms that are already in use (reuse same classrooms)
|
||||||
|
suitable.sort((c1, c2) -> {
|
||||||
|
int usage1 = getClassroomUsageCount(c1.getClassroomId(), scheduleState);
|
||||||
|
int usage2 = getClassroomUsageCount(c2.getClassroomId(), scheduleState);
|
||||||
|
// Sort descending (most used first)
|
||||||
|
return Integer.compare(usage2, usage1);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BALANCE_CLASSROOMS:
|
||||||
|
// Prefer classrooms that are least used
|
||||||
|
suitable.sort((c1, c2) -> {
|
||||||
|
int usage1 = getClassroomUsageCount(c1.getClassroomId(), scheduleState);
|
||||||
|
int usage2 = getClassroomUsageCount(c2.getClassroomId(), scheduleState);
|
||||||
|
// Sort ascending (least used first)
|
||||||
|
return Integer.compare(usage1, usage2);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// DEFAULT or others: prefer smaller classrooms that fit (efficient space usage)
|
||||||
|
suitable.sort(Comparator.comparingInt(Classroom::getCapacity));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return suitable;
|
return suitable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count how many times a classroom has been used in the current schedule.
|
||||||
|
*/
|
||||||
|
private int getClassroomUsageCount(String classroomId, ScheduleState scheduleState) {
|
||||||
|
int count = 0;
|
||||||
|
for (ExamAssignment assignment : scheduleState.getAssignments().values()) {
|
||||||
|
if (assignment.isAssigned() && assignment.getClassroomId().equals(classroomId)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to represent a day/slot pair.
|
||||||
|
*/
|
||||||
|
private static class DaySlotPair {
|
||||||
|
final int day;
|
||||||
|
final int slot;
|
||||||
|
|
||||||
|
DaySlotPair(int day, int slot) {
|
||||||
|
this.day = day;
|
||||||
|
this.slot = slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the current schedule generation.
|
* Cancel the current schedule generation.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user