API Reference

This page provides a reference for the modules, functions, and types in ZebraPuzzles.jl.

Modules

Functions

  • add_clues!: Add clues to a puzzle.
  • add_clue!: Add a single clue to a puzzle.
  • attributes: Get the attributes of a puzzle.
  • riddle: Get the clues of a puzzle.
  • nclue: Get the number of clues in a puzzle.
  • nattr: Get the number of attributes in a puzzle.
  • solve!: Solve a zebra puzzle.

Types

ZebraPuzzles.ZebraPuzzlesModule
ZebraPuzzles

Defines logic puzzles of the zebra kind. This module has the logic to define, generate and solve these puzzles as well as phrase them in plain text and markdown.

source
ZebraPuzzles.EINSTEINS_ZEBRAConstant
EINSTEINS_ZEBRA isa SolvedZebraPuzzle

This is the famous zebra puzzle that gave zebra puzzles their name. It is said to be created by Albert Einstein. You can learn more about it at the Wikipedia Zebra Puzzle entry.

julia> ZP.EINSTEINS_ZEBRA
SolvedZebraPuzzle{5, 5, Tuple{House, Nationality, Drink, Smoke, Pet}} with 14 clues
┌──────────────────────────────────────────────────────────┐
│ House   Nationality      Smoke         Drink       Pet   │
├──────────────────────────────────────────────────────────┤
│ yellow   Norwegian       Kools         water       fox   │
├──────────────────────────────────────────────────────────┤
│  blue    Ukrainian   Chesterfields      tea       horse  │
├──────────────────────────────────────────────────────────┤
│  red    Englishman     Old Gold         milk      snails │
├──────────────────────────────────────────────────────────┤
│ ivory    Spaniard    Lucky Strike   orange juice   dog   │
├──────────────────────────────────────────────────────────┤
│ green    Japanese     Parliaments      coffee     zebra  │
└──────────────────────────────────────────────────────────┘

clues:
1) Nationality("Englishman") ⟹ House("red")
2) Nationality("Spaniard") ⟹ Pet("dog")
3) Drink("coffee") ⟹ House("green")
4) Nationality("Ukrainian") ⟹ Drink("tea")
5) Pos[House("green")] == Pos[House("ivory")] + 1
6) Smoke("Old Gold") ⟹ Pet("snails")
7) Smoke("Kools") ⟹ House("yellow")
8) Pos[Drink("milk")] == 3
9) Pos[Nationality("Norwegian")] == 1
10) abs(Pos[Smoke("Chesterfields")] - Pos[Pet("fox")]) == 1
11) abs(Pos[Smoke("Kools")] - Pos[Pet("horse")]) == 1
12) Smoke("Lucky Strike") ⟹ Drink("orange juice")
13) Nationality("Japanese") ⟹ Smoke("Parliaments")
14) abs(Pos[Nationality("Norwegian")] - Pos[House("blue")]) == 1
source
ZebraPuzzles.UNSOLVED_EINSTEINS_ZEBRAConstant
UNSOLVED_EINSTEINS_ZEBRA isa UnsolvedZebraPuzzle

This is the famous zebra puzzle that gave zebra puzzles their name. It is said to be created by Albert Einstein. You can learn more about it at the Wikipedia Zebra Puzzle entry.

The difference between this constant and EINSTEINS_ZEBRA is that this instance is not solved (does not contain the solution table).

See also EINSTEINS_ZEBRA

julia> ZP.UNSOLVED_EINSTEINS_ZEBRA
UnsolvedZebraPuzzle{5, 5, Tuple{Drink, House, Nationality, Pet, Smoke}} with 14 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 │
└────────────────────────────────────────────────────────────────────────┘

clues:
1) Nationality("Englishman") ⟹ House("red")
2) Nationality("Spaniard") ⟹ Pet("dog")
3) Drink("coffee") ⟹ House("green")
4) Nationality("Ukrainian") ⟹ Drink("tea")
5) Pos[House("green")] == Pos[House("ivory")] + 1
6) Smoke("Old Gold") ⟹ Pet("snails")
7) Smoke("Kools") ⟹ House("yellow")
8) Pos[Drink("milk")] == 3
9) Pos[Nationality("Norwegian")] == 1
10) abs(Pos[Smoke("Chesterfields")] - Pos[Pet("fox")]) == 1
11) abs(Pos[Smoke("Kools")] - Pos[Pet("horse")]) == 1
12) Smoke("Lucky Strike") ⟹ Drink("orange juice")
13) Nationality("Japanese") ⟹ Smoke("Parliaments")
14) abs(Pos[Nationality("Norwegian")] - Pos[House("blue")]) == 1
source
ZebraPuzzles.AbsoluteDistanceType
AbsoluteDistance{A,B} <: RelativePosition{A,B}

A clue that states "a::A is d places from b::B"

julia> AbsoluteDistance(House("red"), Drink("coffee"), 2) |> string |> print
abs(Pos[House("red")] - Pos[Drink("coffee")]) == 2
julia> ZP.check(ZP.EINSTEINS_ZEBRA, AbsoluteDistance(House("red"), Drink("coffee"), 2); implied=false, duplicates=false, minimal=false)
true
source
ZebraPuzzles.AttributeType
Attribute

Represents a possible attribute of a subject of type S.

The type parameters determine the phrase that is used for the clues and the subject strings used in the puzzle. S is the type of the subject that the Attribute can describe (Person, House, etc.)

source
ZebraPuzzles.AttributeQuestionType
AttributeQuestion{A,S} <: Question

A question about a specific attribute of type A of the subject type S, or position if S<:Int.

The question that an AttributeQuestion asks can be loosely stated as "What is the attribute with type A linked to the subject s::S?" An answer is the attribute a::A which is linked to the subject s::S.

source
ZebraPuzzles.ConflictingClueType
ConflictingClue <: ClueError

Thrown when trying to add a clue that is in conflict with the clues that are already in the puzzle.

source
ZebraPuzzles.DirectionClueType
DirectionClue{A,B,D} <: RelativePosition{A,B}

A clue that states "a::A is d::D of b::B".

julia> DirectionClue(House("red"), Drink("coffee"), ZP.d_left) |> string |> print
Pos[House("red")] < Pos[Drink("coffee")]
julia> ZP.check(ZP.EINSTEINS_ZEBRA, DirectionClue(House("red"), Drink("coffee"), ZP.d_left); implied=false, duplicates=false, minimal=false)
true
source
ZebraPuzzles.InvalidClueType
InvalidClue <: ClueError

Thrown when a rule is in conflict with the puzzle solution table of the SolvedZebraPuzzle

source
ZebraPuzzles.MinimalityViolationType
MinimalityViolation <: PuzzleError

An error thrown when the puzzle minimality would be violated by an operation.

Minimality of the puzzle means that there are no clues which could be discarded and still leave the puzzle solution intact and tractable.

See also check_minimal, ImpliedClue

source
ZebraPuzzles.PositionQuestionType
PositionQuestion{A}

A question about the position of the subject with the attribute a::A.

The question that a PositionQuestion asks can be loosely stated as "What is the position of the subject with the attribute a::A?" An answer is the position of the subject with the attribute a::A.

source
ZebraPuzzles.ZebraPuzzleType
ZebraPuzzle{K,N,Attrs}

Represents a Zebra Puzzle, a type of logic puzzle where one deduces relationships between different subjects and their attributes based on a set of clues.

Type Parameters

  • K: number of puzzle subjects and therefore also the number of distinct values of every attribute type
  • N: number of attributes of per subject
  • Attrs: attribute types Tuple{Attr1,Attr2,...} where Attri can be e.g. Hat, Nationality, Person or House. It has length N.
source
ZebraPuzzles.ZebraPuzzleMethod
ZebraPuzzle(attribute_variants...; clues=Clue[], questions=Question[])::UnsolvedZebraPuzzle

Construct an unsolved zebra puzzle. The puzzle holds the variants of the attributes and a solution table with missing values. Clues can be later added by add_clues!.

julia> ZebraPuzzle(
               House => ("red", "blue", "green"), 
               Person => ("Martin", "David", "Lucas"), 
               Pet => ("Weasel", "Cow", "Mammoth")
           )
UnsolvedZebraPuzzle{3, 3, Tuple{House, Person, Pet}} with no clues
┌──────────────────────────────┐
│ House     red, blue, green   │
├──────────────────────────────┤
│ Person  Martin, David, Lucas │
├──────────────────────────────┤
│  Pet    Weasel, Cow, Mammoth │
└──────────────────────────────┘
source
ZebraPuzzles.ZebraPuzzleMethod
ZebraPuzzle(linked_attributes...; clues=Clue[], questions=Question[])::SolvedZebraPuzzle

Construct a solved zebra puzzle with the solution table zpairs with no clues. Clues can be later added by add_clues!.

julia> ZebraPuzzle(
           (Person("Martin"), Hat("fedora"), Nationality("czech")),
           (Person("David"), Hat("beanie"), Nationality("spanish")),
           (Person("Lucas"), Hat("cap"), Nationality("german")),
           (Person("Lucy"), Hat("baret"), Nationality("american"))
       )
SolvedZebraPuzzle{4, 3, Tuple{Person, Hat, Nationality}} with no clues
┌─────────────────────────────┐
│ Nationality   Hat    Person │
├─────────────────────────────┤
│    czech     fedora  Martin │
├─────────────────────────────┤
│   spanish    beanie  David  │
├─────────────────────────────┤
│   german      cap    Lucas  │
├─────────────────────────────┤
│  american    baret    Lucy  │
└─────────────────────────────┘
source
Base.randMethod
Random.rand(UnsolvedZebraPuzzle{K,N}; clues=true)

Generate a random unsolved zebra puzzle with K subjects each of which has N attributes.

If clues is true, the puzzle is filled with a minimal set of random clues ensuring that it is solvable. If question is true, the puzzle is accompanied with a random question about the puzzle.

source
DataAPI.ncolMethod
ncol(z::ZebraPuzzle)

Returns the number of columns of the solution table for the puzzle z which is equal to the number of attributes linked to each of the puzzle subjects.

See also nrow, nattr

julia> ZP.ncol(ZP.EINSTEINS_ZEBRA)
5
source
DataAPI.nrowMethod
nrow(z::ZebraPuzzle)

Returns the number of rows of the solution table for the puzzle z which is equal to the number of subjects the puzzle is about.

See also ncol, nattr

julia> ZP.nrow(ZP.EINSTEINS_ZEBRA)
5
source
ZebraPuzzles.add_clue!Method
add_clue!(z::ZebraPuzzle, c::Clue; ischecked=false, kwargs...)

Adds a single clue c to the ZebraPuzzle z.

The clue is checked (See check) prior to its addition if ischecked == false. Any other keyword arguments are passed to check.

See also add_clues!

julia> z = ZP.SIMPLE_ZEBRA |> deepcopy;

julia> add_clue!(z, Clue(House("green"), Smoke("Parliaments")))
SolvedZebraPuzzle{3, 4, Tuple{House, Nationality, Smoke, Drink}} with 1 clues
┌────────────────────────────────────────────────┐
│ House  Nationality     Smoke         Drink     │
├────────────────────────────────────────────────┤
│  red   Englishman     Old Gold        tea      │
├────────────────────────────────────────────────┤
│ green   Japanese    Parliaments      coffee    │
├────────────────────────────────────────────────┤
│ ivory   Spaniard    Lucky Strike  orange juice │
└────────────────────────────────────────────────┘

clues:
1) House("green") ⟹ Smoke("Parliaments")
source
ZebraPuzzles.add_clue!Method
add_clue!(z::ZebraPuzzle)

Adds a randomly generated clue to the ZebraPuzzle z.

julia> z = ZP.SIMPLE_ZEBRA |> deepcopy;

julia> add_clue!(z)
SolvedZebraPuzzle{3, 4, Tuple{House, Nationality, Smoke, Drink}} with 1 clues
┌────────────────────────────────────────────────┐
│ House  Nationality     Smoke         Drink     │
├────────────────────────────────────────────────┤
│  red   Englishman     Old Gold        tea      │
├────────────────────────────────────────────────┤
│ green   Japanese    Parliaments      coffee    │
├────────────────────────────────────────────────┤
│ ivory   Spaniard    Lucky Strike  orange juice │
└────────────────────────────────────────────────┘

clues:
1) Pos[Nationality("Japanese")] < Pos[Smoke("Lucky Strike")]
source
ZebraPuzzles.add_clues!Method
add_clues!(z::ZebraPuzzle, cs::Vector{<:Clue}; ischecked=false, kwargs...)

Adds clues from cs to the ZebraPuzzle z.

The clues are checked (See check) prior to their addition if ischecked == false. Any other keyword arguments are passed to check.

julia> z = ZP.SIMPLE_ZEBRA |> deepcopy;

julia> add_clues!(z, [
            Clue(House("red"), Smoke("Old Gold")),
            Clue(Nationality("Spaniard"), Drink("orange juice"))
        ])
SolvedZebraPuzzle{3, 4, Tuple{House, Nationality, Smoke, Drink}} with 2 clues
┌────────────────────────────────────────────────┐
│ House  Nationality     Smoke         Drink     │
├────────────────────────────────────────────────┤
│  red   Englishman     Old Gold        tea      │
├────────────────────────────────────────────────┤
│ green   Japanese    Parliaments      coffee    │
├────────────────────────────────────────────────┤
│ ivory   Spaniard    Lucky Strike  orange juice │
└────────────────────────────────────────────────┘

clues:
1) House("red") ⟹ Smoke("Old Gold")
2) Nationality("Spaniard") ⟹ Drink("orange juice")
source
ZebraPuzzles.add_question!Method
add_question!(z::ZebraPuzzle, q::Question; ischecked=false)

Add a question q to the ZebraPuzzle z.

The question is checked (See check) prior to its addition if ischecked == false. Any other keyword arguments are passed to check.

julia> z = ZP.SIMPLE_ZEBRA |> deepcopy;

julia> add_question!(z, AttributeQuestion{Drink}(House("red")))
SolvedZebraPuzzle{3, 4, Tuple{House, Nationality, Smoke, Drink}} with no clues and 1 questions
┌────────────────────────────────────────────────┐
│ House  Nationality     Smoke         Drink     │
├────────────────────────────────────────────────┤
│  red   Englishman     Old Gold        tea      │
├────────────────────────────────────────────────┤
│ green   Japanese    Parliaments      coffee    │
├────────────────────────────────────────────────┤
│ ivory   Spaniard    Lucky Strike  orange juice │
└────────────────────────────────────────────────┘

questions:
1) Drink[House("red")]?
source
ZebraPuzzles.answerMethod
answer(q::Question, z::ZebraPuzzle)

Give the answer to the question q in the ZebraPuzzle z.

julia> aq = AttributeQuestion{Smoke}(Nationality("Englishman"));

julia> ZP.answer(aq, ZP.EINSTEINS_ZEBRA)
Smoke("Old Gold")

julia> pq = PositionQuestion(Drink("water"));

julia> ZP.answer(pq, ZP.EINSTEINS_ZEBRA)
1
source
ZebraPuzzles.answerMethod
answer(puzzle::ZebraPuzzle)

Give the phrases for the answers to the puzzle questions.

julia> puz = ZP.EINSTEINS_ZEBRA |> deepcopy;

julia> add_question!(puz); puz.questions[1]
PositionQuestion{House}(House("ivory"))

julia> ZP.answer(puz)
"The ivory house is in the fourth position."
source
ZebraPuzzles.attr_typesMethod
attr_types(q::Question) => Vector

Get the attribute types that the question q is about

Every subtype of Question must implement this interface.

julia> aq = AttributeQuestion{Smoke}(Nationality("Englishman"));
 
julia> ZP.attr_types(aq)
2-element Vector{DataType}:
 Smoke
 Nationality
source
ZebraPuzzles.attributesMethod
attributes(c::Clue)

Retrieve the attributes that are involved in a clue.

This is mainly for checking for the correctness of the clue.

julia> ZP.EINSTEINS_ZEBRA.clues[1] |> string |> print
Nationality("Englishman") ⟹ House("red")

julia> attributes(ZP.EINSTEINS_ZEBRA.clues[1])
(Nationality("Englishman"), House("red"))
source
ZebraPuzzles.attributesMethod
attributes(q::Question) => Vector{Attribute}

Get the attributes that the question q is about

Every subtype of Question must implement this interface.

julia> aq = AttributeQuestion{Smoke}(Nationality("Englishman"));

julia> ZP.attributes(aq)
1-element Vector{Nationality}:
 Nationality("Englishman")
source
ZebraPuzzles.attributesMethod
attributes(puzzle, s::Attribute)
attributes(puzzle, s::Not{Attribute})

Get the other attributes of the puzzle that are linked to the attribute s

julia> attributes(ZP.EINSTEINS_ZEBRA, Smoke("Old Gold"))
4-element Vector{ZebraPuzzles.Attribute}:
 House("red")
 Nationality("Englishman")
 Drink("milk")
 Pet("snails")

julia> attributes(ZP.EINSTEINS_ZEBRA, Not(House("red")))
20-element Vector{ZebraPuzzles.Attribute}:
 House("yellow")
 House("blue")
 House("ivory")
 House("green")
 Nationality("Norwegian")
 Nationality("Ukrainian")
 Nationality("Spaniard")
 Nationality("Japanese")
 Smoke("Kools")
 Smoke("Chesterfields")
 Smoke("Lucky Strike")
 Smoke("Parliaments")
 Drink("water")
 Drink("tea")
 Drink("orange juice")
 Drink("coffee")
 Pet("fox")
 Pet("horse")
 Pet("dog")
 Pet("zebra")
source
ZebraPuzzles.attributesMethod
attributes(puzzle::ZebraPuzzle, S::Not{<:Type{<:Attribute}})

Get the attributes of the puzzle other than the given type S.

Every subtype of ZebraPuzzle must implement this interface.

julia> attributes(ZP.EINSTEINS_ZEBRA, Not(Smoke))
20-element Vector{ZebraPuzzles.Attribute}:
 House("yellow")
 House("blue")
 House("red")
 House("ivory")
 House("green")
 Nationality("Norwegian")
 Nationality("Ukrainian")
 Nationality("Englishman")
 Nationality("Spaniard")
 Nationality("Japanese")
 Drink("water")
 Drink("tea")
 Drink("milk")
 Drink("orange juice")
 Drink("coffee")
 Pet("fox")
 Pet("horse")
 Pet("snails")
 Pet("dog")
 Pet("zebra")
source
ZebraPuzzles.attributesMethod
attributes(puzzle::ZebraPuzzle, S::Type{<:Attribute})

Get the attributes of the puzzle of the given type s.

Every subtype of ZebraPuzzle must implement this interface.

julia> attributes(ZP.EINSTEINS_ZEBRA, Smoke)
5-element Vector{Smoke}:
 Smoke("Kools")
 Smoke("Chesterfields")
 Smoke("Old Gold")
 Smoke("Lucky Strike")
 Smoke("Parliaments")
source
ZebraPuzzles.attributesMethod
attributes(puzzle::ZebraPuzzle)

Get all the attributes of the puzzle

Every subtype of ZebraPuzzle must implement this interface.

julia> attributes(ZP.EINSTEINS_ZEBRA)
25-element Vector{ZebraPuzzles.Attribute}:
 House("yellow")
 House("blue")
 House("red")
 House("ivory")
 House("green")
 Nationality("Norwegian")
 Nationality("Ukrainian")
 Nationality("Englishman")
 Nationality("Spaniard")
 Nationality("Japanese")
 ⋮
 Drink("tea")
 Drink("milk")
 Drink("orange juice")
 Drink("coffee")
 Pet("fox")
 Pet("horse")
 Pet("snails")
 Pet("dog")
 Pet("zebra")
source
ZebraPuzzles.attrtypesMethod
attrtypes(puzzle)

Get the attribute parameters of the puzzle

julia> ZP.attrtypes(ZP.EINSTEINS_ZEBRA)
5-element Vector{DataType}:
 House
 Nationality
 Drink
 Smoke
 Pet
source
ZebraPuzzles.checkMethod
check(puzzle::SolvedZebraPuzzle, c::Clue; <kwargs>)

Implementation of the check interface for ZebraPuzzle that includes a clue validity check against the solution table.

See also check_valid

Keyword Arguments

Keyword arguments control which of the checks are controlled for the clue.

  • duplicates=true – clue is not already included in the puzzle?
  • valid=true – clue is valid under the solution table?
  • types=true – clue has valid attribute types for the puzzle?
  • variants=true – clue has valid attribute variants ("names") for the puzzle?
  • implied=true – clue is not implied by the clues in the puzzle?
  • minimal=true – clue is needed for the solution? I.e. current clues do not suffice for getting the full solution.
source
ZebraPuzzles.checkMethod
check(puzzle::SolvedZebraPuzzle, c::Clue; <kwargs>)

Implementation of the check interface for ZebraPuzzle that includes a clue validity check against the solution table.

See also check_valid

Keyword Arguments

Keyword arguments control which of the checks are controlled for the clue.

  • duplicates=true – clue is not already included in the puzzle?
  • valid=true – clue is not in contradiction with the puzzle clues?
  • types=true – clue has valid attribute types for the puzzle?
  • variants=true – clue has valid attribute variants ("names") for the puzzle?
  • implied=true – clue is not implied by the clues in the puzzle?
  • minimal=true – clue is needed for the solution? I.e. current clues do not suffice for getting the full solution.
source
ZebraPuzzles.checkMethod
check(z::ZebraPuzzle, q::Question, types=true, variants=true)

Implementation of the check interface for ZebraPuzzle that checks the questions q for valid types and attribute variants.

Keyword Arguments

Keyword arguments control which of the checks are controlled for the clue.

  • types=true – question has valid attribute types for the puzzle?
  • variants=true – question has valid attribute variants ("names") for the puzzle?
source
ZebraPuzzles.check_attrtypeMethod
check_attrtype(puzzle, s::Type{<:Attribute}; throw_error=true)::Bool
check_attrtype(puzzle, s::Attribute)

Check that the attribute of type s is a valid attribute type in the puzzle

julia> ZP.check_attrtype(ZP.EINSTEINS_ZEBRA, House)
true

julia> ZP.check_attrtype(ZP.EINSTEINS_ZEBRA, House("red"))
true

julia> ZP.check_attrtype(ZP.EINSTEINS_ZEBRA, House("pink")) # !!! This only checks the type !!!
true

julia> ZP.check_attrtype(ZP.EINSTEINS_ZEBRA, Hat)
ERROR: AttributeTypeError: attribute type `Hat` is invalid for the given puzzle. Valid types are `DataType[House, Nationality, Drink, Smoke, Pet]`
[...]
source
ZebraPuzzles.check_attrvariantMethod
check_attrvariant(puzzle, s::Attribute; throw_error=true)::Bool

Check that the attribute variant s is included in the puzzle.

Warning

Assumes that the attribute type typeof(s) is valid for the puzzle.

source
ZebraPuzzles.check_impliedFunction
check_implied(puzzle, c::Clue, exprs::AttributeExprs=AttributeExprs(puzzle); throw_error=true)::Bool

Check that the clue c is not implied by the rules and clues already included in the puzzle.

julia> z = ZebraPuzzle(Drink => ("coffee", "tea"), Smoke => ("Old Gold", "Chesterfields"), House => ("green", "red"));

julia> ZP.add_clue!(z, Clue(House("red"), Smoke("Old Gold")));

julia> ZP.add_clue!(z, Clue(Smoke("Old Gold"), Drink("tea")))
UnsolvedZebraPuzzle{2, 3, Tuple{Drink, Smoke, House}} with 2 clues
┌────────────────────────────────┐
│ Drink        coffee, tea       │
├────────────────────────────────┤
│ Smoke  Old Gold, Chesterfields │
├────────────────────────────────┤
│ House        green, red        │
└────────────────────────────────┘

clues:
1) House("red") ⟹ Smoke("Old Gold")
2) Smoke("Old Gold") ⟹ Drink("tea")

julia> ZP.check_implied(z, AbsolutePosition(House("red"), 1)) # independent clue
true

julia> ZP.check_implied(z, Clue(Drink("tea"), House("red"))) # (red => old gold) ∧ (old gold => tea) => (red => tea)
ERROR: ImpliedClue: clue Drink("tea") ⟹ House("red") is implied by the rules and clues already included in the puzzle.
[...]
source
ZebraPuzzles.check_minimalFunction
check_minimal(puzzle, c::Clue, exprs::AttributeExprs=AttributeExprs(puzzle); throw_error=true)::Bool

Check that the clue c is not breaking the minimality of the puzzle clue set. I.e. that adding the additional clue is not necessary for finding the solution.

source
ZebraPuzzles.check_validFunction
check_valid(z::UnsolvedZebraPuzzle, c::Clue, exprs=AttributeExprs(z); throw_error=true)::Bool

Validate the truth of the clue under the assertion of puzzle rules and the current puzzle clues.

julia> puzzle = ZP.UNSOLVED_EINSTEINS_ZEBRA |> deepcopy;

julia> empty!(puzzle.clues)
Clue[]

julia> add_clue!(puzzle, Clue(House("blue"), Pet("horse")))
UnsolvedZebraPuzzle{5, 5, Tuple{Drink, House, Nationality, Pet, Smoke}} with 1 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 │
└────────────────────────────────────────────────────────────────────────┘

clues:
1) House("blue") ⟹ Pet("horse")

julia> ZP.check_valid(puzzle, Clue(House("red"), Pet("horse")))
ERROR: ConflictingClue: clue House("red") ⟹ Pet("horse") is in conflict with the current rules/clues in the puzzle.
[...]

julia> ZP.check_valid(puzzle, Clue(House("blue"), Pet("horse")))
true

julia> ZP.check_valid(puzzle, Clue(House("ivory"), Pet("horse")); throw_error=false)
false
source
ZebraPuzzles.check_validMethod
check_valid(z::SolvedZebraPuzzle, c::Clue; throw_error=true)::Bool

Validate the truth of the clue against the solution table of the puzzle.

Warning

It does not check against the clues included in the puzzle.

source
ZebraPuzzles.colMethod
col(S::Type{<:Attribute})
col(s::Attribute)

Get the name of the column of attribute s / of the type S in the solution table.

julia> ZP.col(House("red"))
:House

julia> ZP.col(House)
:House
source
ZebraPuzzles.fill_clues!Method
fill_clues!(puzzle::ZebraPuzzle)

Add random clues until the puzzle has a minimal set and ensures a unique solution.

julia> z = ZebraPuzzle(
           Drink => ("coffee", "tea"),
           Smoke => ("Old Gold", "Chesterfields"), 
           House => ("green", "red")
       );

julia> ZP.fill_clues!(z)
UnsolvedZebraPuzzle{2, 3, Tuple{Drink, Smoke, House}} with 3 clues
┌────────────────────────────────┐
│ Drink        coffee, tea       │
├────────────────────────────────┤
│ Smoke  Old Gold, Chesterfields │
├────────────────────────────────┤
│ House        green, red        │
└────────────────────────────────┘

clues:
1) Pos[Drink("coffee")] > Pos[Drink("tea")]
2) Pos[House("green")] == 2
3) Drink("tea") ⟹ ¬Smoke("Chesterfields")
source
ZebraPuzzles.has_unique_solutionFunction
has_unique_solution(z::ZebraPuzzle)

Check whether the clues of the puzzle lead to one unique solution.

julia> ZP.has_unique_solution(ZP.UNSOLVED_EINSTEINS_ZEBRA)
true
source
ZebraPuzzles.indexofMethod
indexof(z::ZebraPuzzle, A::Type{<:Attribute})
indexof(z::ZebraPuzzle, a::Attribute)

Return the internal index of the attribute / attribute type

This internal index is used indexing into the AttributeExprs of the puzzle, which holds the Satisfiability.jl variable used for solving the puzzle.

Every subtype of ZebraPuzzle must implement this interface.

julia> ZP.indexof(ZP.EINSTEINS_ZEBRA, Smoke("Chesterfields"))
(2, 3)

julia> ZP.indexof(ZP.EINSTEINS_ZEBRA, Smoke)
3
source
ZebraPuzzles.issolvedMethod
issolved(puzzle::UnsolvedZebraPuzzle)

Check whether the puzzle was solved by solve! and has a solution without missing keys.

julia> z = ZP.UNSOLVED_EINSTEINS_ZEBRA |> deepcopy;

julia> ZP.issolved(z)
false

julia> solve!(z);

julia> ZP.issolved(z)
true
source
ZebraPuzzles.nattrMethod
nattr(z::ZebraPuzzle)

Returns the total number of attributes of the puzzle z which is equal to nrow(z) * ncol(z)

See also nrow, ncol

julia> ZP.nattr(ZP.EINSTEINS_ZEBRA)
25
source
ZebraPuzzles.phraseMethod
phrase(q::Question) => String

Get a string representation of the question q

Every subtype of Question must implement this interface

julia> aq = AttributeQuestion{Smoke}(Nationality("Englishman"));

julia> ZP.phrase(aq)
"What cigarette brand does the Englishman prefer?"
source
ZebraPuzzles.riddleMethod
riddle(puzzle::ZebraPuzzle; <kwargs>)

Return the string of the zebra puzzle introduction and clues in natural language.

The string uses markdown for bullet points or numbers and prints the Markdown using the context IO.

If introduction=false is (default true) the introduction such as "There are five houses." is skipped. If bulletpoints=true, the clues are prefixed with "- " and if numbers=true the clues are prefixed with "i)". If both are false the clues only have a space between them.

If quiet=true the riddle is not printed but only returned as a string.

See also solve!

source
ZebraPuzzles.rulesMethod
rules(exprs::AttributeExprs)::BoolExpr
rules(puzzle::ZebraPuzzle)::Tuple{AttributeExprs, BoolExpr}

Generate the zebra puzzle Satisfiability.jl rules for the attributes return the rule assertion BoolExpr. If a ZebraPuzzle is passed, it first generates the AttributeExprs and then returns the (exprs, rules) tuple.

julia> z = ZebraPuzzle(Drink => ("coffee", "tea"), House => ("green", "red"))
UnsolvedZebraPuzzle{2, 2, Tuple{Drink, House}} with no clues
┌────────────────────┐
│ Drink  coffee, tea │
├────────────────────┤
│ House  green, red  │
└────────────────────┘


julia> exprs, rules = ZP.rules(z);

julia> rules
4-element Vector{Satisfiability.BoolExpr}:
 and_4a3b8ce4f0c5932b
 | leq_13a07d362557ecbd
 |  | const_1 = 1
 |  | Drink_tea
 | leq_5f49e791afe246a5
 |  | const_1 = 1
 |  | House_green
 | leq_a27b1741a1f9008e
 |  | const_1 = 1
 |  | House_red
 | leq_e94b7d8032d90182
 |  | const_1 = 1
 |  | Drink_coffee

 and_9b58b2ca1f5f8553
 | leq_20b3312716ae8085
 |  | House_red
 |  | const_2 = 2
 | leq_2349e5270bfc6484
 |  | Drink_tea
 |  | const_2 = 2
 | leq_4674d87e645a7ee8
 |  | Drink_coffee
 |  | const_2 = 2
 | leq_e343fa1b3fccf18b
 |  | House_green
 |  | const_2 = 2

 distinct_f63a38a3190ef4f4
 | Drink_coffee
 | Drink_tea

 distinct_7f6fa8abcc538373
 | House_green
 | House_red
source
ZebraPuzzles.show_solutionMethod
show_solution(puzzle::UnsolvedZebraPuzzle)

If the puzzle was solved by solve!, converts the puzzle to a SolvedZebraPuzzle shows it.

julia> puzzle = ZP.UNSOLVED_EINSTEINS_ZEBRA |> deepcopy;

julia> ZP.show_solution(puzzle)
ERROR: UnsolvedPuzzle: puzzle is not solved
[...]

julia> solve!(puzzle);

julia> ZP.show_solution(puzzle)
SolvedZebraPuzzle{5, 5, NTuple{5, Union{Missing, ZebraPuzzles.Attribute}}}
┌──────────────────────────────────────────────────────────┐
│    Drink      House   Nationality   Pet        Smoke     │
├──────────────────────────────────────────────────────────┤
│    water      yellow   Norwegian    fox        Kools     │
├──────────────────────────────────────────────────────────┤
│     tea        blue    Ukrainian   horse   Chesterfields │
├──────────────────────────────────────────────────────────┤
│     milk       red    Englishman   snails    Old Gold    │
├──────────────────────────────────────────────────────────┤
│ orange juice  ivory    Spaniard     dog    Lucky Strike  │
├──────────────────────────────────────────────────────────┤
│    coffee     green    Japanese    zebra    Parliaments  │
└──────────────────────────────────────────────────────────┘
source
ZebraPuzzles.solve!Method
solve!(puzzle::UnsolvedZebraPuzzle)

Solve the zebra puzzle and fill in the solution table.

See also show_solution

julia> puz = ZP.UNSOLVED_EINSTEINS_ZEBRA |> deepcopy;

julia> solve!(puz);

julia> puz |> ZP.show_solution
SolvedZebraPuzzle{5, 5, NTuple{5, Union{Missing, ZebraPuzzles.Attribute}}}
┌──────────────────────────────────────────────────────────┐
│    Drink      House   Nationality   Pet        Smoke     │
├──────────────────────────────────────────────────────────┤
│    water      yellow   Norwegian    fox        Kools     │
├──────────────────────────────────────────────────────────┤
│     tea        blue    Ukrainian   horse   Chesterfields │
├──────────────────────────────────────────────────────────┤
│     milk       red    Englishman   snails    Old Gold    │
├──────────────────────────────────────────────────────────┤
│ orange juice  ivory    Spaniard     dog    Lucky Strike  │
├──────────────────────────────────────────────────────────┤
│    coffee     green    Japanese    zebra    Parliaments  │
└──────────────────────────────────────────────────────────┘

If the puzzle is not solvable an error is thrown

julia> puz = ZP.UNSOLVED_EINSTEINS_ZEBRA |> deepcopy;

julia> pop!(puz.clues) |> ZP.phrase
"The Norwegian lives immediately next to the blue house."

julia> push!(puz.clues, ExactRelativePosition(Nationality("Norwegian"), House("yellow"), 1));

julia> solve!(puz);
ERROR: Failed to find a solution. Got `UNSAT` from the solver.
[...]
source
ZebraPuzzles.titlecaseMethod
titlecase(s::String)

Upper-case the first letter of the string

julia> ZP.titlecase("red house")
"Red house"

julia> ZP.titlecase("apple")
"Apple"
source
ZebraPuzzles.toclueMethod
toclue(q::Question, puz::ZebraPuzzle)

Get the clue that corresponds to the question q in the puzzle.

Throws an UnsolvedPuzzle error if the puzzle is not solved.

julia> ZP.toclue(AttributeQuestion{Smoke}(Nationality("Englishman")), ZP.EINSTEINS_ZEBRA)
PositiveClue{Nationality, Smoke}(Nationality("Englishman"), Smoke("Old Gold"))

julia> ZP.toclue(PositionQuestion(Smoke("Parliaments")), ZP.EINSTEINS_ZEBRA)
AbsolutePosition{Smoke, Int64}(Smoke("Parliaments"), 5, 5)
source
ZebraPuzzles.truthtableMethod
truthtable(puzzle::ZebraPuzzle)

Get the truth table of the puzzle.

Throws a PuzzleError if the puzzle is not solved yet.

source
ZebraPuzzles.variantsMethod
variants(A::Type{<:Attribute})

Returns known variants of the attribute type A.

These are used for generating random puzzles.

source