| 5 | 5 | |
| 6 | 6 | export class ZebraPuzzle { |
| 7 | 7 | constructor() { |
| 8 | | throw new Error('Remove this line and implement the function'); |
| 8 | this.houses = [1, 2, 3, 4, 5]; |
| 9 | this.colors = ['red', 'green', 'ivory', 'yellow', 'blue']; |
| 10 | this.nationalities = ['Englishman', 'Spaniard', 'Ukrainian', 'Norwegian', 'Japanese']; |
| 11 | this.pets = ['dog', 'snails', 'fox', 'horse', 'zebra']; |
| 12 | this.drinks = ['coffee', 'tea', 'milk', 'orange juice', 'water']; |
| 13 | this.hobbies = ['dancing', 'painting', 'reading', 'football', 'chess']; |
| 14 | |
| 15 | // Generate all possible permutations and find the solution |
| 16 | this.solution = this.solve(); |
| 17 | } |
| 18 | |
| 19 | // Helper function to generate all permutations of an array |
| 20 | *permute(arr) { |
| 21 | if (arr.length === 1) { |
| 22 | yield arr; |
| 23 | } else { |
| 24 | for (let i = 0; i < arr.length; i++) { |
| 25 | const rest = arr.slice(0, i).concat(arr.slice(i + 1)); |
| 26 | for (const subperm of this.permute(rest)) { |
| 27 | yield [arr[i]].concat(subperm); |
| 28 | } |
| 29 | } |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | // Check if a configuration satisfies all constraints |
| 34 | isValidSolution(config) { |
| 35 | const [colors, nationalities, pets, drinks, hobbies] = config; |
| 36 | |
| 37 | // Constraint 2: The Englishman lives in the red house |
| 38 | // Edge Case: Englishman not in red house |
| 39 | const englishmanIndex = nationalities.indexOf('Englishman'); |
| 40 | if (colors[englishmanIndex] !== 'red') return false; |
| 41 | |
| 42 | // Constraint 3: The Spaniard owns the dog |
| 43 | // Edge Case: Spaniard doesn't own dog |
| 44 | const spaniardIndex = nationalities.indexOf('Spaniard'); |
| 45 | if (pets[spaniardIndex] !== 'dog') return false; |
| 46 | |
| 47 | // Constraint 4: Coffee drinker lives in the green house |
| 48 | // Edge Case: Coffee drinker not in green house |
| 49 | const greenIndex = colors.indexOf('green'); |
| 50 | if (drinks[greenIndex] !== 'coffee') return false; |
| 51 | |
| 52 | // Constraint 5: The Ukrainian drinks tea |
| 53 | // Edge Case: Ukrainian doesn't drink tea |
| 54 | const ukrainianIndex = nationalities.indexOf('Ukrainian'); |
| 55 | if (drinks[ukrainianIndex] !== 'tea') return false; |
| 56 | |
| 57 | // Constraint 6: The green house is immediately to the right of the ivory house |
| 58 | // Edge Case: Green house not immediately right of ivory house |
| 59 | const ivoryIndex = colors.indexOf('ivory'); |
| 60 | const greenIndex2 = colors.indexOf('green'); |
| 61 | if (ivoryIndex + 1 !== greenIndex2) return false; |
| 62 | |
| 63 | // Constraint 7: The snail owner likes to go dancing |
| 64 | // Edge Case: Snail owner doesn't like dancing |
| 65 | const snailIndex = pets.indexOf('snails'); |
| 66 | if (hobbies[snailIndex] !== 'dancing') return false; |
| 67 | |
| 68 | // Constraint 8: The person in the yellow house is a painter |
| 69 | // Edge Case: Person in yellow house is not a painter |
| 70 | const yellowIndex = colors.indexOf('yellow'); |
| 71 | if (hobbies[yellowIndex] !== 'painting') return false; |
| 72 | |
| 73 | // Constraint 9: The person in the middle house drinks milk |
| 74 | // Edge Case: Person in middle house doesn't drink milk |
| 75 | if (drinks[2] !== 'milk') return false; |
| 76 | |
| 77 | // Constraint 10: The Norwegian lives in the first house |
| 78 | // Edge Case: Norwegian not in first house |
| 79 | if (nationalities[0] !== 'Norwegian') return false; |
| 80 | |
| 81 | // Constraint 11: The person who enjoys reading lives next to the person with the fox |
| 82 | // Edge Case: Reader not next to fox owner |
| 83 | const readingIndex = hobbies.indexOf('reading'); |
| 84 | const foxIndex = pets.indexOf('fox'); |
| 85 | if (Math.abs(readingIndex - foxIndex) !== 1) return false; |
| 86 | |
| 87 | // Constraint 12: The painter's house is next to the house with the horse |
| 88 | // Edge Case: Painter not next to horse owner |
| 89 | const paintingIndex = hobbies.indexOf('painting'); |
| 90 | const horseIndex = pets.indexOf('horse'); |
| 91 | if (Math.abs(paintingIndex - horseIndex) !== 1) return false; |
| 92 | |
| 93 | // Constraint 13: The person who plays football drinks orange juice |
| 94 | // Edge Case: Football player doesn't drink orange juice |
| 95 | const footballIndex = hobbies.indexOf('football'); |
| 96 | if (drinks[footballIndex] !== 'orange juice') return false; |
| 97 | |
| 98 | // Constraint 14: The Japanese person plays chess |
| 99 | // Edge Case: Japanese person doesn't play chess |
| 100 | const japaneseIndex = nationalities.indexOf('Japanese'); |
| 101 | if (hobbies[japaneseIndex] !== 'chess') return false; |
| 102 | |
| 103 | // Constraint 15: The Norwegian lives next to the blue house |
| 104 | // Edge Case: Norwegian not next to blue house |
| 105 | const norwegianIndex = nationalities.indexOf('Norwegian'); |
| 106 | const blueIndex = colors.indexOf('blue'); |
| 107 | if (Math.abs(norwegianIndex - blueIndex) !== 1) return false; |
| 108 | |
| 109 | return true; |
| 110 | } |
| 111 | |
| 112 | solve() { |
| 113 | // Generate all permutations for each category |
| 114 | const colorPerms = Array.from(this.permute(this.colors)); |
| 115 | const nationalityPerms = Array.from(this.permute(this.nationalities)); |
| 116 | const petPerms = Array.from(this.permute(this.pets)); |
| 117 | const drinkPerms = Array.from(this.permute(this.drinks)); |
| 118 | const hobbyPerms = Array.from(this.permute(this.hobbies)); |
| 119 | |
| 120 | // Try all combinations |
| 121 | for (const colors of colorPerms) { |
| 122 | for (const nationalities of nationalityPerms) { |
| 123 | // Apply early constraints to reduce search space |
| 124 | // Constraint 10: Norwegian in first house |
| 125 | // Edge Case: Norwegian not in first position |
| 126 | if (nationalities[0] !== 'Norwegian') continue; |
| 127 | |
| 128 | // Constraint 9: Milk drinker in middle house |
| 129 | // Edge Case: Milk not in middle position |
| 130 | for (const drinks of drinkPerms) { |
| 131 | if (drinks[2] !== 'milk') continue; |
| 132 | |
| 133 | for (const pets of petPerms) { |
| 134 | for (const hobbies of hobbyPerms) { |
| 135 | const config = [colors, nationalities, pets, drinks, hobbies]; |
| 136 | if (this.isValidSolution(config)) { |
| 137 | return config; |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | // Edge Case: No valid solution found |
| 146 | throw new Error('No solution found'); |
| 9 | 147 | } |
| 10 | 148 | |
| 11 | 149 | waterDrinker() { |
| 12 | | throw new Error('Remove this line and implement the function'); |
| 150 | const [, nationalities, , drinks] = this.solution; |
| 151 | const waterIndex = drinks.indexOf('water'); |
| 152 | return nationalities[waterIndex]; |
| 13 | 153 | } |
| 14 | 154 | |
| 15 | 155 | zebraOwner() { |
| 16 | | throw new Error('Remove this line and implement the function'); |
| 156 | const [, nationalities, pets] = this.solution; |
| 157 | const zebraIndex = pets.indexOf('zebra'); |
| 158 | return nationalities[zebraIndex]; |
| 17 | 159 | } |
| 18 | 160 | } |
| 161 | |
| 162 | // Handled Edge Cases: Englishman not in red house, Spaniard doesn't own dog, Coffee drinker not in green house, Ukrainian doesn't drink tea, Green house not immediately right of ivory house, Snail owner doesn't like dancing, Person in yellow house is not a painter, Person in middle house doesn't drink milk, Norwegian not in first house, Reader not next to fox owner, Painter not next to horse owner, Football player doesn't drink orange juice, Japanese person doesn't play chess, Norwegian not next to blue house, No valid solution found, Norwegian not in first position, Milk not in middle position |