package zebra; import java.util.ArrayList; import java.util.Iterator; public class Puzzle { private static final ArrayList orders = new ArrayList<>(5); private static final ArrayList nations = new ArrayList<>(5); private static final ArrayList animals = new ArrayList<>(5); private static final ArrayList drinks = new ArrayList<>(5); private static final ArrayList cigarettes = new ArrayList<>(5); private static final ArrayList colors = new ArrayList<>(5); private static PuzzleSet puzzleTable; static { // House orders orders.add(1); orders.add(2); orders.add(3); orders.add(4); orders.add(5); // Man nations nations.add("English"); nations.add("Danish"); nations.add("German"); nations.add("Swedesh"); nations.add("Norwegian"); //Animals animals.add("Zebra"); animals.add("Horse"); animals.add("Birds"); animals.add("Dog"); animals.add("Cats"); //Drinks drinks.add("Coffee"); drinks.add("Tea"); drinks.add("Beer"); drinks.add("Water"); drinks.add("Milk"); //Smokes cigarettes.add("Pall Mall"); cigarettes.add("Blend"); cigarettes.add("Blue Master"); cigarettes.add("Prince"); cigarettes.add("Dunhill"); //Colors colors.add("Red"); colors.add("Green"); colors.add("White"); colors.add("Blue"); colors.add("Yellow"); } public static void main (String[] args){ boolean validLine=true; puzzleTable = new PuzzleSet<>(); //Rules LineOfPuzzle rule2 = new LineOfPuzzle(null, "English", "Red", null, null, null); LineOfPuzzle rule3 = new LineOfPuzzle(null, "Swedesh", null, "Dog", null, null); LineOfPuzzle rule4 = new LineOfPuzzle(null, "Danish", null, null, "Tea", null); LineOfPuzzle rule6 = new LineOfPuzzle(null, null, "Green", null, "Coffee", null); LineOfPuzzle rule7 = new LineOfPuzzle(null, null, null, "Birds", null, "Pall Mall"); LineOfPuzzle rule8 = new LineOfPuzzle(null, null, "Yellow", null, null, "Dunhill"); LineOfPuzzle rule9 = new LineOfPuzzle(3, null, null, null, "Milk", null); LineOfPuzzle rule10 = new LineOfPuzzle(1, "Norwegian", null, null, null, null); LineOfPuzzle rule13 = new LineOfPuzzle(null, null, null, null, "Beer", "Blue Master"); LineOfPuzzle rule14 = new LineOfPuzzle(null, "German", null, null, null, "Prince"); LineOfPuzzle rule15 = new LineOfPuzzle(2, null, "Blue", null, null, null); PuzzleSet ruleSet = new PuzzleSet<>(); ruleSet.add(rule2); ruleSet.add(rule3); ruleSet.add(rule4); ruleSet.add(rule6); ruleSet.add(rule7); ruleSet.add(rule8); ruleSet.add(rule9); ruleSet.add(rule10); ruleSet.add(rule13); ruleSet.add(rule14); ruleSet.add(rule15); //Creating all possible combination of a puzzle line. //The maximum number of lines is 5^^6 (15625). //Each combination line is checked against a set of knowing facts, thus //only a small number of line result at the end. for (Integer orderId : Puzzle.orders) { for (String nation : Puzzle.nations) { for (String color : Puzzle.colors) { for (String animal : Puzzle.animals) { for (String drink : Puzzle.drinks) { for (String cigarette : Puzzle.cigarettes) { LineOfPuzzle pzlLine = new LineOfPuzzle(orderId, nation, color, animal, drink, cigarette); // Checking against a set of knowing facts if (ruleSet.accepts(pzlLine)){ // Adding rules of neighbors if (cigarette.equalsIgnoreCase("Blend") && (animal.equalsIgnoreCase("Cats") || drink.equalsIgnoreCase("Water"))) validLine = false; if (cigarette.equalsIgnoreCase("Dunhill") && animal.equalsIgnoreCase("Horse")) validLine = false; if (validLine){ puzzleTable.add(pzlLine); //set neighbors constraints if (color.equalsIgnoreCase("Green")){ pzlLine.setRightNeighbor(new LineOfPuzzle(null, null, "White", null, null, null)); } if (color.equalsIgnoreCase("White")){ pzlLine.setLeftNeighbor(new LineOfPuzzle(null, null, "Green", null, null, null)); } // if (animal.equalsIgnoreCase("Cats") && !cigarette.equalsIgnoreCase("Blend") ){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, null, null, "Blend")); } if (cigarette.equalsIgnoreCase("Blend") && !animal.equalsIgnoreCase("Cats")){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, "Cats", null, null)); } // if (drink.equalsIgnoreCase("Water") && !animal.equalsIgnoreCase("Cats") && !cigarette.equalsIgnoreCase("Blend")){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, null, null, "Blend")); } if (cigarette.equalsIgnoreCase("Blend") && !drink.equalsIgnoreCase("Water")){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, null, "Water", null)); } // if (animal.equalsIgnoreCase("Horse") && !cigarette.equalsIgnoreCase("Dunhill")){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, null, null, "Dunhill")); } if (cigarette.equalsIgnoreCase("Dunhill") && !animal.equalsIgnoreCase("Horse")){ pzlLine.addUndefindedNeighbor(new LineOfPuzzle(null, null, null, "Horse", null, null)); } } validLine = true; } } //cigarette end } //drinks end } //animal end } //color end } //nations end } //order end System.out.println("After general rule set validation, remains "+ puzzleTable.size() + " lines."); for (Iterator it = puzzleTable.iterator(); it.hasNext();){ validLine=true; LineOfPuzzle lineOfPuzzle = it.next(); if (lineOfPuzzle.hasLeftNeighbor()){ LineOfPuzzle neighbor = lineOfPuzzle.getLeftNeighbor(); if (neighbor.getOrder()<1 || neighbor.getOrder()>5){ validLine=false; it.remove(); } } if (validLine && lineOfPuzzle.hasRightNeighbor()){ LineOfPuzzle neighbor = lineOfPuzzle.getRightNeighbor(); if (neighbor.getOrder()<1 || neighbor.getOrder()>5){ it.remove(); } } } System.out.println("After removing out of bound neighbors, remains " + puzzleTable.size() + " lines."); //Setting left and right neighbors for (Iterator it = puzzleTable.iterator(); it.hasNext();) { LineOfPuzzle puzzleLine = it.next(); if (puzzleLine.hasUndefNeighbors()){ for (Iterator it1 = puzzleLine.getUndefNeighbors().iterator(); it1.hasNext();) { LineOfPuzzle leftNeighbor = it1.next(); LineOfPuzzle rightNeighbor = leftNeighbor.clone(); //make it left neighbor leftNeighbor.setOrder(puzzleLine.getOrder()-1); if (puzzleTable.contains(leftNeighbor)){ if (puzzleLine.hasLeftNeighbor()) puzzleLine.getLeftNeighbor().merge(leftNeighbor); else puzzleLine.setLeftNeighbor(leftNeighbor); } rightNeighbor.setOrder(puzzleLine.getOrder()+1); if (puzzleTable.contains(rightNeighbor)){ if (puzzleLine.hasRightNeighbor()) puzzleLine.getRightNeighbor().merge(rightNeighbor); else puzzleLine.setRightNeighbor(rightNeighbor); } } } } int iteration=1; int lastSize=0; //Recursively validate against neighbor rules while (puzzleTable.size()>5 && lastSize != puzzleTable.size()) { lastSize = puzzleTable.size(); puzzleTable.clearLineCountFlags(); recursiveSearch(null, puzzleTable, -1); ruleSet.clear(); // Assuming we'll get at leas one valid line each iteration, we create // a set of new rules with lines which have no more then one instance of same OrderId. for (int i = 1; i < 6; i++) { if (puzzleTable.getLineCountByOrderId(i)==1) ruleSet.addAll(puzzleTable.getSimilarLines(new LineOfPuzzle(i, null, null, null, null, null))); } for (Iterator it = puzzleTable.iterator(); it.hasNext();) { LineOfPuzzle puzzleLine = it.next(); if (!ruleSet.accepts(puzzleLine)) it.remove(); } // System.out.println("After " + iteration + " recursive iteration, remains " + puzzleTable.size() + " lines"); iteration+=1; } // Print the results System.out.println("-------------------------------------------"); if (puzzleTable.size()==5){ for (Iterator it = puzzleTable.iterator(); it.hasNext();) { LineOfPuzzle puzzleLine = it.next(); System.out.println(puzzleLine.getWholeLine()); } }else System.out.println("Sorry, solution not found!"); } // Recursively checks the input set to ensure each line has right neighbor. // Neighbors can be of three type, left, right or undefined. // Direction: -1 left, 0 undefined, 1 right private static boolean recursiveSearch(LineOfPuzzle pzzlNodeLine, PuzzleSet puzzleSet, int direction){ boolean validLeaf = false; boolean hasNeighbor = false; PuzzleSet puzzleSubSet = null; for (Iterator it = puzzleSet.iterator(); it.hasNext();) { LineOfPuzzle pzzlLeafLine = it.next(); validLeaf = false; hasNeighbor = pzzlLeafLine.hasNeighbor(direction); if (hasNeighbor){ puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(direction)); if (puzzleSubSet != null){ if (pzzlNodeLine !=null) validLeaf = puzzleSubSet.contains(pzzlNodeLine); else validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, -1*direction); } else validLeaf = false; } if (!validLeaf && pzzlLeafLine.hasNeighbor(-1*direction)){ hasNeighbor = true; if (hasNeighbor){ puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(-1*direction)); if (puzzleSubSet != null){ if (pzzlNodeLine !=null) validLeaf = puzzleSubSet.contains(pzzlNodeLine); else validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, direction); } else validLeaf = false; } } if (pzzlNodeLine != null && validLeaf) return validLeaf; if (pzzlNodeLine == null && hasNeighbor && !validLeaf){ it.remove(); } if (pzzlNodeLine == null){ if (hasNeighbor && validLeaf){ puzzleSet.riseLineCountFlags(pzzlLeafLine.getOrder()); } if (!hasNeighbor){ puzzleSet.riseLineCountFlags(pzzlLeafLine.getOrder()); } } } return validLeaf; } }