# -*- Mode: Python -*-

# Sam Rushing (http://www.nightmare.com/rushing)

from constraint import *

# ALBERT EINSTEIN'S RIDDLE 
#  
# ARE YOU IN THE TOP 2% OF INTELLIGENT PEOPLE IN THE WORLD? 
# SOLVE THE RIDDLE AND FIND OUT. 
# 
# There are no tricks, just pure logic, so good luck and don't give up. 
# 
# 1. In a street there are five houses, painted five different colours. 
# 2. In each house lives a person of different nationality 
# 3. These five homeowners each drink a different kind of beverage, smoke 
# different brand of cigar and keep a different pet. 
# 
# THE QUESTION: WHO OWNS THE FISH? 
# 
# HINTS 
# 
# 1. The Brit lives in a red house. 
# 2. The Swede keeps dogs as pets. 
# 3. The Dane drinks tea. 
# 4. The Green house is on the left of the White house. 
# 5. The owner of the Green house drinks coffee. 
# 6. The person who smokes Pall Mall rears birds. 
# 7. The owner of the Yellow house smokes Dunhill. 
# 8. The man living in the centre house drinks milk. 
# 9. The Norwegian lives in the first house. 
# 10. The man who smokes Blends lives next to the one who keeps cats. 
# 11. The man who keeps horses lives next to the man who smokes Dunhill. 
# 12. The man who smokes Blue Master drinks beer. 
# 13. The German smokes Prince. 
# 14. The Norwegian lives next to the blue house. 
# 15. The man who smokes Blends has a neighbour who drinks water. 
# 
# ALBERT EINSTEIN WROTE THIS RIDDLE EARLY DURING THE 19th CENTURY. HE 
# SAID THAT 98% OF THE WORLD POPULATION WOULD NOT BE ABLE TO SOLVE IT. 

p = Problem()

# Assign a single letter variable to each object.  Only the nationalities
#   are obvious, the others are just lower-case letters in order.
nats = ('BSDNG', 'brit', 'swede', 'dane', 'nord', 'german')
pets = ('abcde', 'dogs', 'birds', 'cats', 'horses', 'fish')
cols = ('fghij', 'red', 'green', 'white', 'yellow', 'blue')
smokes = ('klmno', 'pall-mall', 'dunhill', 'blends', 'blue-master', 'prince')
drinks = ('pqrst', 'tea', 'coffee', 'milk', 'beer', 'water')

trans = {}
for key in (nats, pets, cols, smokes, drinks):
    for i in range (5):
        trans[key[0][i]] = key[i+1]

houses = [1,2,3,4,5]

p.addVariables ("BSDNGabcdefghijklmnopqrst", houses)
# all different nationalities...
p.addConstraint (AllDifferentConstraint(), "BSDNG")
# all different pets...
p.addConstraint (AllDifferentConstraint(), "abcde")
p.addConstraint (AllDifferentConstraint(), "fghij")
p.addConstraint (AllDifferentConstraint(), "klmno")
p.addConstraint (AllDifferentConstraint(), "pqrst")

pa = p.addConstraint

# 1-5
pa (lambda B,f: B == f, "Bf")
pa (lambda S,a: S == a, "Sa")
pa (lambda D,p: D == p, "Dp")
# a tricky one.  the clue *should* say 'immediate left',
# if you use "g < h" you get 8 solutions rather than one.
pa (lambda g,h: g == h-1, "gh")
pa (lambda g,q: g == q, "gq")

# 6-10
pa (lambda k,b: k == b, "kb")
pa (lambda i,l: i == l, "il")
pa (lambda r: r == 3, "r")
pa (lambda N: N == 1, "N")
pa (lambda m,c: (m+1 == c) or (m-1 == c), "mc")

# 11-15
pa (lambda d,l: (d == l+1) or (d == l-1), "dl")
pa (lambda n,s: n == s, "ns")
pa (lambda G,o: G == o, "Go")
pa (lambda N,j: (N == j+1) or (N == j-1), "Nj")
pa (lambda m,t: (m == t+1) or (m == t-1), "mt")

def print_sol (s):
    items = [(v,k) for (k,v) in s.items()]
    items.sort()
    i = 0
    for v,k in items:
        print trans[k],
        i += 1
        if i%5 == 0:
            print
    print

for s in p.getSolutions():
    print_sol (s)
