8.4. A basic Constraint example: the XXX Constraint

8.4.1. The AllDifferentExcept constraint more in details

class AllDifferentExcept : public Constraint {
 public:
  AllDifferentExcept(Solver* const s, std::vector<IntVar*> vars, int64 escape_value)
      : Constraint(s), vars_(vars), escape_value_(escape_value) {}

  virtual ~AllDifferentExcept() {}

  virtual void Post() {
    for (int i = 0; i < vars_.size(); ++i) {
      IntVar* const var = vars_[i];
      Demon* const d = MakeConstraintDemon1(
          solver(), this, &AllDifferentExcept::Propagate, "Propagate", i);
      var->WhenBound(d);
    }
  }

  virtual void InitialPropagate() {
    for (int i = 0; i < vars_.size(); ++i) {
      if (vars_[i]->Bound()) {
        Propagate(i);
      }
    }
  }

  void Propagate(int index) {
    const int64 val = vars_[index]->Value();
    if (val != escape_value_) {
      for (int j = 0; j < vars_.size(); ++j) {
        if (index != j) {
          vars_[j]->RemoveValue(val);
        }
      }
    }
  }

  virtual std::string DebugString() const {
    return StringPrintf("AllDifferentExcept([%s], %" GG_LL_FORMAT "d",
                        JoinDebugStringPtr(vars_, ", ").c_str(), escape_value_);
  }

  virtual void Accept(ModelVisitor* const visitor) const {
    visitor->BeginVisitConstraint(ModelVisitor::kAllDifferent, this);
    visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
                                               vars_);
    visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, escape_value_);
    visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this);
  }

 private:
  std::vector<IntVar*> vars_;
  const int64 escape_value_;
};

basic_constraint_example