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:
sabazadam
2025-12-19 21:21:46 +03:00
parent 8c7cb9e0fb
commit 96fc9408ec
6 changed files with 54 additions and 29 deletions

View File

@@ -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();
});

View File

@@ -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

View File

@@ -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
if (!allowBackToBack) {
// HARD CONSTRAINT: Max 2 exams per day per student
// This is ALWAYS enforced, regardless of allowBackToBack flag
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 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()) {
ValidationResult consecutiveResult = checkNoConsecutiveExams(
studentId, assignment, scheduleState);
result.merge(consecutiveResult);
// If consecutive violation, no need to check more students
if (!result.isValid()) {
break;
}

View File

@@ -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
);
}
}

View File

@@ -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 -->

View File

@@ -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>