Zebra PuzzleをPythonで解いてみた。

 Zebra PuzzlePythonで解いてみました。(^_^;

01:家が5軒あります。その5軒の家は、それぞれ異なる色で塗られていて、そして、その住民はそれぞれ異なる国籍で、それぞれ異なるペットを飼っていて、それぞれ異なる飲み物をふだん好んで飲み、それぞれ異なる銘柄のアメリカのたばこを吸っています。
02:イギリス人は赤い家に住んでいます。
03:スペイン人は犬を飼っています。
04:緑の家の人はふだんコーヒーを飲んでいます。
05:ウクライナ人は紅茶を好んで飲みます。
06:緑の家は白い家のすぐ右隣にあります。(※[白][緑])
07:オールドゴールド銘柄のたばこを吸う人は、カタツムリを飼っています。
08:黄色の家に住んでいる人はクールズ銘柄のたばこを吸っています。
09:中央の家に住んでいる人はふだんミルクを飲んでいます。
10:ノルウェー人は、一番目(左端)の家に住んでいます。
11:チェスターフィールド銘柄のたばこを吸う人は狐を飼っている男の人の隣に住んでいます。
12:クールズ銘柄のたばこは、馬を飼っている人の隣の家の人が吸っています。
13:ラッキーストライク銘柄のたばこを吸う人は、オレンジジュースを好んで飲みます。
14:日本人はパーラメント銘柄のたばこを吸います。
15:ノルウェー人は、青い家の隣に住んでいます。

 さて、(1)誰がふだん水を飲んでいますか?(2)誰がシマウマを飼っていますか?

House{1,2,3,4,5}
Color{赤(R),緑(G),白(W),黄(Y),青(B)}
Nationality{イギリス(E),日本(J),ノルウェー(N),スペイン(S),ウクライナ(U)}
Drink{コーヒー(C),ミルク(M),オレンジジュース(O),紅茶(T),水(W)}
Smoke{チェスターフィールド(C),クールズ(K),ラッキーストライク(L),オールドゴールド(O),パーラメント(P)}
Pet{犬(D),狐(F),馬(H),カタツムリ(S),シマウマ(Z)}

 これは、Einstein's Riddleの類題で、こっちの方がソースが確定しているようだから大本かな。(^_^;
 Einstein.pyを雛形にして作りましたが、問題の要素は変わっていますが、構造はほとんど同じもののようです。(^_^;

● Zebra1.py

# coding: UTF-8
# Zebra1.py
# H: 12345
# C: YBRWG
# N: NUESJ
# D: WTMOC
# S: KCOLP
# P: FHSDZ

# 条件チェック: xからm個右側にyがあるか調べる
def check_cond(m, a, x, b, y):
    n = a.index(x)
    if n==ValueError or len(a)<=m+n:
        return False
    return b[m+n]==y

# マッチング条件
def check_match(a, x, b, y):
    return check_cond(0, a, x, b, y)

# 順序付き隣接条件(左からx,yの順で隣接)
def check_adj_1(a, x, b, y):
    return check_cond(1, a, x, b, y)

# 隣接条件(順不定)
def check_adj_2(a, x, b, y):
    return check_adj_1(a,x,b,y) or check_adj_1(b,y,a,x)

def main():
    import itertools
    from time import time
    tm = time() # Timer Start

    # 要素を昇順にソートしたもの
    HOUSE  = '12345'    # 家の場所(固定)
    COLOR  = 'BGRWY'    # 家の色
    NATION = 'EJNSU'    # 国、国籍
    DRINK  = 'CMOTW'    # 飲み物
    SMOKE  = 'CKLOP'    # タバコ
    PET    = 'DFHSZ'    # ペット

    # 連想配列
    Nation = {
        "E" : u"E:イギリス",
        "J" : u"J:日本",
        "N" : u"N:ノルウェー",
        "S" : u"S:スペイン",
        "U" : u"U:ウクライナ"
    }

    house = HOUSE[:]
    for nation in itertools.permutations(NATION):               # nation loop
        if not check_match(nation,'N',house, '1'): continue                 # 条件10
        for color in itertools.permutations(COLOR):             # house loop
            if not check_match(nation,'E',color, 'R'): continue             # 条件02
            if not check_adj_1(color, 'W',color, 'G'): continue             # 条件06
            if not check_adj_2(nation,'N',color, 'B'): continue             # 条件15
            for pet in itertools.permutations(PET):             # pet loop
                if not check_match(nation,'S',pet,   'D'): continue         # 条件03
                for drink in itertools.permutations(DRINK):     # drink loop
                    if not check_match(nation,'U',drink, 'T'): continue     # 条件05
                    if not check_match(color, 'G',drink, 'C'): continue     # 条件04
                    if not check_match(house, '3',drink, 'M'): continue     # 条件09
                    for smoke in itertools.permutations(SMOKE): # tabaco loop
                        if not check_match(smoke, 'O',pet,   'S'): continue # 条件07
                        if not check_match(color, 'Y',smoke, 'K'): continue # 条件08
                        if not check_adj_2(smoke, 'C',pet,   'F'): continue # 条件11
                        if not check_adj_2(pet,   'H',smoke, 'K'): continue # 条件12
                        if not check_match(smoke, 'L',drink, 'O'): continue # 条件13
                        if not check_match(nation,'J',smoke, 'P'): continue # 条件14
                        # チェックを潜り抜けたものだけを表示
                        print("H: %s"%"".join(house ))
                        print("C: %s"%"".join(color ))
                        print("N: %s"%"".join(nation))
                        print("D: %s"%"".join(drink ))
                        print("S: %s"%"".join(smoke ))
                        print("P: %s"%"".join(pet   ))
                        print(u"∴")
                        print(u"(1)%s人"%Nation[nation[drink.index('W')]])
                        print(u"(2)%s人"%Nation[nation[pet  .index('Z')]])

    print("Runtime : %.3f [sec]"%(time()-tm))   # Timer Stop & Print

if __name__ == '__main__':
    main()

●実行結果

H: 12345
C: YBRWG
N: NUESJ
D: WTMOC
S: KCOLP
P: FHSDZ
∴
(1)N:ノルウェー人
(2)J:日本人
Runtime : 0.185 [sec]

Zebra PuzzleをPythonで解いてみた。(2)