API Reference
This page provides a reference for the modules, functions, and types in ZebraPuzzles.jl.
Modules
ZebraPuzzles: The main module of the package.
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
ZebraPuzzle: Abstract type for any zebra puzzle.SolvedZebraPuzzle: A solved zebra puzzle.UnsolvedZebraPuzzle: An unsolved zebra puzzle.
Attribute: Abstract type for all attributes.Clue: Abstract type for all clues.DirectClue: A direct association between two attributes.PositionClue: A clue that specifies the position of an attribute.
ZebraPuzzles.ZebraPuzzles — Module
ZebraPuzzlesDefines 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.
ZebraPuzzles.EINSTEINS_ZEBRA — Constant
EINSTEINS_ZEBRA isa SolvedZebraPuzzleThis 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")]) == 1ZebraPuzzles.UNSOLVED_EINSTEINS_ZEBRA — Constant
UNSOLVED_EINSTEINS_ZEBRA isa UnsolvedZebraPuzzleThis 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")]) == 1ZebraPuzzles.AbsoluteDistance — Type
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
ZebraPuzzles.AbsolutePosition — Type
AbsolutePosition{A,P} <: PositionClueA clue that states the absolute position p::P of a subject with the attribute a::A.
ZebraPuzzles.Attribute — Type
AttributeRepresents 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.)
ZebraPuzzles.AttributeError — Type
AttributeError <: ExceptionThrown when an attribute is passed in the context of a puzzle, where this attribute is not valid.
Subtypes defined in ZebraPuzzles are AttributeTypeError and AttributeVariantError
ZebraPuzzles.AttributeExprs — Type
AttributeExprs{K,N,P}The IntExprs about the Attributes of a ZebraPuzzle that are used to solve the puzzle.
ZebraPuzzles.AttributeQuestion — Type
AttributeQuestion{A,S} <: QuestionA 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.
ZebraPuzzles.AttributeTypeError — Type
AttributeTypeError <: AttributeErrorAn error thrown when an attribute has an invalid type for the given puzzle
See also check_attrtype and AttributeVariantError
ZebraPuzzles.AttributeVariantError — Type
AttributeVariantError <: AttributeErrorAn error thrown when an attribute has a variant but the puzzle does not contain the variant of the attribute passed in the context of the puzzle.
See also check_attrvariant
ZebraPuzzles.Clue — Type
ClueSupertype of any clue (DirectClue, PositionClue, etc.) for a ZebraPuzzle.
ZebraPuzzles.ClueError — Type
ClueError <: ExceptionThrown when a clue is in conflict with puzzle rules or not compatible with current rules of a puzzle passed within the same context.
Subtypes defined in ZebraPuzzles are DuplicateClue and ImpliedClue
ZebraPuzzles.ConflictingClue — Type
ConflictingClue <: ClueErrorThrown when trying to add a clue that is in conflict with the clues that are already in the puzzle.
ZebraPuzzles.DirectClue — Type
DirectClue <: ClueA direct relationship of two attributes. I.e. PositiveClue if they belong together or NegativeClue if they dont.
ZebraPuzzles.DirectionClue — Type
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)
trueZebraPuzzles.Drink — Type
ZebraPuzzles.Drive — Type
Drive <: AttributeWhat does the subject drive.
ZebraPuzzles.DuplicateClue — Type
DuplicateClue <: ClueErrorAn error thrown when trying to add a clue that is already included in the puzzle.
See also check_duplicate
ZebraPuzzles.ExactRelativePosition — Type
ExactRelativePosition{A,B,D} <: RelativePosition{A,B}A clue that states "a::A is r::Int places in the direction of d::D from b::B".
ZebraPuzzles.Hat — Type
Hat <: AttributeHat that the subject wears.
ZebraPuzzles.House — Type
House <: AttributeThe house description that the subject lives in.
In most puzzles given by colour.
See also EINSTEINS_ZEBRA
ZebraPuzzles.ImpliedClue — Type
ImpliedClue <: ClueErrorAn error thrown when trying to add a clue that is implied by the rules and clues already included in the puzzle.
See also check_implied, MinimalityViolation
ZebraPuzzles.InvalidClue — Type
InvalidClue <: ClueErrorThrown when a rule is in conflict with the puzzle solution table of the SolvedZebraPuzzle
ZebraPuzzles.MinimalityViolation — Type
MinimalityViolation <: PuzzleErrorAn 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
ZebraPuzzles.NegativeClue — Type
const NegativeClue = DirectClue{ct_negative::ClueType}ZebraPuzzles.Person — Type
ZebraPuzzles.Pet — Type
ZebraPuzzles.PositionClue — Type
PositionClue <: ClueA clue about the position of a subject with a specific attribute or the relation of the positions of a pair of subjects.
Direct subtypes are AbsolutePosition, RelativePosition
ZebraPuzzles.PositionQuestion — Type
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.
ZebraPuzzles.PositiveClue — Type
const PositiveClue = DirectClue{ct_possitive::ClueType}ZebraPuzzles.PuzzleError — Type
PuzzleError <: ExceptionThrown when a puzzle would violate some optimality conditions by undergoing an operation.
Subtypes defined in ZebraPuzzles are MinimalityViolation
ZebraPuzzles.Question — Type
QuestionA question that can be asked about the solution of a ZebraPuzzle
Subtypes are AttributeQuestion, PositionQuestion
ZebraPuzzles.RelativePosition — Type
RelativePosition{A,B} <: PositionClueA clue about the relationship of the positions of two subjects with the attributes a::A and b::B.
Direct subtypes are ExactRelativePosition, DirectionClue
ZebraPuzzles.Smoke — Type
ZebraPuzzles.SolvedZebraPuzzle — Type
SolvedZebraPuzzle{K,N,Attrs} <: ZebraPuzzle{K,N,Attrs}A ZebraPuzzle that is created with a known solution table.
ZebraPuzzles.UnsolvablePuzzle — Type
UnsolvablePuzzle <: PuzzleErrorThrown when calling riddle on a puzzle that is not solvable.
ZebraPuzzles.UnsolvedPuzzle — Type
UnsolvedPuzzle <: PuzzleErrorThrown when show_solution or truthtable is called on an unsolved puzzle.
ZebraPuzzles.UnsolvedZebraPuzzle — Type
UnsolvedZebraPuzzle{K,N,Attrs} <: ZebraPuzzle{K,N,Attrs}A ZebraPuzzle that is created without a solution table. It has a known set of attributes and possibly a list of clues.
See also fill_clues!, solve!
ZebraPuzzles.ZebraPuzzle — Type
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 typeN: number of attributes of per subjectAttrs: attribute typesTuple{Attr1,Attr2,...}whereAttrican be e.g.Hat,Nationality,PersonorHouse. It has lengthN.
ZebraPuzzles.ZebraPuzzle — Method
ZebraPuzzle(attribute_variants...; clues=Clue[], questions=Question[])::UnsolvedZebraPuzzleConstruct 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 │
└──────────────────────────────┘ZebraPuzzles.ZebraPuzzle — Method
ZebraPuzzle(linked_attributes...; clues=Clue[], questions=Question[])::SolvedZebraPuzzleConstruct 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 │
└─────────────────────────────┘Base.rand — Method
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.
DataAPI.ncol — Method
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.
julia> ZP.ncol(ZP.EINSTEINS_ZEBRA)
5DataAPI.nrow — Method
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.
julia> ZP.nrow(ZP.EINSTEINS_ZEBRA)
5ZebraPuzzles.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")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")]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")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")]?ZebraPuzzles.answer — Method
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)
1ZebraPuzzles.answer — Method
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."ZebraPuzzles.attr_types — Method
attr_types(q::Question) => VectorGet 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
NationalityZebraPuzzles.attributes — Method
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"))ZebraPuzzles.attributes — Method
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")ZebraPuzzles.attributes — Method
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")ZebraPuzzles.attributes — Method
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")ZebraPuzzles.attributes — Method
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")ZebraPuzzles.attributes — Method
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")ZebraPuzzles.attrtypes — Method
attrtypes(puzzle)Get the attribute parameters of the puzzle
julia> ZP.attrtypes(ZP.EINSTEINS_ZEBRA)
5-element Vector{DataType}:
House
Nationality
Drink
Smoke
PetZebraPuzzles.check — Method
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.
ZebraPuzzles.check — Method
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.
ZebraPuzzles.check — Method
check(z::ZebraPuzzle, c::Clue)Check that the clue c is compatible with the puzzle z.
All subtypes of ZebraPuzzle must implement this interface
See also check_attrtype, check_attrvariant, check_minimal, check_implied
julia> all(ZP.check.(fill(ZP.EINSTEINS_ZEBRA), ZP.EINSTEINS_ZEBRA.clues; duplicates=false, minimal=false, implied=false))
trueZebraPuzzles.check — Method
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?
ZebraPuzzles.check_attrtype — Method
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]`
[...]ZebraPuzzles.check_attrvariant — Method
check_attrvariant(puzzle, s::Attribute; throw_error=true)::BoolCheck that the attribute variant s is included in the puzzle.
ZebraPuzzles.check_duplicate — Method
check_duplicate(puzzle, c::Clue; throw_error=true)::BoolCheck that the clue c is not already included in the puzzle.
ZebraPuzzles.check_implied — Function
check_implied(puzzle, c::Clue, exprs::AttributeExprs=AttributeExprs(puzzle); throw_error=true)::BoolCheck 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.
[...]ZebraPuzzles.check_minimal — Function
check_minimal(puzzle, c::Clue, exprs::AttributeExprs=AttributeExprs(puzzle); throw_error=true)::BoolCheck 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.
ZebraPuzzles.check_valid — Function
check_valid(z::UnsolvedZebraPuzzle, c::Clue, exprs=AttributeExprs(z); throw_error=true)::BoolValidate 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)
falseZebraPuzzles.check_valid — Method
check_valid(z::SolvedZebraPuzzle, c::Clue; throw_error=true)::BoolValidate the truth of the clue against the solution table of the puzzle.
ZebraPuzzles.col — Method
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)
:HouseZebraPuzzles.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")ZebraPuzzles.has_unique_solution — Function
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)
trueZebraPuzzles.id — Method
id(a::Attribute)Satisfiability variable name.
ZebraPuzzles.indexof — Method
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)
3ZebraPuzzles.issolved — Method
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)
trueZebraPuzzles.nattr — Method
nattr(z::ZebraPuzzle)Returns the total number of attributes of the puzzle z which is equal to nrow(z) * ncol(z)
julia> ZP.nattr(ZP.EINSTEINS_ZEBRA)
25ZebraPuzzles.nclue — Method
nclue(puzzle)Get the number of clues of the puzzle.
ZebraPuzzles.nquestion — Method
nquestion(puzzle)Get the number of questions of the puzzle.
ZebraPuzzles.phrase — Method
phrase(q::Question) => StringGet 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?"ZebraPuzzles.riddle — Method
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!
ZebraPuzzles.rules — Method
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_redZebraPuzzles.show_solution — Method
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 │
└──────────────────────────────────────────────────────────┘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.
[...]ZebraPuzzles.titlecase — Method
titlecase(s::String)Upper-case the first letter of the string
julia> ZP.titlecase("red house")
"Red house"
julia> ZP.titlecase("apple")
"Apple"ZebraPuzzles.toclue — Method
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)ZebraPuzzles.truthtable — Method
truthtable(puzzle::ZebraPuzzle)Get the truth table of the puzzle.
Throws a PuzzleError if the puzzle is not solved yet.
ZebraPuzzles.variants — Method
variants(A::Type{<:Attribute})Returns known variants of the attribute type A.
These are used for generating random puzzles.