/*

  For more information about this file, see 
  "Choco: Constraint Programming i Java"
  http://www.hakank.org/webblogg/archives/001113.html
  
*/


// **************************************************
// *  CHOCO: an open-source Constraint Programming  *
// *     System for Research and Education          *
// *                                                *
// *    contributors listed in choco.Entity.java    *
// *           Copyright (C) F. Laburthe, 1999-2006 *
// **************************************************

/* 
From chocosamples/Zebra.java, somewhat changed.

The problem stated at http://www.probp.com/examples/cg/zebra.pl:

    The English man lives in a red house.
    The Spaniard owns a dog.
    The Japanese is a painter.
    The Italian drinks tea.
    The Norwegian lives in the first house on the left.
    The owner of the green house drinks coffee.
    The green house is on the right of the white one.
    The sculptor breeds snails. 
    The diplomat lives in the yellow house.
    Milk is drunk in the middle house.
    The Norwegian's house is next to the blue one.
    The violinist drinks fruit juice.
    The fox is in the house next to that of the doctor.
    The horse is in the house next to that of the diplomat.

    Who owns a zebra and who drinks water?

*/

import choco.*;
import choco.Problem;
import choco.Problem.*;
import choco.ContradictionException;
import choco.integer.IntDomainVar;

public class Zebra {
    
    private static Problem pb;
    private static IntDomainVar green, blue, yellow, ivory, red;
    private static IntDomainVar diplomat, painter, sculptor, doctor, violinist;
    private static IntDomainVar norwegian, english, japanese, spaniard, italian;
    private static IntDomainVar wine, milk, coffee, water, tea;
    private static IntDomainVar fox, snail, horse, dog, zebra;
    private static IntDomainVar[] colors, trades, nationalities, drinks, pets;
    private static IntDomainVar[][] arrays;
    
    public static void main(String args[]) {

        pb = new Problem();

        green = pb.makeEnumIntVar("green", 1, 5);
        blue = pb.makeEnumIntVar("blue", 1, 5);
        yellow = pb.makeEnumIntVar("yellow", 1, 5);
        ivory = pb.makeEnumIntVar("ivory", 1, 5);
        red = pb.makeEnumIntVar("red", 1, 5);
        diplomat = pb.makeEnumIntVar("diplomat", 1, 5);
        painter = pb.makeEnumIntVar("painter", 1, 5);
        sculptor = pb.makeEnumIntVar("sculptor", 1, 5);
        doctor = pb.makeEnumIntVar("doctor", 1, 5);
        violinist = pb.makeEnumIntVar("violinist", 1, 5);
        norwegian = pb.makeEnumIntVar("norwegian", 1, 5);
        english = pb.makeEnumIntVar("english", 1, 5);
        japanese = pb.makeEnumIntVar("japanese", 1, 5);
        spaniard = pb.makeEnumIntVar("spaniard", 1, 5);
        italian = pb.makeEnumIntVar("italian", 1, 5);
        wine = pb.makeEnumIntVar("wine", 1, 5);
        milk = pb.makeEnumIntVar("milk", 1, 5);
        coffee = pb.makeEnumIntVar("coffee", 1, 5);
        water = pb.makeEnumIntVar("water", 1, 5);
        tea = pb.makeEnumIntVar("tea", 1, 5);
        fox = pb.makeEnumIntVar("fox", 1, 5);
        snail = pb.makeEnumIntVar("snail", 1, 5);
        horse = pb.makeEnumIntVar("horse", 1, 5);
        dog = pb.makeEnumIntVar("dog", 1, 5);
        zebra = pb.makeEnumIntVar("zebra", 1, 5);
        colors = new IntDomainVar[]{green, blue, yellow, ivory, red};
        trades = new IntDomainVar[]{diplomat, painter, sculptor, doctor, violinist};
        nationalities = new IntDomainVar[]{norwegian, english, japanese, spaniard, italian};
        drinks = new IntDomainVar[]{wine, milk, coffee, water, tea};
        pets = new IntDomainVar[]{fox, snail, horse, dog, zebra};

        arrays = new IntDomainVar[][]{colors, trades, nationalities, drinks, pets};


        // alldifferent
        for (int a = 0; a < 5; a++) {
            for (int i = 0; i < 4; i++) {
                for (int j = i + 1; j < 5; j++) {
                    pb.post( pb.neq(arrays[a][i], arrays[a][j]));
                }
            }
        }

        // help for incomplete alldiff on colors
        pb.post( pb.eq(yellow, 1));

        // help for incomplete alldiff on colors
        pb.post( pb.eq(water, 1));
        
        pb.post( pb.eq(english, red));
        pb.post( pb.eq(spaniard, dog));
        pb.post( pb.eq(coffee, green));
        pb.post( pb.eq(italian, tea));
        pb.post( pb.eq(sculptor, snail));
        pb.post( pb.eq(diplomat, yellow));
        pb.post( pb.eq(green, pb.plus(ivory, 1)));
        pb.post( pb.eq(milk, 3));
        pb.post( pb.eq(norwegian, 1));
        pb.post( pb.eq(violinist, wine));
        pb.post( pb.eq(japanese, painter));

        // pb.post( pb.eq(pb.minus(doctor, fox), 1)); // original
        // The fox is in the house next to that of the doctor.
        pb.post(pb.or( 
                      pb.eq(pb.minus(doctor, fox), 1),
                      pb.eq(pb.minus(doctor, fox), -1)
                 ));

        // pb.post(pb.eq(pb.minus(diplomat, horse), -1));  // original
        // The horse is in the house next to that of the diplomat.
        pb.post(
                pb.or(
                      pb.eq(pb.minus(diplomat, horse), 1),
                      pb.eq(pb.minus(diplomat, horse), -1)                     
                ));

        // pb.post(pb.eq(pb.minus(norwegian, blue), -1)); // original
        // The Norwegian's house is next to the blue one.
        pb.post(
                pb.or(
                      pb.eq(pb.minus(norwegian, blue), 1),
                      pb.eq(pb.minus(norwegian, blue), -1)
                ));


        // Now, solve the problem
        pb.solve(true);

        System.out.println("Solution: zebra: " + zebra.getVal() + " water: " + water.getVal() + "\n");

        
        Solver s = pb.getSolver();        
        for (int a = 0; a < 5; a++) {
          for (int i = 0; i < 5; i++) {
            System.out.print(arrays[a][i].toString() + ": " + arrays[a][i].getVal() + " ");
          }
          System.out.println();
        } 
        
    } // end main

} // end vlass
