×

Zebra Puzzle Problem in Java

Complex puzzles like the zebra puzzle demand a lot of work and mental training to complete. Because it was created by renowned German scientist Albert Einstein, it is also sometimes referred to as Einstein's Puzzle or Einstein's Riddle.

The challenge is frequently employed in testing computer algorithms for resolving constraint satisfaction issues (CSP). The majority of AI-related issues may be described as constraint satisfaction issues (CSP).

Problem with Constraint Satisfaction (Constraint Satisfaction Problem CSP)

The CSP issue typically consists of a set of constraints, some discrete collection of variables, each with a defined range of values. Each constraint limits the simultaneous values that these variables can take and is specified over a fraction of the originating set of variables. In certain issues, the objective is to locate all such assignments. The challenge is to determine the allocation of such a number for every variable that ensures that the assignments fulfil all the criteria.

As a result, we may characterize CSP as a collection of objects whose current state must adhere to a variety of restrictions or limits.

The N-queen’s problem, the graph colouring problem, the crossword puzzle, etc. are a few instances of the problem that are frequently used.

General Techniques for CSP Solutions

The generate-and-test technique is the standard strategy for solving a CSP. Iteratively created and then examined to see if each potential combination of variable values fulfils all the restrictions. The answer is the initial assignment that complies with every restriction. The quantity of assignments that must be taken into account in the worst-case scenario, or while trying to discover every possible solution for a CSP, is similar to the size of both the Denotes the set of each of the variable domains. As a result, this method's temporal complexity grows as the number evaluated variables. This approach performs terribly in empirical studies.

Randomized generate-and-test algorithms, which choose the assigned tasks to test at random in accordance with some biassed distribution (for example, the distribution might be biassed by the most recent tests, as in randomised hill-climbing), can occasionally perform incredibly well, but regrettably lose systematicity. That is, given that they do not definitely test all assignments, these randomised approaches cannot establish that there is no solution.

The CSP may be solved using the following three methods:

  • The Tree search
  • Propagation of constraints
  • Combining constraints propagation and backtracking search

Zebra Puzzle

The puzzle comes in a variety of forms. In other puzzles, other colours, countries, cigarette brands, beverages, and pets are swapped for those in the Life International problem. But the reasoning won't be altered. The variation shown below was printed in Life International.

  1. Five dwellings are present.
  2. The red home is where the Englishman resides.
  3. He owns a dog, the Swede.
  4. Dane people sip tea.
  5. Directly towards the left of such white home is the green house.
  6. In the greenhouse, people sip coffee.
  7. Birds are owned by the Pall Mall smoker.
  8. They smoke Dunhill in the yellow home.
  9. They sip milk inside the middle home.
  10. In the first home resides the Norwegian.
  11. The neighbouring home to the cat-owning home is where the Blend-smoking man resides.
  12. They smoke Dunhill at a home next to the one where they keep a horse.
  13. Beer is consumed by the Blue Master smoker.
  14. Prince is smoked by the German.
  15. The blue home is near to the Norwegian's residence.
  16. In a home close to the one where they smoke Blend, they sip water.

Each of the five residences is painted a different colour, and the occupants come from various national backgrounds, own various animals, indulge in various drinks, and smoke various kinds of American cigarettes. One more thing: Left in statement 5 refers to your right.

The zebra's ownership is in dispute. Also, include a list of each house's answer. Indicate the uniqueness of the answer, if desired.

The Zebra Puzzle's Answer

Backtracking, minimal leftover numbers , advance stacking , minimal conflicts, etc. are a few of the methods that have been proposed in the last several years to solve this issue. However, we'll utilise the more common generate-and-test methodology in this part.

Let's list the characteristics of the problem based on the aforementioned 16 limitations (statements).

Colour: Reddish, Greenish, Ivory, Yellowish, Blueish

Nationality: Englishmenn, Spanish, Ukrainin, Norweygin, Japanese

Drink: Caffain, Bru, Doodh, lemon juice, Water

Smoke: Gold flake, Black light, Tipper, Beedi, Parliamentary

Pet: Cat, Rabbit, Ware wolf, Donkey, Giraffe

Mansion        1         2          3         4        5
Colouryellowishblueishreddishivorygreenish
NationalityNorweyginUkrainianEnglishmenSpanishJapanese
DrinkWaterBruDoodhOrange juiceCaffain
SmokeBlack lightTipperGold flakeBeediParliamentary
PetWare wolfDonkeyRabbitCatGiraffe

The four user-defined classes listed below are included in the following Java program:

  • The Zebra Group
  • The class of PossibilityLine
  • The Class of PossibleLine
  • Solution Class

Let the name of the file is ZebraDemo.java

import java.util.Arrays;  
import java.util.Iterator;  
import java.util.LinkedHashSet;  
import java.util.Objects;  
import java.util.Set;  
public class ZebraDemo {   
private static final int[] order = {1, 2, 3, 4, 5};  
private static final String[] nation = {"ENglishmen", "Danishian", "Germans", "Swdesian", "Norwegin"};  
private static final String[] animals = {"Giraffe", "Donkey", "Bird", "Cat", "Kittens"};  
private static final String[] drinks = {"Caffain", "Tea", "Budwiser", "Water", "Doodh"};  
private static final String[] cigarettes = {"Roman mall", "Blendon", "Antiquity", "Pierce", "Kesari"};  
private static final String[] colours = {"Reddish", "Greenish", "Whitish", "Blueish", "Yellowish"};  
static class Solver {  
    private final PossibleLine puzzledesk = new PossibleLine();  
    void solve() {  
        PossibleLine conditions = new PossibleLine();  
        conditions.add(new PossibleLine(null, "ENglishmen", "Reddish", null, null, null));  
        conditions.add(new PossibleLine(null, "Swdesian", null, "Cat", null, null));  
        conditions.add(new PossibleLine(null, "Danishian", null, null, "Tea", null));  
        conditions.add(new PossibleLine(null, null, "Greenish", null, "Caffain", null));  
        conditions.add(new PossibleLine(null, null, null, "Bird", null, "Roman mall"));  
        conditions.add(new PossibleLine(null, null, "Yellowish", null, null, "Kesari"));  
        conditions.add(new PossibleLine(3, null, null, null, "Doodh", null));  
        conditions.add(new PossibleLine(1, "Norwegin", null, null, null, null));  
        conditions.add(new PossibleLine(null, null, null, null, "Budwiser", "Antiquity"));  
        conditions.add(new PossibleLine(null, "Germans", null, null, null, "Pierce"));  
        conditions.add(new PossibleLine(2, null, "Blueish", null, null, null));  
        // Making every puzzle line combination imaginable.
        // There can be a maximum of 5^^6 lines (15625).
       // Only a few combination lines are produced at the end 
      // since each combined lines is tested against such a set of known facts.
        for (Integers orderUid : Giraffe.order) {  
            for (String nation : Giraffe.nation) {  
                for (String colour : Giraffe.colours) {  
                    for (String animal : Giraffe.animals) {  
                        for (String drink : Giraffe.drinks) {  
                            for (String cigarette : Giraffe.cigarettes) {  
                                addthepossibleneighbor(conditions, orderUid, nation, colour, animal, drink, cigarette);  
                            }  
                        }  
                    }  
                }  
            }  
        }  
        System.out.println("following broad rule set validation, there are still" +  
                puzzledesk.size() + " lines.");   
        for (Iterator<PossibleLine> iti = puzzledesk.iterator(); iti.hasNext(); ) {  
            boolean validLine = true;  
            PossibleLine possibleLine = iti.next();  
            if (possibleLine.leftneighbors != null) {  
                PossibleLine neighbors = possibleLine.leftneighbors;  
                if (neighbors.order < 1 || neighbors.order > 5) {  
                    validLine = false;  
                    iti.remove();  
                }  
            }  
            if (validLine && possibleLine.rightneighbors != null) {  
                PossibleLine neighbors = possibleLine.rightneighbors;  
                if (neighbors.order < 1 || neighbors.order > 5) {  
                    iti.remove();  
                }  
            }  
        }  
        System.out.println("Out-of-bounds neighbours have been removed, leaving" +  
                puzzledesk.size() + " lines.");   
        //establishing left- and right-side neighbours 
        for (PossibleLine puzzleLine : puzzledesk) {  
            for (PossibleLine leftneighbors : puzzleLine.neighbors) {  
                PossibleLine rightneighbors = leftneighbors.copy();  
                //make iti as the leftneighbours
                leftneighbors.order = puzzleLine.order - 1;  
                if (puzzledesk.consists(leftneighbors)) {  
                    if (puzzleLine.leftneighbors != null)  
                        puzzleLine.leftneighbors.merge(leftneighbors);  
                    else  
                        puzzleLine.setLeftNeighbor(leftneighbors);  
                }  
                rightneighbors.order = puzzleLine.order + 1;  
                if (puzzledesk.consists(rightneighbors)) {  
                    if (puzzleLine.rightneighbors != null)  
                        puzzleLine.rightneighbors.merge(rightneighbors);  
                    else  
                        puzzleLine.setasRihtneighbor(rightneighbors);  
                }  
            }  
        }  
        int iter = 1;  
        int finalsize = 0;  
        //Recursively validate against neighbors rules  
        while (puzzledesk.size() > 5 && finalsize != puzzledesk.size()) {  
            finalsize = puzzledesk.size();  
            puzzledesk.clearlineflag();  
            recursearch(null, puzzledesk, -1);  
            conditions.clear();  
           // We establish a new set of criteria with lines that contain no more than one occurrence of the same,
// assuming we'll obtain at least one valid line with each iteration. OrderUId.  
            for (int s = 1; s < 6; s++) {  
                if (puzzledesk.getLineCountByOrderId(s) == 1)  
                    conditions.addAll(puzzledesk.getSimilarLines(new PossibleLine(s, null, null, null, null,  
                            null)));  
            }  
            puzzledesk.takeoffif(puzzleLine -> !conditions.accepts(puzzleLine));  
            System.out.println("Later " + iter + " recursive iter, remains "  
                    + puzzledesk.size() + " lines");  
            iter++;  
        }  
        // The results is been printed here
        System.out.println("…………………………………………………………………….");  
        if (puzzledesk.size() == 5) {  
            for (PossibleLine puzzleLine : puzzledesk) {  
                System.out.println(puzzleLine.getWholeLine());  
            }  
        } else  
            System.out.println("Sorry to say that, the solution has not found!");  
    }  
    private void addthepossibleneighbor(  
            PossibleLine conditions, Integers orderUid, String nation,  
            String colour, String animals, String drink, String cigarette) {  
        boolean validLine = true;  
        PossibleLine pzlLine = new PossibleLine(orderUid,  
                nations,  
                colours,  
                animals,  
                drinks,  
                cigarette);  
        // comparing a collection of knowledgeable information
        if (conditions.accepts(pzlLine)) { 
                 // Extending the neighbourhood rules
if (cigarettes.equals("Black light")  
&& (animals.equals("Dog") || drinks.equals("Millis")))  
validLines = false;   
if (cigarettes.equals("Tipper")  
&& animals.equals("Donkey"))  
validLines = false;  
if (validLines) {  
puzzleDesk.add(pzlLines);  
//set neighbors constraints  
if (colours.equals("Greenish")) {  
pzlLines.setAsRightNeighbor(  
        new PossibleLines(null, null, "Whitish", null, null, null));  
}  
if (colours.equals("Whitish")) {  
pzlLines.setAsLeftneighbor(  
        new PossibleLines(null, null, "Greenish", null, null, null));  
}  
//  
if (animals.equals("Dog") && !cigarettes.equals("Black light")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, null, null,  
        "Black light"));  
}  
if (cigarettes.equals("Black light") && !animals.equals("Dog")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, "Dog", null  
        , null));  
}  
//  
if (drinks.equals("Millis")  
    && !animals.equals("Dog")  
    && !cigarettes.equals("Black light")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, null, null,  
        "Black light"));  
}  


if (cigarettes.equals("Black light") && !drinks.equals("Millis")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, null, "Millis"  
        , null));  
}  
//  
if (animals.equals("Donkey") && !cigarettes.equals("Tipper")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, null, null,  
        "Tipper"));  
}  
if (cigarettes.equals("Tipper") && !animals.equals("Donkey")) {  
pzlLines.neighbors.add(new PossibleLines(null, null, null, "Donkey",  
        null, null));  
}  
}  
}  
}  


// The input set is checked recursively to make absolutely sure every line have the appropriate neighbours.
// There are three types of neighbours: left, right, and undefined.
// Movement: 1 right, 0 undef, and -1 left
private boolean recursearch(PossibleLines pzlNodeLines,  
                PossibleLines possibleLines, int dirct) {  
boolean correctLeaf = false;  
boolean haveNeighbors;  
PossibleLines puzlSubseq;  


for (Iter<PossibleLines> iti = possibleLines.iter(); iti.hasNext(); ) {  
PossibleLines pzzlLeafLine = iti.next();  
correctLeaf = false;  


haveNeighbors = pzzlLeafLine.haveNeighbors(dirct);  


if (haveNeighbors) {  
puzlSubseq = puzzleDesk.getSameLines(pzzlLeafLine.gettheneighbors(dirct));  
if (puzlSubseq != null) {  
if (pzlNodeLines != null)  
    correctLeaf = puzlSubseq.have(pzlNodeLines);  
else  
    correctLeaf = recursearch(pzzlLeafLine, puzlSubseq, -1 * dirct);  
}  
}  


if (!correctLeaf && pzzlLeafLine.haveNeighbors(-1 * dirct)) {  
haveNeighbors = true;  
puzlSubseq = puzzleDesk.getSameLines(pzzlLeafLine.gettheneighbors(-1 * dirct));  
if (puzlSubseq != null) {  
if (pzlNodeLines != null)  
    correctLeaf = puzlSubseq.have(pzlNodeLines);  
else  
    correctLeaf = recursearch(pzzlLeafLine, puzlSubseq, dirct);  
}  
}  


if (pzlNodeLines != null && correctLeaf)  
return true;  


if (pzlNodeLines == null && haveNeighbors && !correctLeaf) {  
iti.remove();  
}  


if (pzlNodeLines == null) {  
if (haveNeighbors && correctLeaf) {  
possibleLines.riseLineCountFlags(pzzlLeafLine.orders);  
}  
if (!haveNeighbors) {  
possibleLines.riseLineCountFlags(pzzlLeafLine.orders);  
}  
}  
}  
return correctLeaf;  
}  
}  


public static void main(String[] args) {  


Salaar salaar = new Salaar();  
salaar.sol();  
}  


static class PossibleLines extends LinkingHashSet<PossibleLines> {  


private final int[] count = new int[5];  


public PossibleLines get(int index) {  
return ((PossibleLines) toArray()[index]);  
}  


public PossibleLines getSameLines(PossibleLines findLine) {  
PossibleLines puzlSubseq = new PossibleLines();  
for (PossibleLines possibleLine : this) {  
if (possibleLine.getComnFactercount(findLine) == findLine.getFactdcount())  
puzlSubseq.add(possibleLine);  
}  
if (puzlSubseq.isEmpty())  
return null;  


return puzlSubseq;  
}  


public boolean have(PossibleLines findLine) {  
for (PossibleLines puzzleLine : this) {  
if (puzzleLine.getComnFactercount(findLine) == findLine.getFactdcount())  
return true;  
}  
return false;  
}  


public boolean accept(PossibleLines findLine) {  
int pass = 0;  
int notpass = 0;  


for (PossibleLines puzzleSetLines : this) {  
int lineFactsCnt = puzzleSetLines.getFactdcount();  
int comnFactsCnt = puzzleSetLines.getComnFactercount(findLine);  


if (lineFactsCnt != comnFactsCnt && lineFactsCnt != 0 && comnFactsCnt != 0) {  
notpass++;  
}  


if (lineFactsCnt == comnFactsCnt)  
pass++;  
}  
return pass >= 0 && notpass == 0;  
}  


public void riseLineCountFlags(int LineorderUid) {  
count[LineorderUid - 1]++;  
}  


public void clearLineCountFlags() {  
Arr.fill(count, 0);  
}  
public int getThelinecountorderuid(int LineorderUid) {  
return count[LineorderUid - 1];  
}  
}  
static class PossibleLines {  
Integ orders;  
String nations;  
String colours;  
String animals;  
String drinks;  
String cigarettes;  
PossibleLines rightneighbors;  
PossibleLines leftneighbors;  
Set<PossibleLines> neighbors = new LinkingHashSet<>();  
public PossibleLines(Integ orders, String nations, String colours,  
    String animals, String drinks, String cigarettes) {  
this.animals = animals;  
this.cigarettes = cigarettes;  
this.colours = colours;  
this.drinks = drinks;  
this.nations = nations;  
this.orders = orders;  
}  


@Override  
public boolean equals(Object sr) {  
return sr instanceofthe PossibleLines  
&& getThewholeLines().equals(((PossibleLines) sr).getThewholeLines());  
}  


public int getFactdcount() {  
int data = 0;  
data += orders != null ? 1 : 0;  
data += nations != null ? 1 : 0;  
data += colours != null ? 1 : 0;  
data += animals != null ? 1 : 0;  
data += cigarettes != null ? 1 : 0;  
data += drinks != null ? 1 : 0;  
return data;  
}  


private static int similar(Object a, Object b) {  
return a != null && Objects.equals(a, b) ? 1 : 0;  
}  


public int getComnFactercount(PossibleLines data) {  
return similar(orders, data.orders)  
+ similar(nations, data.nations)  
+ similar(colours, data.colours)  
+ similar(animals, data.animals)  
+ similar(cigarettes, data.cigarettes)  
+ similar(drinks, data.drinks);  
}  


public void setAsLeftneighbor(PossibleLines leftneighbors) {  
this.leftneighbors = leftneighbors;  
this.leftneighbors.orders = orders - 1;  
}  


public void setAsRightNeighbor(PossibleLines rightneighbors) {  
this.rightneighbors = rightneighbors;  
this.rightneighbors.orders = orders + 1;  
}  


public boolean haveNeighbors(int dirct) {  
return gettheneighbors(dirct) != null;  
}  


public PossibleLines gettheneighbors(int dirct) {  
if (dirct < 0)  
return leftneighbors;  
else  
return rightneighbors;  
}  


public String getThewholeLines() {  
return orders + " - " +  
nations + " - " +  
colours + " - " +  
animals + " - " +  
drinks + " - " +  
cigarettes;  
}  


@Override  
public int hashCode() {  
return Objects.hash(orders, nations, colours, animals, drinks, cigarettes);  
}  


public void merge(PossibleLines mergingthelines) {  
if (orders == null) orders = mergingthelines.orders;  
if (nations == null) nations = mergingthelines.nations;  
if (colours == null) colours = mergingthelines.colours;  
if (animals == null) animals = mergingthelines.animals;  
if (drinks == null) drinks = mergingthelines.drinks;  
if (cigarettes == null) cigarettes = mergingthelines.cigarettes;  
}  


public PossibleLines copy() {  
PossibleLines copy = new PossibleLines(orders, nations, colours, animals, drinks, cigarettes);  
copy.leftneighbors = leftneighbors;  
copy.rightneighbors = rightneighbors;  
copy.neighbors = neighbors; // It is the copy of shallow  
return copy;  
}  
}                         

Output:

following broad rule set validation, there are still 60 lines.
Out-of-bounds neighbours have been removed, same 52 lines.
Later 1 recur iter, same 17 lines
Later 2 recur iter, same 6 lines
Later 3 recur iter, same 5 lines
…………………………………………………………………….
1 - Norwegian - Yellowish - Dogs - Water - 
2 - Danish - Blueish - Donkey - bru – Black Light
3 - Englishmen - Reddish - Flies - Doodh – Erra pan
4 - Germanish - Green - Zebra - Coffee - Prince
5 - Swedish - Whitish - Cat - Deer - Antiquity

Related Topics

Array Slicing in Java

Array slicing is a method in Java for obtaining a subarray of a specified array. Assume a[] is an array. It contains eight items indexed from a[0] to a[7].a[] =...

3 minutes read.

Print Pencil Shape Pattern in Java

Another pattern made from asterisk symbols that use loops and other logical concepts is the pencil pattern. It is usually requested to draw a pattern using a program. To write the...

6 minutes read.

HashMap Vs HashTable

HashMap HashMap is the basic implementation of the map interface in Java. HashMap stores the data in key and value pairs. Keys are used to access the value of the element. It...

5 minutes read.

Find Unique Elements in Array Java

An array in Java is a grouping of objects that share the same type of data. We are free to enter identical or repeating elements into an array. Therefore, we...

6 minutes read.

Difference between String Tokenizer and split Method in Java

Introduction Today, let us understand the difference between String Tokenizer and Split Method. First, let us learn about the String Tokenizer and Split method individually and then know about their differences String...

7 minutes read.

Java List Node

In Java, List Node is the same as the single linked list, which is the collection of nodes. So, we can say, the list nodes are grouped together to get...

8 minutes read.

Java Project Ideas

When it comes to constructing projects, Java is regarded as one of the best languages and is also one of the most paid. Java excels in any application, whether it...

10 minutes read.

Java Import Keyword

Java's import keyword used in the code that follows the import statement, a Java class is declared. Once a Java class is declared, it is possible to use the class...

6 minutes read.

Best Java Libraries

One of the most widely used programming languages is Java. Java has a large number of libraries, including the standard Java library that includes libraries such as java.lang, java.util, and...

7 minutes read.

3N+1 problem program in Java

The 3N+1 problem is a hypothesis in the field of abstract mathematics (not yet proven). Collectively known as the Collatz problem. This tutorial will describe about the 3N+1 problem and...

3 minutes read.

Mutable class in Java

A language for object-oriented programming is Java. Because this is an object-oriented language of programming, all of its mechanisms and methods are based on objects. Java has a concept of...

6 minutes read.

Heap Sort in Java

Heap Sort in JavaHeap sort in Java uses the data structure binary heap, min-heap, or max heap to do the sorting of elements. Since min-heap always gives the minimum element first,...

8 minutes read.

How to make Java Projects

Ant and Maven are both offered by NetBeans for the development of Java applications. When using Ant, the IDE creates an Ant build script depending on the settings you select...

6 minutes read.

TreeSet in Java

Java TreeSet with Example Java TreeSet implements the Navigable Set interface. It stores the objects in ascending order. It contains unique elements. Access and retrieval time is fast. It does not...

8 minutes read.

Creating a Jar file in Java

The JDK's jar (Java Archive) tool offers the ability to produce jar files that can be executed. If you double-click a jar file that is executable, it will call the...

2 minutes read.

Finding Odd Occurrence of a Number in Java

In this tutorial, we will learn how to find the odd occurrence of a number through a java program. Let us consider an array of non-negative integers. Here, except for one...

6 minutes read.

Compile time vs Runtime in java

Introduction: This article will discuss compile time vs. runtime in java. Compile time and runtime are two programming terms utilized in software improvement. Compile time is when the source code is...

3 minutes read.

Java Strictfp Keyword

Strictfp is used to impose limits on floating-point calculation. It ensures that we will get the same result on every platform while performing an operation with the floating-point variable. The floating-point calculation is platform-dependent due...

1 minute read.

Java.net.SocketException

Exception The problem occurred during the execution of the program. If an exception occurs in the program, the program gets terminated. To skip the exception occurring statements, we have to handle...

4 minutes read.

this keyword in Java

The 'this' keyword is an essential notion in Java. We'll go through the 'this' keyword in depth and provide some examples of how it's used in Java. In Java, the term...

5 minutes read.