2023-11-21 14:09:04 +01:00
|
|
|
package com.baeldung.timefoldsolver;
|
|
|
|
|
|
2023-11-24 21:40:29 +01:00
|
|
|
import static ai.timefold.solver.core.api.score.stream.Joiners.equal;
|
|
|
|
|
|
2023-11-21 14:09:04 +01:00
|
|
|
import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
|
|
|
|
|
import ai.timefold.solver.core.api.score.stream.Constraint;
|
|
|
|
|
import ai.timefold.solver.core.api.score.stream.ConstraintFactory;
|
|
|
|
|
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;
|
|
|
|
|
|
|
|
|
|
public class ShiftScheduleConstraintProvider implements ConstraintProvider {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
|
2023-11-24 21:40:29 +01:00
|
|
|
return new Constraint[] { atMostOneShiftPerDay(constraintFactory), requiredSkill(constraintFactory) };
|
2023-11-21 14:09:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Constraint atMostOneShiftPerDay(ConstraintFactory constraintFactory) {
|
|
|
|
|
return constraintFactory.forEach(Shift.class)
|
2023-11-24 21:40:29 +01:00
|
|
|
.join(Shift.class, equal(shift -> shift.getStart()
|
|
|
|
|
.toLocalDate()), equal(Shift::getEmployee))
|
|
|
|
|
.filter((shift1, shift2) -> shift1 != shift2)
|
|
|
|
|
.penalize(HardSoftScore.ONE_HARD)
|
|
|
|
|
.asConstraint("At most one shift per day");
|
2023-11-21 14:09:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Constraint requiredSkill(ConstraintFactory constraintFactory) {
|
|
|
|
|
return constraintFactory.forEach(Shift.class)
|
2023-11-24 21:40:29 +01:00
|
|
|
.filter(shift -> !shift.getEmployee()
|
|
|
|
|
.getSkills()
|
|
|
|
|
.contains(shift.getRequiredSkill()))
|
|
|
|
|
.penalize(HardSoftScore.ONE_HARD)
|
|
|
|
|
.asConstraint("Required skill");
|
2023-11-21 14:09:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|