mirror of
https://github.com/sabazadam/Se302.git
synced 2025-12-31 12:21:22 +00:00
Scheduling algorithm avoided students that have many lectures and leading a bug, its fixed. Also scheduling calendar had scrolling issue that fixed too (Commit error. now i sending the codes)
This commit is contained in:
@@ -121,7 +121,7 @@ public class ScheduleCalendarController {
|
||||
|
||||
private void initializeSpinners() {
|
||||
// Number of days spinner (1-30)
|
||||
SpinnerValueFactory<Integer> daysFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 30, 5);
|
||||
SpinnerValueFactory<Integer> daysFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 30, 8);
|
||||
numDaysSpinner.setValueFactory(daysFactory);
|
||||
|
||||
// Slots per day spinner (1-10)
|
||||
@@ -362,6 +362,10 @@ public class ScheduleCalendarController {
|
||||
}
|
||||
|
||||
private void updateStatistics(ScheduleState schedule, long durationMs) {
|
||||
// Update total courses (BUG FIX: this was missing!)
|
||||
totalCoursesLabel.setText(String.valueOf(schedule.getTotalCourses()));
|
||||
|
||||
// Update scheduled courses
|
||||
scheduledCoursesLabel.setText(String.valueOf(schedule.getAssignedCourses()));
|
||||
|
||||
// Count unique classrooms used
|
||||
@@ -390,6 +394,12 @@ public class ScheduleCalendarController {
|
||||
int numDays = config.getNumDays();
|
||||
int slotsPerDay = config.getSlotsPerDay();
|
||||
|
||||
// Dynamically set minimum grid width to fit all columns
|
||||
// Time column (120px) + each day column (200px) + padding
|
||||
double minGridWidth = 120 + (numDays * 200) + 40;
|
||||
scheduleGrid.setMinWidth(minGridWidth);
|
||||
scheduleGrid.setPrefWidth(minGridWidth);
|
||||
|
||||
// Column constraints - make columns wider for better visibility
|
||||
ColumnConstraints headerCol = new ColumnConstraints();
|
||||
headerCol.setMinWidth(100);
|
||||
@@ -398,9 +408,9 @@ public class ScheduleCalendarController {
|
||||
|
||||
for (int day = 0; day < numDays; day++) {
|
||||
ColumnConstraints dayCol = new ColumnConstraints();
|
||||
dayCol.setMinWidth(180);
|
||||
dayCol.setPrefWidth(220);
|
||||
dayCol.setHgrow(Priority.ALWAYS);
|
||||
dayCol.setMinWidth(135);
|
||||
dayCol.setPrefWidth(150);
|
||||
dayCol.setHgrow(Priority.NEVER); // Prevent shrinking, allow horizontal scroll
|
||||
scheduleGrid.getColumnConstraints().add(dayCol);
|
||||
}
|
||||
|
||||
@@ -531,9 +541,10 @@ public class ScheduleCalendarController {
|
||||
examBox.setOnDragDone(e -> {
|
||||
draggedExam = null;
|
||||
examBox.setOpacity(1.0);
|
||||
// Refresh grid to reset all cell colors
|
||||
// Defer grid refresh to after drag event completes to avoid crash
|
||||
// when modifying scene graph during active event processing
|
||||
if (currentSchedule != null && currentConfig != null) {
|
||||
displayScheduleGrid(currentSchedule, currentConfig);
|
||||
Platform.runLater(() -> displayScheduleGrid(currentSchedule, currentConfig));
|
||||
}
|
||||
e.consume();
|
||||
});
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ScheduleConfiguration {
|
||||
* Creates a default schedule configuration.
|
||||
*/
|
||||
public ScheduleConfiguration() {
|
||||
this.numDays = 5;
|
||||
this.numDays = 8;
|
||||
this.slotsPerDay = 4;
|
||||
this.startDate = LocalDate.now().plusDays(7); // Default: start in a week
|
||||
this.slotDurationMinutes = 120; // 2 hours
|
||||
|
||||
@@ -63,28 +63,36 @@ public class ConstraintValidator {
|
||||
ValidationResult doubleBookingResult = checkNoDoubleBooking(assignment, scheduleState);
|
||||
result.merge(doubleBookingResult);
|
||||
|
||||
// Check student constraints - only check same time slot conflicts (always
|
||||
// required)
|
||||
// Check student constraints
|
||||
Course course = dataManager.getCourse(assignment.getCourseCode());
|
||||
if (course != null) {
|
||||
// Check if student has another exam at the SAME time slot (hard constraint)
|
||||
// HARD CONSTRAINT: Check if student has another exam at the SAME time slot
|
||||
// This is ALWAYS required
|
||||
ValidationResult sameTimeResult = checkNoSameTimeExams(assignment, scheduleState, course);
|
||||
result.merge(sameTimeResult);
|
||||
|
||||
// Only check consecutive and max per day if back-to-back is NOT allowed
|
||||
// HARD CONSTRAINT: Max 2 exams per day per student
|
||||
// This is ALWAYS enforced, regardless of allowBackToBack flag
|
||||
for (String studentId : course.getEnrolledStudents()) {
|
||||
ValidationResult maxPerDayResult = checkMaxTwoExamsPerDay(
|
||||
studentId, assignment, scheduleState);
|
||||
result.merge(maxPerDayResult);
|
||||
|
||||
// If max per day violated, no need to check more students
|
||||
if (!result.isValid()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SOFT CONSTRAINT: No consecutive exams (back-to-back)
|
||||
// Only enforced when allowBackToBack = false
|
||||
if (!allowBackToBack) {
|
||||
for (String studentId : course.getEnrolledStudents()) {
|
||||
// Check no consecutive exams (soft - skip if allowBackToBack)
|
||||
ValidationResult consecutiveResult = checkNoConsecutiveExams(
|
||||
studentId, assignment, scheduleState);
|
||||
result.merge(consecutiveResult);
|
||||
|
||||
// Check max 2 exams per day
|
||||
ValidationResult maxPerDayResult = checkMaxTwoExamsPerDay(
|
||||
studentId, assignment, scheduleState);
|
||||
result.merge(maxPerDayResult);
|
||||
|
||||
// If already invalid, no need to check more students
|
||||
// If consecutive violation, no need to check more students
|
||||
if (!result.isValid()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -170,10 +170,13 @@ public class ScheduleGeneratorService {
|
||||
|
||||
// Try each classroom
|
||||
for (Classroom classroom : suitableClassrooms) {
|
||||
// Temporarily assign
|
||||
assignment.setDay(timeSlot.day);
|
||||
assignment.setTimeSlotIndex(timeSlot.slot);
|
||||
assignment.setClassroomId(classroom.getClassroomId());
|
||||
// Temporarily assign (using updateAssignment to maintain assignedCourses counter)
|
||||
scheduleState.updateAssignment(
|
||||
assignment.getCourseCode(),
|
||||
timeSlot.day,
|
||||
timeSlot.slot,
|
||||
classroom.getClassroomId()
|
||||
);
|
||||
|
||||
// Validate assignment - pass allowBackToBack from config
|
||||
ConstraintValidator.ValidationResult validationResult = validator.validateAssignment(assignment,
|
||||
@@ -186,10 +189,13 @@ public class ScheduleGeneratorService {
|
||||
}
|
||||
}
|
||||
|
||||
// Backtrack: reset assignment
|
||||
assignment.setDay(-1);
|
||||
assignment.setTimeSlotIndex(-1);
|
||||
assignment.setClassroomId(null);
|
||||
// Backtrack: reset assignment (using updateAssignment to maintain assignedCourses counter)
|
||||
scheduleState.updateAssignment(
|
||||
assignment.getCourseCode(),
|
||||
-1,
|
||||
-1,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,9 +101,9 @@
|
||||
<VBox spacing="12" VBox.vgrow="ALWAYS" styleClass="card">
|
||||
<Label text="Import Messages" styleClass="subsection-title"/>
|
||||
<TextArea fx:id="messagesArea" editable="false" wrapText="true" VBox.vgrow="ALWAYS"
|
||||
prefHeight="200"
|
||||
prefHeight="300" minHeight="250" maxHeight="500"
|
||||
promptText="Validation messages and import results will appear here..."
|
||||
style="-fx-font-family: 'Consolas', 'Monaco', monospace; -fx-font-size: 12px;"/>
|
||||
style="-fx-font-family: 'Consolas', 'Monaco', monospace; -fx-font-size: 13px; -fx-padding: 12px;"/>
|
||||
</VBox>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<!-- Summary -->
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" styleClass="summary-row">
|
||||
<Label text="📊 Total Time Slots:" style="-fx-font-weight: 700;"/>
|
||||
<Label fx:id="summaryLabel" text="5 days × 4 slots = 20 slots"
|
||||
<Label fx:id="summaryLabel" text="8 days × 4 slots = 32 slots"
|
||||
styleClass="summary-value"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
Reference in New Issue
Block a user