拙ブログの記事『Zebra PuzzleをPythonで解いてみた。』の続きです。前回のプログラムにマトリクス(グリッド)表を付けてみました。(^_^;
大きなマトリクス表を描いてみたかったので作ってみましたが、ラベルが半角英数字だったので対策を講じることになりました。2番目の参考URLを参考にして、全角文字を2文字としてカウントするlenB()関数を作りました。これを使って、半角1文字のときは前に空白を補うことにしました。
それから、Python2では、unicodedata.east_asian_width()関数を使うためには引数をユニコード文字列に変換しておく必要があるようです。
ちなみに、今日で、「書いた日数」が500日になります。プラチナまであと半分まで来ました。まだまだ先は長いねぇ。(^_^;
● Zebra2.py
# coding: UTF-8 # Zebra2.py ''' H: 12345 C: YBRWG N: NUESJ D: WTMOC S: KCOLP P: FHSDZ ''' import itertools from time import time import unicodedata import sys def lenB(s): if sys.version_info[0]==2: s = unicode(s) # Python3では不要 w = 0 for c in s: d = unicodedata.east_asian_width(c) w+=(1 if d in 'HNa' else 2) return w # ラベルと答えのリスト等からマトリクス表を作成 def mkMatTbl(lbl,ans): m,n = len(lbl),len(lbl[0]) li = [lbl[i] for i in range(1,m)] # 横軸ラベルの作成 s = ' ' for i in range(m-1): for j in range(n): t = li[i][j] if not isinstance(t,int): if lenB(t)==1: s+=" " s+=t else: s+=('%2s'%str(t))[:2] print(s) for h in range(m-1): for i in range(n): s,t = '',lbl[-h][i] if not isinstance(t,int): # 縦軸ラベルの作成 if lenB(t)==1: s+=' ' s+=t else: s = ('%2s'%str(t))[:2] g = ans[-h].index(t) for j in range(1,m-h): a = ans[j][g] for k in range(n): s+=' o' if lbl[j][k]==a else ' x' print(s) # 条件チェック: 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(): 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('') mkMatTbl((HOUSE,COLOR,NATION,DRINK,SMOKE,PET), \ (HOUSE,color,nation,drink,smoke,pet)) 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:日本人 B G R W Y E J N S U C M O T W C K L O P D F H S Z 1 x x x x o x x o x x x x x x o x o x x x x o x x x 2 o x x x x x x x x o x x x o x o x x x x x x o x x 3 x x o x x o x x x x x o x x x x x x o x x x x o x 4 x x x o x x x x o x x x o x x x x o x x o x x x x 5 x o x x x x o x x x o x x x x x x x x o x x x x o D x x x o x x x x o x x x o x x x x o x x F x x x x o x x o x x x x x x o x o x x x H o x x x x x x x x o x x x o x o x x x x S x x o x x o x x x x x o x x x x x x o x Z x o x x x x o x x x o x x x x x x x x o C o x x x x x x x x o x x x o x K x x x x o x x o x x x x x x o L x x x o x x x x o x x x o x x O x x o x x o x x x x x o x x x P x o x x x x o x x x o x x x x C x o x x x x o x x x M x x o x x o x x x x O x x x o x x x x o x T o x x x x x x x x o W x x x x o x x o x x E x x o x x J x o x x x N x x x x o S x x x o x U o x x x x Runtime : 0.187 [sec]
※参考URL
●Zebra Puzzle - Wikipedia
●Pythonで全角文字を含む文字列の幅を取得する - Narrow Escape
●Pythonバージョンの取得方法 - Qiita
●買い物の推理パズルをPythonで解いてみた。(2)
●願い事の推理パズルをPythonで解いてみた。
P.S.
はてなダイアリーから、はてなブログに移行したとき、実行結果の表示が乱れるようになったので、('◯','×')を(' o',' x')に変更しました。