Reputation: 169
This is my problem description:
Timeslot
from Monday - Friday, starting from 8:00am to 4:00pm. Each timeslot is 1 hourLesson
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 Timeslot
s 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)
Lesson
into 1 hour chunksLesson
"chunk" has a pointer to the next "chunk" (like a linked list)Timeslot
is null
, I'm assuming this happens because I'm using Timefold the wrong way.Joiners.overlapping
ConstraintProvider
implementation, I replaced Joiners.equal(Lesson::getTimeslot)
with Joiners.overlapping
but still got overlapping schedules and negative hard scoresConstraint 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