判断推理のロッカーの位置関係の問題をPythonで解いてみた。

 知恵袋で見つけた判断推理のロッカーの位置関係の問題Pythonで解いてみました。(^_^;

 A〜Lの12人はあるスポーツクラブの会員であり、それぞれ、図のように配置された1番から12番までのロッカーのいずれか一つを個人ロッカーとして使用している。今、次の事が分かっている時、Dが使用している可能性があるロッカーを全て挙げているのはどれか。なお、1番のロッカーの周りのロッカーとは、2番、5番、6番のロッカーを指すものとする。

ア.Aのロッカーの周りのロッカーは3個で、それらは、E、I、Jのロッカーである。
イ.Bのロッカーの周りのロッカーは8個で、その中にFのロッカーはない。
ウ.Cのロッカーの1つ斜め上はB、Eのロッカーである。
エ.Lのロッカーは、左端の列(1番、5番、9番)にある。
オ.G、I、Lのロッカーの周りにはそれぞれ5個のロッカーがある。

<選択肢>
1.1,9
2.1,2,12
3.1,2,9,10
4.2,10
5.2,7,10,12

※ただし、条件にア〜オの名前を付けました。(^_^;

 +--+--+--+--+
 | 1| 2| 3| 4| 1行目
 +--+--+--+--+
 | 5| 6| 7| 8| 2行目
 +--+--+--+--+
 | 9|10|11|12| 3行目
 +--+--+--+--+
   1  2  3  4 : 列目

 12個の順列は時間がかかるので枝が早く刈れそうなA,B,E,I,J,Lをループの前の方に持ってきて、残りを順列で回してみました。(^_^;

● Locker1.py

# coding: UTF-8
# Locker1.py

from time import time
import itertools

MR = 3  # 行の最大数
MC = 4  # 列の最大数

# 通し番号n番目の行数を得る
def getRow(n):
    return (n-1)//MC+1

# n番の列数を得る
def getCol(n):
    return (n-1)%MC+1

# r行c列の通し番号を得る
def getN(r,c):
    if r< 1 or MR< r: return 0  # ドメインエラーは0を返す
    if c< 1 or MC< c: return 0
    return (r-1)*MC+(c-1)+1

# n番のロッカーの周りのロッカーの番号のリストを得る
def getSurroundings(n):
    li = []
    if n< 1 or MR*MC< n: return li
    r,c = getRow(n),getCol(n)
    for i in range(-1,2):
        for j in range(-1,2):
            if i*i+j*j==0: continue
            m = getN(r+i,c+j)
            if m!=0:
                li.append(m)
    return li

# 結果を表示
def PrintResult(cnt,li):
    n = len(li)
    NAME = 'ABCDEFGHIJKL'
    print('[%2d]'%cnt)
    s = ''
    for i in range(n):
        s+=NAME[li.index(i+1)]
    print(s[:4]+'\n'+s[4:8]+'\n'+s[8:])
    print('')

def main():
    tm = time()  # Timer Start
    P  = range(1,12+1)
    # 1から12番のロッカーの周りのロッカーの番号のリストのリスト(※先頭はダミー)
    SA = [getSurroundings(n) for n in range(12+1)]
    S3 = [n for n in range(12+1) if len(SA[n])==3]  # 周りのロッカー数が3個のロッカー番号リスト
    S5 = [n for n in range(12+1) if len(SA[n])==5]  # 周りのロッカー数が5個のロッカー番号リスト
    S8 = [n for n in range(12+1) if len(SA[n])==8]  # 周りのロッカー数が8個のロッカー番号リスト
##    print(SA); print(S3,S5,S8)
    ld = []     # Dが使用している可能性があるロッカー番号のリスト
    cnt = 0
    for a in S3:                                                # 条件ア
        for e,i,j in itertools.permutations(SA[a]):             # 条件ア
            for b in S8:                                        # 条件イ
                for l in (1,5,9):                               # 条件エ
                    if l not in S5: continue                    # 条件オ
                    Q = list(set(P)-set([a,b,e,i,j,l]))
                    if len(Q)!=12-6: continue       # ダブっていないか調べる
                    for q in itertools.permutations(Q):
                        c,d,f,g,h,k = q
                        if f in SA[b]: continue                 # 条件イ
                        rc,cc = getRow(c),getCol(c) # Cのロッカーの行、列
                        ul = getN(rc-1,cc-1)        # Cのロッカーの左上のロッカー番号
                        ur = getN(rc-1,cc+1)        # Cのロッカーの右上のロッカー番号
                        if set([ul,ur])!=set([b,e]): continue   # 条件ウ
                        if g not in S5: continue                # 条件オ
                        if i not in S5: continue                # 条件オ
                        # チェックを潜り抜けたものだけを表示
                        cnt+=1
                        PrintResult(cnt,[a,b,c,d,e,f,g,h,i,j,k,l])
                        # 選択肢のチェック用
                        if d not in ld:
                            ld.append(d)

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

if __name__ == '__main__':
    main()

●実行結果

[ 1]
DGIA
LBJE
HKCF

[ 2]
DGIA
LBJE
KHCF

…(省略)…

[12]
KGIA
LBJE
HDCF

∴ [1, 2, 9, 10]
Runtime : 0.016 [sec]

※参考URL
SEND MORE MONEY in Python(3) - rscの日記
判断推理の部屋の位置関係の問題をPythonで解いてみた。 - rscのブログ
日能研のマインスイーパーに似たボードパズルの問題をPythonで解いてみた。 - rscのブログ
判断推理の家の位置関係の問題をPythonで解いてみた。 - rscのブログ
判断推理の家の位置関係の問題をPythonで解いてみた。(2) - rscのブログ