/**
  *
  * Least Diff problem in Choco.
  *
  * Minimize the difference ABCDE - FGHIJ
  *                     where A..J is all different in the range 0..9.
  *
  * The solution is: 50123 - 49876 = 247
  *
  * Other models of this problem:
  * MiniZinc model: http://www.hakank.org/minizinc/least_diff.mzn
  * Choco (version 1): http://www.hakank.org/constraints/LeastDiff2.java
  * JaCoP: http://www.hakank.org/JaCoP/LeastDiff.java
  *
  *
  * Choco model by Hakan Kjellerstrand (hakank@bonetmail.com)
  * Also see http://www.hakank.org/choco/
  *
  */
import static choco.Choco.*;
import choco.cp.model.CPModel;
import choco.cp.solver.CPSolver;
import choco.cp.solver.constraints.*;
import choco.cp.solver.*;
import choco.kernel.model.variables.integer.*;
import choco.kernel.*;
import choco.kernel.solver.*;
import choco.kernel.model.*;
import choco.kernel.model.variables.*;
import choco.kernel.model.constraints.*;
import choco.kernel.model.variables.set.*;
import choco.cp.solver.search.integer.varselector.*;
import choco.cp.solver.search.integer.valiterator.*;
import choco.cp.solver.search.integer.valselector.*;
import choco.cp.solver.search.integer.branching.*;

import java.io.*;
import java.util.*;
import java.text.*;


public class LeastDiff2 {

  public static void main(String[] args) {
    new LeastDiff2().puzzle();
  }

  public void puzzle () {
    Model m = new CPModel();

    IntegerVariable A = makeIntVar("A", 0, 9);
    IntegerVariable B = makeIntVar("B", 0, 9);
    IntegerVariable C = makeIntVar("C", 0, 9);
    IntegerVariable D = makeIntVar("D", 0, 9);
    IntegerVariable E = makeIntVar("E", 0, 9);
    IntegerVariable F = makeIntVar("F", 0, 9);
    IntegerVariable G = makeIntVar("G", 0, 9);
    IntegerVariable H = makeIntVar("H", 0, 9);
    IntegerVariable I = makeIntVar("I", 0, 9);
    IntegerVariable J = makeIntVar("J", 0, 9);
    IntegerVariable[] letters = {A,B,C,D,E,F,G,H,I,J};
  
    IntegerVariable Diff = makeIntVar("Diff", 0, 1000);

    // temporary variables
    IntegerVariable X = makeIntVar("X", 0, 100000);
    IntegerVariable Y = makeIntVar("Y", 0, 100000);

    // all unique
    m.addConstraint(allDifferent(letters));

    // X = A+B+C+D+E
    m.addConstraint(eq(X, scalar(new int[]{10000, 1000, 100, 10, 1},
                                 new IntegerVariable[]{A,B,C,D,E})));
    // Y = F +G + H + I + J
    m.addConstraint(eq(Y, scalar(new int[]{10000, 1000, 100, 10, 1},
                                 new IntegerVariable[]{F,G,H,I,J})));

    // Diff = X - Y
    m.addConstraint(eq(minus(X, Y), Diff));


    Solver s = new CPSolver();
    s.read(m);
    // variable selector
    // s.setVarIntSelector(new MinDomain(s));
    // s.setVarIntSelector(new DomOverDeg(s));
    // s.setVarIntSelector(new DomOverDynDeg(s)); 
    // s.setVarIntSelector(new MostConstrained(s));
    // s.setVarIntSelector(new RandomIntVarSelector(s));
    // s.setVarIntSelector(new MinDomain(s, s.getVar(x)));
    // s.setVarIntSelector(new LexIntVarSelector(
    //                                                new MinDomain(s),
    //                                                new DomOverDeg(s)));
    
    // value interator
    // s.setValIntIterator(new DecreasingDomain());
    // s.setValIntIterator(new IncreasingDomain());
    
    // value selector
    // s.setValIntSelector(new MinVal());
    // s.setValIntSelector(new MaxVal());
    // s.setValIntSelector(new MidVal());
    // s.setValIntSelector(new RandomIntValSelector()); // not bad...
    

    s.monitorTimeLimit(true);
    s.monitorBackTrackLimit(true);
    s.monitorNodeLimit(true);
    s.monitorFailLimit(true);

    // minimize the difference
    s.minimize(s.getVar(Diff), false);

    s.printRuntimeStatistics();
    System.out.println(s.pretty());    

    // Print the solution
    System.out.println("Result: "+ s.getVar(A).getVal() + s.getVar(B).getVal() + s.getVar(C).getVal() +s.getVar(D).getVal() + s.getVar(E).getVal() + " - " + s.getVar(F).getVal() + s.getVar(G).getVal() + s.getVar(H).getVal() + s.getVar(I).getVal() + s.getVar(J).getVal() + " = " + s.getVar(Diff).getVal() );
    
  } // end puzzle

} // end class
