判断推理の部屋の位置関係の問題をPythonで解いてみた。

 判断推理の部屋の位置関係の問題Pythonで解いてみました。(^_^;

 図のような16の部屋からなる4階建てのワンルームマンションがある。
ここにA〜Hの8人がいずれかの部屋に1人ずつ住んでおり、A〜Hの8人が住んでいる以外の部屋は空き部屋となっている。
また、各階とも東側から西側に向かって1号室〜4号室の部屋番号となっている。次のア〜オが分かっているとき、これらから確実にいえるのはどれか。
ア.1階には3人住んでおり、3階と4階には2人ずつが住んでいる。
イ.Aは1階の1号室に住んでいる。また、他の階の1号室に住んでいる者は2人いる。
ウ.Eの両隣の部屋は空き部屋となっている。また、Bは、Eのすぐ下の部屋に住んでおり、かつDよりも下の階に住んでいる。
エ.Fは4号室に住んでいる。また、2号室に住んでいるのはDだけである。
オ.CとEは同じ階に住んでいる。また、GはDよりも下の階に住んでいる。
<選択肢>
1.AとHは同じ階に住んでいる。
2.BとCは同じ階に住んでいる。
3.Cは4階に住んでいる。
4.GはEのすぐ下の階に住んでいる。
5.Hは1号室に住んでいる。

 ただし、問題文を少し省略しました。(^_^;
 また、各部屋に0〜15の通し番号を付けました。4で割った商に1を加えて階を、4で割った余りに1を加えて何号室かを得ることができます。

      +------+------+------+------+
      |  12  |  13  |  14  |  15  |
      +------+------+------+------+
      |   8  |   9  |  10  |  11  |
      +------+------+------+------+
      |   4  |   5  |   6  |   7  |
      +------+------+------+------+
 東側 |   0  |   1  |   2  |   3  | 西側
------+------+------+------+------+------
       1号室 2号室 3号室 4号室

 16個の中から8個のものをとる順列で回すのは遅いので、条件から空室でない部屋の通し番号のタプルのリストを作成して部屋の位置を選んでおいて、8個の順列で回してみました。(^_^;

● Rooms1a.py

# coding: UTF-8
# Rooms1a.py

import itertools
from time import time

# 部屋の一覧表を作成
def mkRoomTable(p,q):
    r = ['x']*16
    for i in range(8):
        r[q[i]] = p[i]
    s = ''.join(r)
    return '|%s||%s||%s||%s|'%(s[:4],s[4:8],s[8:12],s[12:])

# r階のc号室の通し番号を得る
def getNum(r,c):
    return (r-1)*4+(c-1)

# 通し番号nから何階か調べる
def getRow(n):
    return n//4+1

# 通し番号nから何号室か調べる
def getCol(n):
    return n%4+1

# 通し番号のタプルtの中にn階の住人が何人いるか調べる
def getNumInRowOf(n,t):
    cnt = 0
    for i in t:
        if getRow(i)==n: cnt+=1
    return cnt

# 通し番号のタプルtの中にn号室の住人が何人いるか調べる
def getNumInColOf(n,t):
    cnt = 0
    for i in t:
        if getCol(i)==n: cnt+=1
    return cnt

# p,qからsの通し番号を得る
def getNumOf(s,p,q):
    return q[p.index(s)]

# 確実にいえる選択肢を得る
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
    P = 'ABCDEFGH'
    count = 0
    rooms = []  # 条件から空室でない部屋の通し番号のタプルのリストを作成
    for q in itertools.combinations(range(16),8):
        if getNumInRowOf(1,q)!=3: continue          # 条件ア
        if getNumInRowOf(3,q)!=2: continue          # 条件ア
        if getNumInRowOf(4,q)!=2: continue          # 条件ア
        if getNum(1,1) not in q:  continue          # 条件イ
        if getNumInColOf(1,q)!=3: continue          # 条件イ
        if getNumInColOf(2,q)!=1: continue          # 条件エ
        rooms.append(q)
##    print(rooms); exit()
    for p in itertools.permutations(P):
        if p[0]!='A': continue                      # 条件イ
        a = 0                       # Aの部屋の通し番号
        for q in rooms:
            d = getNumOf('D',p,q)   # Dの部屋の通し番号
            if getCol(d)!=2:           continue     # 条件エ
            f = getNumOf('F',p,q)   # Fの部屋の通し番号
            if getCol(f)!=4:           continue     # 条件エ
            b = getNumOf('B',p,q)   # Bの部屋の通し番号
            e = getNumOf('E',p,q)   # Eの部屋の通し番号
            if getCol(b)!=getCol(e):   continue     # 条件ウ
            if getRow(b)!=getRow(e)-1: continue     # 条件ウ
            if getRow(b)>=getRow(d):   continue     # 条件ウ
            c = getNumOf('C',p,q)   # Cの部屋の通し番号
            if getRow(c)!=getRow(e):   continue     # 条件オ
            g = getNumOf('G',p,q)   # Gの部屋の通し番号
            if getRow(g)>=getRow(d):   continue     # 条件オ
            rt = mkRoomTable(p,q)   # 部屋の一覧表を作成
            if 'xEx' not in rt:        continue     # 条件ウ
            h = getNumOf('H',p,q)   # Hの部屋の通し番号
            # チェックを潜り抜けたものだけを表示
            count+=1
            print('[%2d]'%count)
            print('%s\n%s\n%s\n%s'%(rt[18:],rt[12:18],rt[6:12],rt[:6]))
            # 選択肢のチェック
            choices[0] &= (getRow(a)==getRow(h))
            choices[1] &= (getRow(b)==getRow(c))
            choices[2] &= (getRow(c)==4)
            choices[3] &= (getRow(g)==getRow(e)-1)
            choices[4] &= (getCol(h)==1)

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

if __name__ == '__main__':
    main()

●実行結果

[ 1]
|HDxx|
|CxEx|
|xxBx|
|AxGF|
∴5
Runtime : 0.454 [sec]

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