Zebra Puzzle

  1. 有五間房子
  2. 英國人住紅色的房子
  3. 西班牙人養狗
  4. 住綠色房子的人喝咖啡
  5. 烏克蘭人喝茶
  6. 綠色房子緊鄰的左邊(你的右邊)是白色房子
  7. 抽「Old Gold」牌香菸的人養蝸牛
  8. 黃色房子的人抽「Kools」牌香菸
  9. 正中間房子的人喝牛奶
  10. 挪威人住左邊(你的右邊)第一間房子
  11. 抽「Chesterfields」牌香菸的人,住在養狐狸的人的隔壁
  12. 抽「Kools」牌香菸的人,住在養馬的人隔壁
  13. 抽「Lucky Strike」牌香菸的人,喝橘子汁
  14. 日本人抽「Parliament」牌香菸
  15. 挪威人住在藍色房子的隔壁

Question:誰喝水? 誰養斑馬?

In [2]:
import itertools 
屋子 = 第一間, _, 中間, _, _ = [1, 2, 3, 4, 5]
所有順序 = list(itertools.permutations(屋子))
所有順序
Out[2]:
[(1, 2, 3, 4, 5),
 (1, 2, 3, 5, 4),
 (1, 2, 4, 3, 5),
 (1, 2, 4, 5, 3),
 (1, 2, 5, 3, 4),
 (1, 2, 5, 4, 3),
 (1, 3, 2, 4, 5),
 (1, 3, 2, 5, 4),
 (1, 3, 4, 2, 5),
 (1, 3, 4, 5, 2),
 (1, 3, 5, 2, 4),
 (1, 3, 5, 4, 2),
 (1, 4, 2, 3, 5),
 (1, 4, 2, 5, 3),
 (1, 4, 3, 2, 5),
 (1, 4, 3, 5, 2),
 (1, 4, 5, 2, 3),
 (1, 4, 5, 3, 2),
 (1, 5, 2, 3, 4),
 (1, 5, 2, 4, 3),
 (1, 5, 3, 2, 4),
 (1, 5, 3, 4, 2),
 (1, 5, 4, 2, 3),
 (1, 5, 4, 3, 2),
 (2, 1, 3, 4, 5),
 (2, 1, 3, 5, 4),
 (2, 1, 4, 3, 5),
 (2, 1, 4, 5, 3),
 (2, 1, 5, 3, 4),
 (2, 1, 5, 4, 3),
 (2, 3, 1, 4, 5),
 (2, 3, 1, 5, 4),
 (2, 3, 4, 1, 5),
 (2, 3, 4, 5, 1),
 (2, 3, 5, 1, 4),
 (2, 3, 5, 4, 1),
 (2, 4, 1, 3, 5),
 (2, 4, 1, 5, 3),
 (2, 4, 3, 1, 5),
 (2, 4, 3, 5, 1),
 (2, 4, 5, 1, 3),
 (2, 4, 5, 3, 1),
 (2, 5, 1, 3, 4),
 (2, 5, 1, 4, 3),
 (2, 5, 3, 1, 4),
 (2, 5, 3, 4, 1),
 (2, 5, 4, 1, 3),
 (2, 5, 4, 3, 1),
 (3, 1, 2, 4, 5),
 (3, 1, 2, 5, 4),
 (3, 1, 4, 2, 5),
 (3, 1, 4, 5, 2),
 (3, 1, 5, 2, 4),
 (3, 1, 5, 4, 2),
 (3, 2, 1, 4, 5),
 (3, 2, 1, 5, 4),
 (3, 2, 4, 1, 5),
 (3, 2, 4, 5, 1),
 (3, 2, 5, 1, 4),
 (3, 2, 5, 4, 1),
 (3, 4, 1, 2, 5),
 (3, 4, 1, 5, 2),
 (3, 4, 2, 1, 5),
 (3, 4, 2, 5, 1),
 (3, 4, 5, 1, 2),
 (3, 4, 5, 2, 1),
 (3, 5, 1, 2, 4),
 (3, 5, 1, 4, 2),
 (3, 5, 2, 1, 4),
 (3, 5, 2, 4, 1),
 (3, 5, 4, 1, 2),
 (3, 5, 4, 2, 1),
 (4, 1, 2, 3, 5),
 (4, 1, 2, 5, 3),
 (4, 1, 3, 2, 5),
 (4, 1, 3, 5, 2),
 (4, 1, 5, 2, 3),
 (4, 1, 5, 3, 2),
 (4, 2, 1, 3, 5),
 (4, 2, 1, 5, 3),
 (4, 2, 3, 1, 5),
 (4, 2, 3, 5, 1),
 (4, 2, 5, 1, 3),
 (4, 2, 5, 3, 1),
 (4, 3, 1, 2, 5),
 (4, 3, 1, 5, 2),
 (4, 3, 2, 1, 5),
 (4, 3, 2, 5, 1),
 (4, 3, 5, 1, 2),
 (4, 3, 5, 2, 1),
 (4, 5, 1, 2, 3),
 (4, 5, 1, 3, 2),
 (4, 5, 2, 1, 3),
 (4, 5, 2, 3, 1),
 (4, 5, 3, 1, 2),
 (4, 5, 3, 2, 1),
 (5, 1, 2, 3, 4),
 (5, 1, 2, 4, 3),
 (5, 1, 3, 2, 4),
 (5, 1, 3, 4, 2),
 (5, 1, 4, 2, 3),
 (5, 1, 4, 3, 2),
 (5, 2, 1, 3, 4),
 (5, 2, 1, 4, 3),
 (5, 2, 3, 1, 4),
 (5, 2, 3, 4, 1),
 (5, 2, 4, 1, 3),
 (5, 2, 4, 3, 1),
 (5, 3, 1, 2, 4),
 (5, 3, 1, 4, 2),
 (5, 3, 2, 1, 4),
 (5, 3, 2, 4, 1),
 (5, 3, 4, 1, 2),
 (5, 3, 4, 2, 1),
 (5, 4, 1, 2, 3),
 (5, 4, 1, 3, 2),
 (5, 4, 2, 1, 3),
 (5, 4, 2, 3, 1),
 (5, 4, 3, 1, 2),
 (5, 4, 3, 2, 1)]
In [4]:
def 在右邊(h1, h2):
    "h1 緊鄰 h2 的右邊."
    return h1-h2 == 1

def 隔壁(h1, h2):
    "h1 h2 在隔壁"
    return abs(h1-h2) == 1
In [5]:
def zebra_puzzle():        
    return [locals()
                for (, , , , ) in 所有順序
                for (英國人, 西班牙人, 烏克蘭人, 日本人, 挪威人) in 所有順序
                for (咖啡, , 牛奶, 橘子汁, ) in 所有順序
                for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments) in 所有順序
                for (, 蝸牛, 狐狸, , 斑馬) in 所有順序                                   
                    if 英國人 is   #2
                    if 西班牙人 is  #3
                    if 咖啡 is  #4
                    if 烏克蘭人 is  #5
                    if 在右邊(, ) #6 
                    if OldGold is 蝸牛 #7
                    if Kools is  #8
                    if 牛奶 is 中間 #9
                    if 挪威人 is 第一間 #10
                    if 隔壁(Chesterfields, 狐狸) #11
                    if 隔壁(Kools, ) #12
                    if LuckyStrike is 橘子汁 #13
                    if 日本人 is Parliaments #14 
                    if 隔壁(挪威人, ) #15 
                ]
zebra_puzzle()
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-5-868aca501721> in <module>()
     21                     if 隔壁(挪威人,) #15
     22                 ]
---> 23 zebra_puzzle()

<ipython-input-5-868aca501721> in zebra_puzzle()
      1 def zebra_puzzle():
      2     return [locals()
----> 3                 for (,,,,) in 所有順序
      4                 for (英國人, 西班牙人, 烏克蘭人, 日本人, 挪威人) in 所有順序
      5                 for (咖啡,, 牛奶, 橘子汁,) in 所有順序

<ipython-input-5-868aca501721> in <listcomp>(.0)
      5                 for (咖啡,, 牛奶, 橘子汁,) in 所有順序
      6                 for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments) in 所有順序
----> 7                 for (, 蝸牛, 狐狸,, 斑馬) in 所有順序
      8                     if 英國人 is#2
      9                     if 西班牙人 is#3

KeyboardInterrupt: 

時間太長!

In [6]:
def zebra_puzzle():        
    return [locals()
                for (, , , , ) in 所有順序
                    if 在右邊(, ) #6
                for (英國人, 西班牙人, 烏克蘭人, 日本人, 挪威人) in 所有順序
                    if 英國人 is   #2
                    if 挪威人 is 第一間 #10
                    if 隔壁(挪威人, ) #15
                for (咖啡, , 牛奶, 橘子汁, ) in 所有順序
                    if 咖啡 is  #4
                    if 烏克蘭人 is  #5
                    if 牛奶 is 中間 #9
                for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments) in 所有順序
                    if Kools is  #8
                    if LuckyStrike is 橘子汁 #13
                    if 日本人 is Parliaments #14
                for (, 蝸牛, 狐狸, , 斑馬) in 所有順序
                    if 西班牙人 is  #3
                    if OldGold is 蝸牛 #7
                    if 隔壁(Chesterfields, 狐狸) #11
                    if 隔壁(Kools, ) #12
                ]
zebra_puzzle()
Out[6]:
[{'.0': <list_iterator at 0x7f9e8004cf98>,
  'Chesterfields': 2,
  'Kools': 1,
  'LuckyStrike': 4,
  'OldGold': 3,
  'Parliaments': 5,
  '咖啡': 5,
  '挪威人': 1,
  '斑馬': 5,
  '日本人': 5,
  '橘子汁': 4,
  '水': 1,
  '烏克蘭人': 2,
  '牛奶': 3,
  '狐狸': 1,
  '狗': 4,
  '白': 4,
  '紅': 3,
  '綠': 5,
  '英國人': 3,
  '茶': 2,
  '藍': 2,
  '蝸牛': 3,
  '西班牙人': 4,
  '馬': 2,
  '黃': 1}]
In [7]:
def result(d): return {i:[k for k,v in d.items() if v == i]for i in 屋子}
def zebra_puzzle():        
    return [result(locals())
                for (, , , , ) in 所有順序
                    if 在右邊(, )
                for (英國人, 西班牙人, 烏克蘭人, 日本人, 挪威人) in 所有順序
                    if 英國人 is 
                    if 挪威人 is 第一間
                    if 隔壁(挪威人, )
                for (咖啡, , 牛奶, 橘子汁, ) in 所有順序
                    if 咖啡 is 
                    if 烏克蘭人 is 
                    if 牛奶 is 中間
                for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments) in 所有順序
                    if Kools is 
                    if LuckyStrike is 橘子汁
                    if 日本人 is Parliaments
                for (, 蝸牛, 狐狸, , 斑馬) in 所有順序
                    if 西班牙人 is 
                    if OldGold is 蝸牛
                    if 隔壁(Chesterfields, 狐狸)
                    if 隔壁(Kools, ) ]
zebra_puzzle()[0]
Out[7]:
{1: ['狐狸', 'Kools', '黃', '水', '挪威人'],
 2: ['馬', 'Chesterfields', '茶', '藍', '烏克蘭人'],
 3: ['英國人', '蝸牛', '紅', '牛奶', 'OldGold'],
 4: ['橘子汁', '白', '狗', 'LuckyStrike', '西班牙人'],
 5: ['日本人', 'Parliaments', '咖啡', '斑馬', '綠']}

Credit:

基於 Udacity's CS212 的解答