@Override
 public void unassigned(long iteration, ExamPlacement value) {
   super.unassigned(iteration, value);
   if (!isHard() && iIsSatisfied != isSatisfied()) {
     iIsSatisfied = !iIsSatisfied;
     ((ExamModel) value.variable().getModel())
         .addDistributionPenalty(iIsSatisfied ? -getWeight() : getWeight());
   }
 }
 /**
  * Compute conflicts -- there is a conflict if the other variable is assigned and {@link
  * ExamDistributionConstraint#check(ExamPlacement, ExamPlacement)} is false
  */
 @Override
 public void computeConflicts(ExamPlacement givenPlacement, Set<ExamPlacement> conflicts) {
   boolean before = true;
   for (Exam exam : variables()) {
     if (exam.equals(givenPlacement.variable())) {
       before = false;
       continue;
     }
     ExamPlacement placement = exam.getAssignment();
     if (placement == null) continue;
     if (!check(before ? placement : givenPlacement, before ? givenPlacement : placement))
       conflicts.add(placement);
   }
 }
 /**
  * Check for conflict -- there is a conflict if the other variable is assigned and {@link
  * ExamDistributionConstraint#check(ExamPlacement, ExamPlacement)} is false
  */
 @Override
 public boolean inConflict(ExamPlacement givenPlacement) {
   boolean before = true;
   for (Exam exam : variables()) {
     if (exam.equals(givenPlacement.variable())) {
       before = false;
       continue;
     }
     ExamPlacement placement = exam.getAssignment();
     if (placement == null) continue;
     if (!check(before ? placement : givenPlacement, before ? givenPlacement : placement))
       return true;
   }
   return false;
 }
 /**
  * Return true if this is hard constraint or this is a soft constraint without any violation
  *
  * @param p exam assignment to be made
  */
 public boolean isSatisfied(ExamPlacement p) {
   if (isHard()) return true;
   switch (getType()) {
     case sDistPrecedence:
       ExamPeriod last = null;
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         if (last == null || last.getIndex() < placement.getPeriod().getIndex())
           last = placement.getPeriod();
         else return false;
       }
       return true;
     case sDistPrecedenceRev:
       last = null;
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         if (last == null || last.getIndex() > placement.getPeriod().getIndex())
           last = placement.getPeriod();
         else return false;
       }
       return true;
     case sDistSamePeriod:
       ExamPeriod period = null;
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         if (period == null) period = placement.getPeriod();
         else if (period.getIndex() != placement.getPeriod().getIndex()) return false;
       }
       return true;
     case sDistDifferentPeriod:
       HashSet<ExamPeriod> periods = new HashSet<ExamPeriod>();
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         if (!periods.add(placement.getPeriod())) return false;
       }
       return true;
     case sDistSameRoom:
       Set<ExamRoomPlacement> rooms = null;
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         if (rooms == null) rooms = placement.getRoomPlacements();
         else if (!rooms.containsAll(placement.getRoomPlacements())
             || !placement.getRoomPlacements().containsAll(rooms)) return false;
       }
       return true;
     case sDistDifferentRoom:
       HashSet<ExamRoomPlacement> allRooms = new HashSet<ExamRoomPlacement>();
       for (Exam exam : variables()) {
         ExamPlacement placement =
             (p != null && exam.equals(p.variable()) ? p : exam.getAssignment());
         if (placement == null) continue;
         for (ExamRoomPlacement room : placement.getRoomPlacements()) {
           if (!allRooms.add(room)) return false;
         }
       }
       return true;
     default:
       return false;
   }
 }
 /**
  * Check assignments of the given exams
  *
  * @param first assignment of the first exam
  * @param second assignment of the second exam
  * @return true, if the constraint is satisfied
  */
 public boolean check(ExamPlacement first, ExamPlacement second) {
   switch (getType()) {
     case sDistPrecedence:
       return first.getPeriod().getIndex() < second.getPeriod().getIndex();
     case sDistPrecedenceRev:
       return first.getPeriod().getIndex() > second.getPeriod().getIndex();
     case sDistSamePeriod:
       return first.getPeriod().getIndex() == second.getPeriod().getIndex();
     case sDistDifferentPeriod:
       return first.getPeriod().getIndex() != second.getPeriod().getIndex();
     case sDistSameRoom:
       return first.getRoomPlacements().containsAll(second.getRoomPlacements())
           || second.getRoomPlacements().containsAll(first.getRoomPlacements());
     case sDistDifferentRoom:
       for (Iterator<ExamRoomPlacement> i = first.getRoomPlacements().iterator(); i.hasNext(); )
         if (second.getRoomPlacements().contains(i.next())) return false;
       return true;
     default:
       return false;
   }
 }
 /**
  * Consistency check -- {@link ExamDistributionConstraint#check(ExamPlacement, ExamPlacement)} is
  * called
  */
 @Override
 public boolean isConsistent(ExamPlacement first, ExamPlacement second) {
   boolean before =
       (variables().indexOf(first.variable()) < variables().indexOf(second.variable()));
   return check(before ? first : second, before ? second : first);
 }