知恵袋で見つけた判断推理のリーグ戦の問題をPythonで解いてみた。(2)

 知恵袋で見つけた判断推理のリーグ戦の問題Pythonで解いてみました。以前、Javaで作ったのPythonで作り直してみました。今回は選択肢のチェックもしておきました。

 A〜Fの6チームで野球のリーグ戦を行ったところ、対戦結果について次のア〜カのことがわかった。このとき確実にいえるのはどれか。
ア、Aは1勝2敗2引き分けであった。
イ、BはAに勝った。
ウ、CはFにのみ勝った。
エ、Dは3勝2敗であった。
オ、EはAに敗れ、2勝3敗であった。
カ、FはDに敗れ、1勝3敗1引き分けであった。
選択肢
1、AはFに勝った。
2、Bは無敗であった。
3、Cは1勝2敗2引き分けであった。
4、DはEに勝った。
5、FはEに敗れた。

 勝ち点p[i]を勝ち100点、引分け10点、負け1点とすると、表中の反対称な得点q[i]は100/p[i]で表すことができます。また、合計点の百の位が勝ち数、十の位が引分け数、一の位が負け数になります。
 空欄を変数p[i],q[i](ただし、i=0〜10)でおいて、条件を表であらわすと次のようになります。
 それから、扱いやすいように表の1行をそれぞれリストla〜lfにしました。(^_^;

+------+------+------+------+------+------+------+
|      |  A  |  B  |  C  |  D  |  E  |  F  |(相手)
+------+------+------+------+------+------+------+
|  A  |  \  |  X  | p[0] | p[1] |  〇  | p[2] | 1勝2敗2分⇒122
+------+------+------+------+------+------+------+
|  B  |  〇  |  \  | p[3] | p[4] | p[5] | p[6] |
+------+------+------+------+------+------+------+
|  C  | q[0] | q[3] |  \  | p[7] | p[8] |  〇  | 1勝のみ  ⇒1??
+------+------+------+------+------+------+------+
|  D  | q[1] | q[4] | q[7] |  \  | p[9] |  〇  | 3勝2敗   ⇒302
+------+------+------+------+------+------+------+
|  E  |  X  | q[5] | q[8] | q[9] |  \  | p[10]| 2勝3敗   ⇒203
+------+------+------+------+------+------+------+
|  F  | q[2] | q[6] |  X  |  X  | q[10]|  \  | 1勝3敗1分⇒113
+------+------+------+------+------+------+------+
※〇:勝(100); △:分(10); X:敗(1)

 ループを分けてネストを深くした方が高速ですが、最近のPCの高速化に甘えて、ネストが深くならない方を選びました。(^_^;
 形は悪くなりますが、qのリストを生成する前にAの勝敗数で枝狩りした方が高速化するようなので、この枝狩りだけ前の方にもって来ました。(^_^;
 ちなみに、リストをタプルに変更すると少しだけ速くなります。(^_^;

● LeagueMatch.py

# coding: UTF-8
# LeagueMatch.py

import itertools
from time import time

def PrintResult(lst):
    n = len(lst)
    S = u' ABCDEF'
    print(S)
    for i in range(n):
        s = S[i+1]
        for j in range(n):
            k = lst[i][j]
            if   k==100: s+=u'〇'    # 勝:100
            elif k== 10: s+=u'△'    # 分: 10
            elif k==  1: s+=u'X'    # 敗:  1
            else:        s+=u'\'
        print(s)

def main():
    tm = time()  # Timer Start
    NAME = 'ABCDEF'
    N = 11
    ch = [True]*5
    cnt = 0
    for p in itertools.product([100,10,1],repeat=N): # 勝:100; 分:10; 敗:1
        la = [   0 ,   1 ,p[ 0],p[ 1], 100 ,p[ 2]]   # 条件イ,オ
        if sum(la)!=122:   continue                  # 条件ア
        q  = [100//p[i] for i in range(N)]           # 反対称な得点

        lb = [ 100 ,   0 ,p[ 3],p[ 4],p[ 5],p[ 6]]   # 条件イ
        lc = [q[ 0],q[ 3],   0 ,p[ 7],p[ 8], 100 ]   # 条件ウ
        ld = [q[ 1],q[ 4],q[ 7],   0 ,p[ 9], 100 ]   # 条件カ
        le = [   1 ,q[ 5],q[ 8],q[ 9],   0 ,p[10]]   # 条件オ
        lf = [q[ 2],q[ 6],   1 ,   1 ,q[10],   0 ]   # 条件ウ,カ

        if sum(lc)//100!=1: continue                 # 条件ウ
        if sum(ld)!=302:   continue                  # 条件エ
        if sum(le)!=203:   continue                  # 条件オ
        if sum(lf)!=113:   continue                  # 条件カ
        # チェックを潜り抜けたものだけを表示
        cnt+=1
        print("[%d]"%cnt)
        PrintResult([la,lb,lc,ld,le,lf])
        # 選択肢のチェック
        ch[0] &= (la[NAME.index('F')]==100)
        ch[1] &= (sum(lb)%10==0)
        ch[2] &= (sum(lc)==122)
        ch[3] &= (ld[NAME.index('E')]==100)
        ch[4] &= (lf[NAME.index('E')]==  1)

    if cnt==0: ch = [False]*5
    s = ""
    for c in ch:
        if c : s+=" %s"%(ch.index(c)+1)
    print(u"∴%s"%s)
    print("Runtime : %.3f [sec]"%(time()-tm))   # Timer Stop & Disp

if __name__ == '__main__':
    main()

●実行結果

[1]
 ABCDEF
A\X△X〇△
B〇\〇〇〇〇
C△X\XX〇
D〇X〇\X〇
EXX〇〇\X
F△XXX〇\
[2]
 ABCDEF
A\X△X〇△
B〇\△〇〇〇
C△△\XX〇
D〇X〇\X〇
EXX〇〇\X
F△XXX〇\
∴ 2
Runtime : 0.359 [sec]

※参考URL
知恵袋で見つけた判断推理のリーグ戦の問題をJavaで解いてみた。
知恵袋で見つけた判断推理のリーグ戦の問題をPythonで解いてみた。