Skip to content

ZebraPuzzles.jl is a Julia package for defining and solving zebra puzzles. It uses a Satisfiability Modulo Theories (SMT) to model and efficiently solve these logic puzzles.

License

Notifications You must be signed in to change notification settings

kunzaatko/ZebraPuzzles.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

48 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ZebraPuzzles.jl Logo: A zebra with Einsteins hair in julia colours

ZebraPuzzles.jl πŸ¦“

Stable Dev Build Status Coverage Code Style: Blue ColPrac: Contributor's Guide on Collaborative Practices for Community Packages Aqua

A Julia package for creating, solving, and analyzing zebra puzzles. Provides a framework for defining puzzles with attributes, adding clues, and finding unique solutions.

Installation

using Pkg
Pkg.add("ZebraPuzzles")

Quick Start

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)

Features

  • 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

Usage Examples

Creating a Solved Puzzle

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")),
)

Adding Position-Based Clues

add_clue!(puzzle, AbsoluteDistance(Smoke("Chesterfields"), Pet("fox"), 1))
add_clue!(puzzle, ExactRelativePosition(House("green"), House("ivory"), 1))

Generating Random Puzzles

using Random
Random.seed!(42)
random_puzzle = rand(UnsolvedZebraPuzzle{3,4})  # 4 subjects, 3 attributes each

Converting to Natural Language

riddle(puzzle)  # Returns human-readable clue descriptions

API Overview

  • ZebraPuzzle(): Create puzzles from attributes or a truth table
  • add_clue!(), add_clues!(): Add clues to puzzles
  • solve!(): Find a solution
  • fill_clues!(): Fill to a minimal set of random clues for solubility
  • riddle(): Convert to natural language
  • show_solution(): Display the solved puzzle

See the documentation for complete API reference and examples.

Citing

See CITATION.bib for the relevant reference(s).

About

ZebraPuzzles.jl is a Julia package for defining and solving zebra puzzles. It uses a Satisfiability Modulo Theories (SMT) to model and efficiently solve these logic puzzles.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages