金貨と銅貨と空箱の「うそつき問題」をPythonで解いてみた

 エイプリルフールなので、金貨と銅貨と空箱の「うそつき問題」をPythonで解いてみました。(^_^;

 A~Eの五つの箱があり、これらの箱は、金貨の入った箱、銅貨の入った箱、空箱の3種類の場合がある。
 また、それぞれの箱にはラベルが付いているが、そのラベルの記述の内容は、金貨の入った箱のものは真(真実に一致している)であるが、銅貨の入った箱のものは偽(真実に反している)であり、空箱のものは真の場合も偽の場合もあるという。
 このとき、銅貨の入った箱が二つあるとすると、確実に銅貨の入った箱はどれか。
[ラベル]
A:「Bのラベルの記述の内容は真である。」
B:「Aが空箱ならば、この箱も空箱である。」
C:「この箱は、銅貨の入った箱である。」
D:「AかEの少なくとも一方は、銅貨の入った箱である。」
E:「この箱は、金貨の入った箱である。」

 これは、天使と悪魔と人間の「うそつき問題」の類題です。
 Aのラベルの記述の条件で、「b!='C'」のとこは、「b=='G' or b=='E'」や「Imp(a=='E',b=='E')」でもいいです。

● Liar12.py

# coding: UTF-8
# Liar12.py

import itertools
from time import time

# 論理等価Eqv
def Eqv(p,q):
    return not(p^q)

# 論理包含Imp
def Imp(p,q):
    return not p or q

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

def main():
    tm = time() # Timer Start
    choices = [True]*5
    P = 'CEG'
    for p in itertools.product(P,repeat=5):
        if not p.count('C')*p.count('E')*p.count('G')!=0: continue
        if not p.count('C')==2: continue
        a,b,c,d,e = p
        if not Imp(a!='E',Eqv(a=='G',b!='C')): continue
        if not Imp(b!='E',Eqv(b=='G',Imp(a=='E',b=='E'))): continue
        if not Imp(c!='E',Eqv(c=='G',c=='C')): continue
        if not Imp(d!='E',Eqv(d=='G',a=='C' or e=='C')): continue
        if not Imp(e!='E',Eqv(e=='G',e=='G')): continue
        pass # チェックを潜り抜けたものを表示
        print(p)
        pass # 選択肢のチェック
        choices[0] &= (a=='C')
        choices[1] &= (b=='C')
        choices[2] &= (c=='C')
        choices[3] &= (d=='C')
        choices[4] &= (e=='C')

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

if __name__ == '__main__':
    main()

●実行結果

('E', 'C', 'E', 'C', 'G')
('E', 'C', 'E', 'G', 'C')
∴B

※参考URL
天使と悪魔と道化の「ウソつき問題」をPythonで解いてみた。 - rscのブログ