private fun minAndMaxShiftsPerMonth(factory: ConstraintFactory): Constraint { return factory .from(Employee::class.java) .join(ShiftAssignment::class.java, employeeEqualsShiftAssignment()) .groupBy({ left, _ -> left }, countBi()) .penalize("Minimum and Maximum number of assignments", HardMediumSoftScore.ONE_HARD) { employee, count -> val minShifts = employee.minShiftsInMonth val maxShifts = employee.maxShiftsInMonth when { count < minShifts -> minShifts - count count > maxShifts -> count - maxShifts else -> 0 } } }
private fun employeeEqualsShiftAssignment() = Joiners.equal<Employee, ShiftAssignment?, String>(Employee::code) { it.employee?.code } private fun minAndMaxShiftsPerMonth(factory: ConstraintFactory): Constraint { return factory .from(Employee::class.java) .join(ShiftAssignment::class.java) .groupBy({ employee, _ -> employee }, countIfBi { employee, shiftAssignment -> employee == shiftAssignment.employee }) .penalize("Minimum and Maximum number of assignments", HardMediumSoftScore.ONE_HARD) { employee, count -> val minShifts = employee.minShiftsInMonth val maxShifts = employee.maxShiftsInMonth when { count < minShifts -> minShifts - count count > maxShifts -> count - maxShifts else -> 0 } } }
private fun <A, B> countIfBi(function: (A, B) -> Boolean) = DefaultBiConstraintCollector( Supplier { IntArray(1) }, TriFunction { resultContainer: IntArray, a: A, b: B -> val change = if (function(a, b)) 1 else 0 resultContainer[0] += change Runnable { resultContainer[0] -= change } }, Function { resultContainer: IntArray -> resultContainer[0] } ) private fun minAndMaxShiftsPerMonth(factory: ConstraintFactory): Constraint { return factory .from(Employee::class.java) .join(ShiftAssignment::class.java, employeeEqualsShiftAssignment()) .groupBy({ left, _ -> left }, countBi()) .penalize("Minimum and Maximum number of assignments", HardMediumSoftScore.ONE_HARD) { employee, count -> val minShifts = employee.minShiftsInMonth val maxShifts = employee.maxShiftsInMonth when { count < minShifts -> minShifts - count count > maxShifts -> count - maxShifts else -> 0 } } }
private fun employeeHasNoShifts(factory: ConstraintFactory): Constraint { return factory .from(Employee::class.java) .ifNotExists(ShiftAssignment::class.java, employeeEqualsShiftAssignment()) .penalize("No assignments", HardMediumSoftScore.ONE_HARD) { employee ->
val minShifts = employee.minShiftsInMonth when { minShifts != 0 -> minShifts else -> 0 } } }
private fun employeeEqualsShiftAssignment() = Joiners.equal<Employee, ShiftAssignment?, String>(Employee::code) { it.employee?.code }