/*
 * The Seseman's Convent Problem in choco v2.
 *
 * Given the following matrix:
 *
 *    A  B  C
 *    D  _  E
 *    F  G  H
 *
 * calculate the following constraints:
 *
 *   A + B + C = RowSum
 *   A + D + F = RowSum
 *   C + E + H = RowSum
 *   F + G + H = RowSum
 *   A + B + C + D + E + F + G + H = Total
 *
 *
 * For more information about this problem:
 * - Swedish blog post with a fuller description of the problem:
 *   "Sesemans matematiska klosterproblem samt lite Constraint Logic Programming"
 *   http://www.hakank.org/webblogg/archives/001084.html
 *
 * Compare with other (constraint programming) models of this problem:
 * - ECLiPSe: http://www.hakank.org/seseman/seseman.ecl
 * - Choco (version 1): http://www.hakank.org/constraints/Seseman.java
 * - MiniZinc solution 1: http://www.hakank.org/minizinc/seseman.mzn
 * - MiniZinc solution 2 (generalized): http://www.hakank.org/minizinc/seseman2.mzn
 * - Python (with the package constraint): http://www.hakank.org/seseman/seseman.py
 * - Matlab: The comments at http://www.hakank.org/webblogg/archives/001084.html
 * - JaCoP: http://www.hakank.org/JaCoP/Seseman.java
 *
 * A CGI-program which uses the ECLiPSe program mentioned above
 *   http://www.hakank.org/seseman/seseman.cgi
 *
 *
 *
 * 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.*;



public class Seseman {
    
    public static void main(String[] args) {
        new Seseman().puzzle();
    }
    
    public void puzzle () {

        // int start = 0; // allow empty room
        int start = 1; // don't allow empty room

        Model m = new CPModel();
        CPSolver s = new CPSolver();
        
        // 0..9: allow empty rooms 1..9: don't allow empty rooms
        IntegerVariable A = makeIntVar("A", start, 9);
        IntegerVariable B = makeIntVar("B", start, 9);
        IntegerVariable C = makeIntVar("C", start, 9);
        IntegerVariable D = makeIntVar("D", start, 9);
        IntegerVariable E = makeIntVar("E", start, 9);
        IntegerVariable F = makeIntVar("F", start, 9);
        IntegerVariable G = makeIntVar("G", start, 9);
        IntegerVariable H = makeIntVar("H", start, 9);
        IntegerVariable[] letters = {A,B,C,D,E,F,G,H};

        IntegerVariable Total = makeIntVar("Total", 24, 24);
        IntegerVariable RowSum = makeIntVar("RowSum", 9, 9);


        m.addConstraint(eq(plus(A, plus(B, C)), RowSum));
        m.addConstraint(eq(plus(A, plus(D, F)), RowSum));
        m.addConstraint(eq(plus(C, plus(E, H)), RowSum));
        m.addConstraint(eq(plus(F, plus(G, H)), RowSum));

        m.addConstraint(eq(sum(letters), Total));
        s.read(m);
        s.solve();


        System.out.println("Feasible: " + s.isFeasible());

        System.out.println("Number of solutions: " + s.getNbSolutions());
        // System.out.println(s.pretty());
        

        int solNum = 1;
        do {
            System.out.println("\nSolution nr. " + solNum);
            solNum++;
            System.out.println("" + s.getVar(A).getVal() + " " + s.getVar(B).getVal() + " " + s.getVar(C).getVal());
            System.out.println("" + s.getVar(D).getVal() + " _ " + s.getVar(D).getVal());
            System.out.println("" + s.getVar(E).getVal() + " " + s.getVar(F).getVal() + " " + s.getVar(G).getVal());
            System.out.println("Total: " + s.getVar(Total).getVal() + " RowSum: " + s.getVar(RowSum).getVal());
            System.out.println();
        } while (s.nextSolution() == Boolean.TRUE);


        s.printRuntimeStatistics();

    }

}
