1/* 2 * DominoChain.java3 * 4 * Computer Science S-225 */6 7import java.util.Arrays;8 9/**10 * A domino chain solver11 * 12 * This class uses backtracking to find domino chain(s) of a desired length.13 */14public class DominoChain {15 16 /** The dominoes to choose from when making chains */17 private Domino[] dominoes;18 19 /** The desired length of the domino chain */20 private int targetLength;21 22 /** An array that keeps track of the current domino chain */23 private Domino[] chain;24 25 /** An array that keeps track of which dominoes are used */26 private boolean[] alreadyUsed;27 28 public DominoChain(Domino[] dominoes, int targetLength) {29 if (dominoes.length == 0) {30 throw new IllegalArgumentException("must be at least one domino");31 }32 if (targetLength <= 0) {33 throw new IllegalArgumentException("chain length must be > 0");34 }35 if (targetLength > dominoes.length) {36 throw new IllegalArgumentException(37 "cannot find chains longer than the number of dominoes"38 );39 }40 41 this.dominoes = dominoes;42 this.alreadyUsed = new boolean[dominoes.length];43 44 this.targetLength = targetLength;45 this.chain = new Domino[targetLength];46 }47 48 public boolean findSolution() {49 // Start building chain at index 050 return this.findSolution(0);51 }52 53 /**54 * Use recursive backtracking to find a chain. When a chain is found,55 * the recursion is stopped and the solution may be obtained using the56 * printSolution() instance method.57 */58 private boolean findSolution(int chainIndex) {59 if (chainIndex == this.targetLength) {60 return true;61 }62 63 for (int i = 0; i < this.dominoes.length; i++) {64 if (this.isValid(chainIndex, this.dominoes[i], i)) {65 this.applyValue(chainIndex, this.dominoes[i], i);66 if (this.findSolution(chainIndex + 1)) {67 return true;68 }69 this.removeValue(chainIndex, i);70 }71 72 if (!this.dominoes[i].isDouble()) {73 Domino flipped = this.dominoes[i].flipped();74 if (this.isValid(chainIndex, flipped, i)) {75 this.applyValue(chainIndex, flipped, i);76 if (this.findSolution(chainIndex + 1)) {77 return true;78 }79 this.removeValue(chainIndex, i);80 }81 }82 }83 84 // No chain possible with the available dominoes85 return false;86 }87 88 /**89 * Checks if a domino can be placed at the given chain index.90 */91 private boolean isValid(92 int chainIndex, Domino candidate, int candidateIndex93 ) {94 if (chainIndex == 0) {95 // Any domino is allowed to start the chain96 return true;97 }98 99 if (this.alreadyUsed[candidateIndex]) {100 // Cannot use the same domino more than once101 return false;102 }103 104 // The previous domino in the chain must match the next domino105 Domino previous = this.chain[chainIndex - 1];106 return previous.getRight() == candidate.getLeft();107 }108 109 private void applyValue(110 int chainIndex, Domino candidate, int candidateIndex111 ) {112 this.alreadyUsed[candidateIndex] = true;113 this.chain[chainIndex] = candidate;114 }115 116 private void removeValue(int chainIndex, int candidateIndex) {117 this.alreadyUsed[candidateIndex] = false;118 this.chain[chainIndex] = null;119 }120 121 /**122 * Use the recursive backtracking technique to find all possible chains.123 * When a chain is found, it is printed, and recursion continues to find124 * all other solutions.125 */126 public void findAllSolutions() {127 // Start building chains at index 0128 this.findAllSolutions(0);129 }130 131 private void findAllSolutions(int chainIndex) {132 if (chainIndex == this.targetLength) {133 this.printSolution();134 return;135 }136 137 for (int i = 0; i < this.dominoes.length; i++) {138 if (this.isValid(chainIndex, this.dominoes[i], i)) {139 this.applyValue(chainIndex, this.dominoes[i], i);140 this.findAllSolutions(chainIndex + 1);141 this.removeValue(chainIndex, i);142 }143 144 if (!this.dominoes[i].isDouble()) {145 Domino flipped = this.dominoes[i].flipped();146 if (this.isValid(chainIndex, flipped, i)) {147 this.applyValue(chainIndex, flipped, i);148 this.findAllSolutions(chainIndex + 1);149 this.removeValue(chainIndex, i);150 }151 }152 }153 }154 155 public void printSolution() {156 System.out.println(Arrays.toString(this.chain));157 }158 159 public static void main(String[] args) {160 Domino[] input = {161 new Domino(4, 2),162 new Domino(1, 0),163 new Domino(1, 4),164 new Domino(2, 0),165 new Domino(3, 2),166 new Domino(1, 3)167 };168 System.out.println("input: " + Arrays.toString(input));169 170 int targetLength = 5;171 DominoChain solver = new DominoChain(input, targetLength);172 173 if (solver.findSolution()) {174 System.out.println("Found one possible chain:");175 solver.printSolution();176 } else {177 System.out.println("No chain is possible.");178 }179 180 // Create a fresh solver object181 DominoChain solver2 = new DominoChain(input, targetLength);182 System.out.println("Find all possible chains:");183 solver2.findAllSolutions();184 }185}
Domino[] dominoes
Field defined at line 17.
int targetLength
Field defined at line 20.
Domino[] chain
Field defined at line 23.
boolean[] alreadyUsed
Field defined at line 26.
DominoChain(dominoes, targetLength)
Constructor defined at line 28.
findSolution()
Method defined at line 48.
findSolution(chainIndex)
Method defined at line 58.
isValid(chainIndex, candidate, candidateIndex)
Method defined at line 91.
applyValue(chainIndex, candidate, candidateIndex)
Method defined at line 109.
removeValue(chainIndex, candidateIndex)
Method defined at line 116.
findAllSolutions()
Method defined at line 126.
findAllSolutions(chainIndex)
Method defined at line 131.
printSolution()
Method defined at line 155.
main(args)
Method defined at line 159.