Aiman Daniel
Aiman Daniel

Reputation: 169

Assigning Lessons longer than Timeslot duration in Timefold/Optaplanner

This is my problem description:

  1. There is a list of Timeslot from Monday - Friday, starting from 8:00am to 4:00pm. Each timeslot is 1 hour
  2. There is a list of Lesson that can be 1 hour or 2 hours long (in reality this can be anything, I'm trying to simplify the problem here)

What I'm trying to do is, for every Lesson with a duration longer than the Timeslot (1 hour), I need to assign consecutive Timeslots to the Lesson, or at least mark the other two as unusable.

What I want to achieve for example:

What I've Tried (was not successful)

  1. Split the 3 hour Lesson into 1 hour chunks
  1. Use Joiners.overlapping
Constraint roomConflict(ConstraintFactory constraintFactory) {
        // A room can accommodate at most one lesson at the same time.
        return constraintFactory
                // Select each pair of 2 different lessons ...
                .forEachUniquePair(Lesson.class,
                        Joiners.overlapping(
                                (a) -> a.getTimeslot().getStartTime(),
                                (a) -> a.getTimeslot().getEndTime(),
                                (b) -> b.getTimeslot().getStartTime(),
                                (b) -> b.getTimeslot().getEndTime()
                        ),
                        // originally, only check for "same timeslot" instead of overlapping time
                        //Joiners.equal(Lesson::getTimeslot),
                        // ... in the same room ...
                        Joiners.equal(Lesson::getRoom))
                // ... and penalize each pair with a hard weight.
                .penalize(HardSoftScore.ONE_HARD)
                .justifyWith((lesson1, lesson2, score) -> new RoomConflictJustification(lesson1.getRoom(), lesson1, lesson2))
                .asConstraint("Room conflict");
    }

My code (methods removed for brevity):

@PlanningSolution
public class Timetable {

    private String name;

    @ProblemFactCollectionProperty
    @ValueRangeProvider
    private List<Timeslot> timeslots;

    @ProblemFactCollectionProperty
    @ValueRangeProvider
    private List<Room> rooms;

    @PlanningEntityCollectionProperty
    private List<Lesson> lessons;

    @PlanningScore
    private HardSoftScore score;

    // Ignored by Timefold, used by the UI to display solve or stop solving button
    private SolverStatus solverStatus;
}
public class Timeslot {

    @PlanningId
    private String id;

    private DayOfWeek dayOfWeek;
    private LocalTime startTime;
    private Duration duration;
}
@Entity
public class Room {

    @PlanningId
    @GeneratedValue
    @Id
    private Long id;

    private String name;
}
@PlanningEntity
public class Lesson {

    @PlanningId
    private String id;

    private String subject;
    private String teacher;
    private String studentGroup;

    @JsonIdentityReference
    @PlanningVariable
    private Timeslot timeslot;

    @JsonIdentityReference
    @PlanningVariable
    private Room room;

    private String activity;
    private Duration duration = Duration.ofHours(1L);
}

Upvotes: 0

Views: 69

Answers (0)

Related Questions