## Who Owns The Zebra?

### June 16, 2009

This famous puzzle was first published by Life magazine on December 17, 1962. It has been variously attributed to both Albert Einstein and Lewis Carroll, but the true author is not known. There are several versions; this is the original from Life:

1 There are five houses.

2 The Englishman lives in the red house.

3 The Spaniard owns the dog.

4 Coffee is drunk in the green house.

5 The Ukrainian drinks tea.

6 The green house is immediately to the right of the ivory house.

7 The Old Gold smoker owns snails.

8 Kools are smoked in the yellow house.

9 Milk is drunk in the middle house.

10 The Norwegian lives in the first house.

11 The man who smokes Chesterfields lives in the house next to the man with the fox.

12 Kools are smoked in the house next to the house where the horse is kept.

13 The Lucky Strike smoker drinks orange juice.

14 The Japanese smokes Parliaments.

15 The Norwegian lives next to the blue house.

In the interest of clarity, it must be added that each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and smoke different brands of American cigarettes.

Your task is to write a program to solve the puzzle and determine: Who drinks water? Who owns the zebra? When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 6 Responses to “Who Owns The Zebra?”

1. Remco Niemeijer said

There’s a slight error in your code: you have the ivory house to the right of the green house instead of the other way round. Flipping the constraint for number 6 around should fix it.

2. [...] Praxis – Who Owns The Zebra? By Remco Niemeijer In Today’s Programming Praxis problem we have to solve a logic puzzle. The provided solution uses a 182-line [...]

3. Remco Niemeijer said

```import Data.List
import qualified Data.Map as M

type Grid = M.Map String (M.Map Int [String])

data Constraint = Link (String, String) (String, String)
| NextTo (String, String) (String, String)
| RightOf (String, String) (String, String)
deriving Eq

type Solver = ([Constraint], Grid)

addConstraint :: Constraint -> Solver -> Solver
addConstraint c (cs, g) = (c : cs, g)

removeIf :: (String, String) -> (String, String) ->
[String -> String -> Int -> Grid -> Bool] -> Grid -> Grid
removeIf (f1, v1) (f2, v2) cs g = M.adjust (M.mapWithKey (\k ->
if and [c f1 v1 k g | c <- cs] then delete v2 else id)) f2 g

notAt :: (Int -> Int) -> String -> String -> Int -> Grid -> Bool
notAt f f1 v1 i g = M.notMember (f i) (g M.! f1) ||
notElem v1 (g M.! f1 M.! (f i))

runConstraint :: Constraint -> Grid -> Grid
runConstraint (Link a b) = removeIf a b conds . removeIf b a conds
where conds = [(\f1 v1 k -> notElem v1 . (M.! k) . (M.! f1))]
M.adjust (M.update (const \$ Just [v1]) i) f1
runConstraint (NextTo a b)  = removeIf a b [notAt pred, notAt succ]
runConstraint (RightOf a b) = removeIf a b [notAt pred] .
removeIf b a [notAt succ]

adjustOthers :: Eq k => (v -> v) -> k -> M.Map k v -> M.Map k v
adjustOthers f k = M.mapWithKey (\k' v -> if k' == k then v else f v)

simplify :: Grid -> Grid
simplify g = foldr (\$) (M.mapWithKey (\_ v ->
M.mapWithKey (\i x -> let d = x \\ concat (M.elems \$ M.delete i v)
in if length d == 1 then d else x) v) g)
| (f, v) <- M.assocs g, (i, x) <- M.assocs v, length x == 1]

run :: Solver -> Solver
run (cs, g) = (cs, simplify \$ foldr runConstraint g cs)

apply :: Solver -> Solver
apply = head . head . dropWhile (null . tail) . group . iterate run

solved :: M.Map k (M.Map k' [v]) -> Bool
solved g = and [False | (_, v)  <- M.assocs g,
(_, xs) <- M.assocs v, length xs /= 1]

solve :: Solver -> [String]
solve s = map (unwords . map head) . transpose . map (M.elems) .
M.elems \$ head [ r | let (cs, g) = apply s,
(f, v) <- M.assocs \$ g, (i, xs) <- M.assocs v, x <- xs,
let (_, r) = apply (cs, M.adjust (M.adjust (const [x]) i) f g),
solved r ]

grid :: Grid
grid = M.fromList . zip (words "owner brand drink pet color") \$
map (M.fromList . zip [1..] . replicate 5)
[words "Englishman Ukranian Norwegian Japanese Spaniard",
words "Old_Gold Kools Chesterfields Lucky_Strike Parliaments",
words "Coffee Tea Milk Orange_Juice Water",
words "Dog Snails Horse Fox Zebra",
words "Red Green Ivory Yellow Blue"]

problem :: Solver
problem = foldr addConstraint ([], grid)
RightOf ("color", "Ivory")         ("color", "Green"),
NextTo  ("brand", "Chesterfields") ("pet",   "Fox"),
NextTo  ("brand", "Kools")         ("pet",   "Horse"),
NextTo  ("owner", "Norwegian")     ("color", "Blue")]

main :: IO ()
main = mapM_ putStrLn \$ solve problem
```
4. Remco Niemeijer said

A more elegant solution (see http://bonsaicode.wordpress.com/2009/06/22/who-owns-the-zebra-reloaded/ for more detail):

```import Data.List

indexOf :: (Eq a) => [a] -> a -> Int
indexOf xs x = head \$ elemIndices x xs

nextTo :: Int -> Int -> Bool
nextTo a b = abs (a - b) == 1

rightOf :: Int -> Int -> Bool
rightOf a b = a == b + 1

options :: String -> [[String]]
options = permutations . words

solution :: [[String]]
solution = head [transpose [cs, os, ds, ss, ps] |
cs <- options "red green ivory yellow blue",
let color = indexOf cs,
color "green" `rightOf` color "ivory",
os <- options "english spaniard ukranian norwegian japanese",
let owner = indexOf os,
owner "norwegian" == 0,
owner "english" == color "red",
owner "norwegian" `nextTo` color "blue",
ds <- options "coffee tea milk juice water",
let drinks = indexOf ds,
drinks "milk" == 2,
drinks "coffee" == color "green",
owner "ukranian" == drinks "tea",
ss <- options "old_gold kools chesterfields parliaments lucky_strike",
let smokes = indexOf ss,
smokes "kools" == color "yellow",
smokes "lucky_strike" == drinks "juice",
owner "japanese" == smokes "parliaments",
ps <- options "dog snails fox horse zebra",
let pet = indexOf ps,
owner "spaniard" == pet "dog",
smokes "old_gold" == pet "snails",
smokes "chesterfields" `nextTo` pet "fox",
smokes "kools" `nextTo` pet "horse"]

main :: IO ()
main = mapM_ print solution
```
5. RFH said

One I did in Python 3.0.1, using the stadard library’s itertools module for the permutations: