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() {
|
private void initializeSpinners() {
|
||||||
// Number of days spinner (1-30)
|
// 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);
|
numDaysSpinner.setValueFactory(daysFactory);
|
||||||
|
|
||||||
// Slots per day spinner (1-10)
|
// Slots per day spinner (1-10)
|
||||||
@@ -362,6 +362,10 @@ public class ScheduleCalendarController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateStatistics(ScheduleState schedule, long durationMs) {
|
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()));
|
scheduledCoursesLabel.setText(String.valueOf(schedule.getAssignedCourses()));
|
||||||
|
|
||||||
// Count unique classrooms used
|
// Count unique classrooms used
|
||||||
@@ -390,6 +394,12 @@ public class ScheduleCalendarController {
|
|||||||
int numDays = config.getNumDays();
|
int numDays = config.getNumDays();
|
||||||
int slotsPerDay = config.getSlotsPerDay();
|
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
|
// Column constraints - make columns wider for better visibility
|
||||||
ColumnConstraints headerCol = new ColumnConstraints();
|
ColumnConstraints headerCol = new ColumnConstraints();
|
||||||
headerCol.setMinWidth(100);
|
headerCol.setMinWidth(100);
|
||||||
@@ -398,9 +408,9 @@ public class ScheduleCalendarController {
|
|||||||
|
|
||||||
for (int day = 0; day < numDays; day++) {
|
for (int day = 0; day < numDays; day++) {
|
||||||
ColumnConstraints dayCol = new ColumnConstraints();
|
ColumnConstraints dayCol = new ColumnConstraints();
|
||||||
dayCol.setMinWidth(180);
|
dayCol.setMinWidth(135);
|
||||||
dayCol.setPrefWidth(220);
|
dayCol.setPrefWidth(150);
|
||||||
dayCol.setHgrow(Priority.ALWAYS);
|
dayCol.setHgrow(Priority.NEVER); // Prevent shrinking, allow horizontal scroll
|
||||||
scheduleGrid.getColumnConstraints().add(dayCol);
|
scheduleGrid.getColumnConstraints().add(dayCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,9 +541,10 @@ public class ScheduleCalendarController {
|
|||||||
examBox.setOnDragDone(e -> {
|
examBox.setOnDragDone(e -> {
|
||||||
draggedExam = null;
|
draggedExam = null;
|
||||||
examBox.setOpacity(1.0);
|
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) {
|
if (currentSchedule != null && currentConfig != null) {
|
||||||
displayScheduleGrid(currentSchedule, currentConfig);
|
Platform.runLater(() -> displayScheduleGrid(currentSchedule, currentConfig));
|
||||||
}
|
}
|
||||||
e.consume();
|
e.consume();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class ScheduleConfiguration {
|
|||||||
* Creates a default schedule configuration.
|
* Creates a default schedule configuration.
|
||||||
*/
|
*/
|
||||||
public ScheduleConfiguration() {
|
public ScheduleConfiguration() {
|
||||||
this.numDays = 5;
|
this.numDays = 8;
|
||||||
this.slotsPerDay = 4;
|
this.slotsPerDay = 4;
|
||||||
this.startDate = LocalDate.now().plusDays(7); // Default: start in a week
|
this.startDate = LocalDate.now().plusDays(7); // Default: start in a week
|
||||||
this.slotDurationMinutes = 120; // 2 hours
|
this.slotDurationMinutes = 120; // 2 hours
|
||||||
|
|||||||
@@ -63,28 +63,36 @@ public class ConstraintValidator {
|
|||||||
ValidationResult doubleBookingResult = checkNoDoubleBooking(assignment, scheduleState);
|
ValidationResult doubleBookingResult = checkNoDoubleBooking(assignment, scheduleState);
|
||||||
result.merge(doubleBookingResult);
|
result.merge(doubleBookingResult);
|
||||||
|
|
||||||
// Check student constraints - only check same time slot conflicts (always
|
// Check student constraints
|
||||||
// required)
|
|
||||||
Course course = dataManager.getCourse(assignment.getCourseCode());
|
Course course = dataManager.getCourse(assignment.getCourseCode());
|
||||||
if (course != null) {
|
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);
|
ValidationResult sameTimeResult = checkNoSameTimeExams(assignment, scheduleState, course);
|
||||||
result.merge(sameTimeResult);
|
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) {
|
if (!allowBackToBack) {
|
||||||
for (String studentId : course.getEnrolledStudents()) {
|
for (String studentId : course.getEnrolledStudents()) {
|
||||||
// Check no consecutive exams (soft - skip if allowBackToBack)
|
|
||||||
ValidationResult consecutiveResult = checkNoConsecutiveExams(
|
ValidationResult consecutiveResult = checkNoConsecutiveExams(
|
||||||
studentId, assignment, scheduleState);
|
studentId, assignment, scheduleState);
|
||||||
result.merge(consecutiveResult);
|
result.merge(consecutiveResult);
|
||||||
|
|
||||||
// Check max 2 exams per day
|
// If consecutive violation, no need to check more students
|
||||||
ValidationResult maxPerDayResult = checkMaxTwoExamsPerDay(
|
|
||||||
studentId, assignment, scheduleState);
|
|
||||||
result.merge(maxPerDayResult);
|
|
||||||
|
|
||||||
// If already invalid, no need to check more students
|
|
||||||
if (!result.isValid()) {
|
if (!result.isValid()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,10 +170,13 @@ public class ScheduleGeneratorService {
|
|||||||
|
|
||||||
// Try each classroom
|
// Try each classroom
|
||||||
for (Classroom classroom : suitableClassrooms) {
|
for (Classroom classroom : suitableClassrooms) {
|
||||||
// Temporarily assign
|
// Temporarily assign (using updateAssignment to maintain assignedCourses counter)
|
||||||
assignment.setDay(timeSlot.day);
|
scheduleState.updateAssignment(
|
||||||
assignment.setTimeSlotIndex(timeSlot.slot);
|
assignment.getCourseCode(),
|
||||||
assignment.setClassroomId(classroom.getClassroomId());
|
timeSlot.day,
|
||||||
|
timeSlot.slot,
|
||||||
|
classroom.getClassroomId()
|
||||||
|
);
|
||||||
|
|
||||||
// Validate assignment - pass allowBackToBack from config
|
// Validate assignment - pass allowBackToBack from config
|
||||||
ConstraintValidator.ValidationResult validationResult = validator.validateAssignment(assignment,
|
ConstraintValidator.ValidationResult validationResult = validator.validateAssignment(assignment,
|
||||||
@@ -186,10 +189,13 @@ public class ScheduleGeneratorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backtrack: reset assignment
|
// Backtrack: reset assignment (using updateAssignment to maintain assignedCourses counter)
|
||||||
assignment.setDay(-1);
|
scheduleState.updateAssignment(
|
||||||
assignment.setTimeSlotIndex(-1);
|
assignment.getCourseCode(),
|
||||||
assignment.setClassroomId(null);
|
-1,
|
||||||
|
-1,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,9 +101,9 @@
|
|||||||
<VBox spacing="12" VBox.vgrow="ALWAYS" styleClass="card">
|
<VBox spacing="12" VBox.vgrow="ALWAYS" styleClass="card">
|
||||||
<Label text="Import Messages" styleClass="subsection-title"/>
|
<Label text="Import Messages" styleClass="subsection-title"/>
|
||||||
<TextArea fx:id="messagesArea" editable="false" wrapText="true" VBox.vgrow="ALWAYS"
|
<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..."
|
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>
|
</VBox>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
<!-- Summary -->
|
<!-- Summary -->
|
||||||
<HBox spacing="12" alignment="CENTER_LEFT" styleClass="summary-row">
|
<HBox spacing="12" alignment="CENTER_LEFT" styleClass="summary-row">
|
||||||
<Label text="📊 Total Time Slots:" style="-fx-font-weight: 700;"/>
|
<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"/>
|
styleClass="summary-value"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|||||||
Reference in New Issue
Block a user