知恵袋で見つけた判断推理のトランプの問題をPythonで解いてみた。(3)

 知恵袋で見つけた判断推理のトランプの問題Pythonで解いてみました。(^_^;

 トランプが12枚ある。ハート、ダイヤ、クラブ、スペードの4種類でそれぞれにジャック、クィーン、キングが揃っている。A~Dの4人に3枚ずつ配ったところ次のことが分かった。
・Aにはハートが2枚あるがクラブはない
・Bにはジャックが2枚あるがハートはない
・Cにはスペードとクイーンは2枚あるがキングはない
・Dにはダイヤが2枚とクラブのキングがある
 以上のことから正しいものをえらびなさい
1 Aにはキングが2枚ある
2 Bにはダイヤのクイーンがある
3 Cにはハートのジャックがある
4 Dにはクイーンが2枚ある
5 Bにはスペードのキングがある

 前回、作った拙プログラムTrump2.pyを雛形にしましたが、countRank関数とcountSuit関数をちょっと書き直してみました。(^_^;
 トランプに、0~11の通し番号を与えて、1人分の枚数3で割った商でスート(絵柄マーク)、3で割った余りからランク(番号)を得ることにしました。

 sSuit: ('S','D','C','H') = n: (0,1,2,3) = (スペード,ダイア,クラブ,ハート)
 sRank: ('J','Q','K') = n: (0,1,2) = (ジャック,クィーン,キング)

      0  1  2
      J  Q  K : Rank
 0 S  0  1  2
 1 D  3  4  5
 2 C  6  7  8
 3 H  9 10 11
 Suit

● Trump3.py

# coding: UTF-8
# Trump3.py

import itertools
from time import time

SUIT = 'SDCH'
RANK = 'JQK'
N = len(RANK)   # 1人分の枚数

# sRank: 'J','Q','K'
def countRank(sRank, cards):
    li = []
    for c in cards:
        li.append(RANK[c%N])
    return li.count(sRank)

# sSuit: 'S','D','C','H'
def countSuit(sSuit, cards):
    li = []
    for c in cards:
        li.append(SUIT[c//N])
    return li.count(sSuit)

def countSuits(cards):
    return [countSuit(SUIT[i],cards) for i in range(4)]

# suitとrankから通し番号を得る
def getN(sSuit,sRank):
    return SUIT.index(sSuit)*N+RANK.index(sRank)

def toStrCards(cards):
    li = []
    for c in cards:
        li.append(SUIT[c//N]+RANK[c%N])
    return "(%s)"%(','.join(li))

# 確実にいえる選択肢を得る
def getAns(cho,lbl='12345'):
    return ','.join([lbl[i] for i in range(len(cho)) if cho[i]])

def main():
    tm = time()  # Timer Start

    choices = [True]*5
    Cards = range(4*N)
    for a in itertools.combinations(Cards,N):
        if countSuit('H',a)!=2: continue                # 条件A-1
        if countSuit('C',a)!=0: continue                # 条件A-2
        B = tuple(set(Cards)-set(a))                # aを除いた残り
        for b in itertools.combinations(B,N):
            if countRank('J',b)!=2: continue            # 条件B-1
            if countSuit('H',b)!=0: continue            # 条件B-2
            C = tuple(set(B)-set(b))                # a,bを除いた残り
            for c in itertools.combinations(C,N):
                if countSuit('S',c)!=2: continue        # 条件C-1
                if countRank('Q',c)!=2: continue        # 条件C-2
                if countRank('K',c)!=0: continue        # 条件C-3
                d = tuple(set(C)-set(c))            # a,b,cを除いた残り
                if countSuit('D',d)!=2: continue        # 条件D-1
                if not getN('C','K') in d: continue     # 条件D-2
                # チェックを潜り抜けたものだけを表示
                print(toStrCards(a),toStrCards(b),toStrCards(c),toStrCards(d))
                # 選択肢のチェック
                choices[0] &= (countRank('K',a)==2)
                choices[1] &= (getN('D','Q') in b )
                choices[2] &= (getN('H','J') in c )
                choices[3] &= (countRank('Q',d)==2)
                choices[4] &= (getN('S','K') in b )

    print(u"∴%s"%getAns(choices))
    print("Runtime : %.3f [sec]"%(time()-tm))   # Timer Stop & Disp

if __name__ == '__main__':
    main()

●実行結果

(SK,HJ,HK) (DJ,CJ,CQ) (SJ,SQ,HQ) (CK,DQ,DK)
∴1
Runtime : 0.016 [sec]

※参考URL
知恵袋で見つけた判断推理のトランプの問題をPythonで解いてみた。 - rscのブログ
知恵袋で見つけた判断推理のトランプの問題をPythonで解いてみた。(2) - rscのブログ