A Julia package for creating, solving, and analyzing zebra puzzles. Provides a framework for defining puzzles with attributes, adding clues, and finding unique solutions.
using Pkg
Pkg.add("ZebraPuzzles")Define a classic zebra puzzle with attributes and clues:
using ZebraPuzzles
# Create a classic puzzle (Einstein's zebra)
puzzle = ZebraPuzzle(
Drink => ("coffee", "milk", "orange juice", "tea", "water"),
House => ("blue", "green", "ivory", "red", "yellow"),
Nationality => ("Englishman", "Japanese", "Spaniard", "Ukrainian", "Norwegian"),
Pet => ("dog", "horse", "snails", "zebra", "fox"),
Smoke => ("Chesterfields", "Lucky Strike", "Old Gold", "Parliaments", "Kools"),
)UnsolvedZebraPuzzle{5, 5, Tuple{Drink, House, Nationality, Pet, Smoke}} with no clues
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Drink coffee, milk, orange juice, tea, water β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β House blue, green, ivory, red, yellow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Nationality Englishman, Japanese, Spaniard, Ukrainian, Norwegian β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Pet dog, horse, snails, zebra, fox β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Smoke Chesterfields, Lucky Strike, Old Gold, Parliaments, Kools β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Add clues
add_clues!(puzzle, [
Clue(Nationality("Englishman"), House("red")), # The Englishman lives in the red house.
Clue(Nationality("Spaniard"), Pet("dog")), # The Spaniard owns the dog.
Clue(Drink("coffee"), House("green")), # Coffee is drunk in the green house.
Clue(Nationality("Ukrainian"), Drink("tea")), # The Ukrainian drinks tea.
ExactRelativePosition(House("green"), House("ivory"), 1), # The green house is immediately to the right of the ivory house.
Clue(Smoke("Old Gold"), Pet("snails")), # The Old Gold smoker owns snails.
Clue(Smoke("Kools"), House("yellow")), # Kools are smoked in the yellow house.
AbsolutePosition(Drink("milk"), 3, 5), # Milk is drunk in the middle house.
AbsolutePosition(Nationality("Norwegian"), 1, 5), # The Norwegian lives in the first house.
AbsoluteDistance(Smoke("Chesterfields"), Pet("fox"), 1), # The man who smokes Chesterfields lives in the house next to the man with the fox.
AbsoluteDistance(Smoke("Kools"), Pet("horse"), 1), # Kools are smoked in the house next to the house where the horse is kept.
Clue(Smoke("Lucky Strike"), Drink("orange juice")), # The Lucky Strike smoker drinks orange juice.
Clue(Nationality("Japanese"), Smoke("Parliaments")), # The Japanese smokes Parliaments.
AbsoluteDistance(Nationality("Norwegian"), House("blue"), 1), # The Norwegian lives next to the blue house.
])
riddle(puzzle)There are 5 houses.
- The Englishman lives in the red house.
- The Spaniard is the owner of the dog.
- The man who drinks coffee lives in the green house.
- The Ukrainian is a drinker of tea.
- The green house is immediately to the right of the ivory house.
- The man who smokes Old Gold is the owner of the snails.
- The smoker of Kools lives in the yellow house.
- The man who drinks milk lives in the middle house.
- The Norwegian lives in the first house.
- The man who smokes Chesterfields lives immediately next to the man who owns the fox.
- The smoker of Kools lives immediately next to the person who owns the horse.
- The man who smokes Lucky Strike drinks orange juice.
- The Japanese smokes Parliaments.
- The Norwegian lives immediately next to the blue house.
# Solve the puzzle
solve!(puzzle)
# View the solution
show_solution(puzzle)
- Random Generation: Generate random puzzles of specified sizes
- Solving Engine: Use satisfiability solving to find solutions
- Clue Validation: Check that added clues do not violate minimality (i.e., are not implied by existing clues)
- Natural Language Riddles: Convert puzzles to human-readable descriptions
solved_puzzle = ZebraPuzzle(
(House("yellow"), Nationality("Norwegian"), Drink("water"), Smoke("Kools"), Pet("fox")),
(House("blue"), Nationality("Ukrainian"), Drink("tea"), Smoke("Chesterfields"), Pet("horse")),
(House("red"), Nationality("Englishman"), Drink("milk"), Smoke("Old Gold"), Pet("snails")),
(House("ivory"), Nationality("Spaniard"), Drink("orange juice"), Smoke("Lucky Strike"), Pet("dog")),
(House("green"), Nationality("Japanese"), Drink("coffee"), Smoke("Parliaments"), Pet("zebra")),
)add_clue!(puzzle, AbsoluteDistance(Smoke("Chesterfields"), Pet("fox"), 1))
add_clue!(puzzle, ExactRelativePosition(House("green"), House("ivory"), 1))using Random
Random.seed!(42)
random_puzzle = rand(UnsolvedZebraPuzzle{3,4}) # 4 subjects, 3 attributes eachriddle(puzzle) # Returns human-readable clue descriptionsZebraPuzzle(): Create puzzles from attributes or a truth tableadd_clue!(),add_clues!(): Add clues to puzzlessolve!(): Find a solutionfill_clues!(): Fill to a minimal set of random clues for solubilityriddle(): Convert to natural languageshow_solution(): Display the solved puzzle
See the documentation for complete API reference and examples.
See CITATION.bib for the relevant reference(s).
