LoginSignup
2
2

More than 5 years have passed since last update.

ソリティアが、どのくらいの回数やれば成功するか、Pythonでシミュレーションしてみた

Last updated at Posted at 2018-01-03

ソリティア(*)が、どのくらいの回数やれば成功するか、Pythonでシミュレーションしてみた

(*)一般的なソリティアではない点注意。ルールはコメント参照。

my_solitaire.jpeg

solitaire.py

# 当該カードをひっくり返す
def updown(card):
    if card[2] == "D":
        card[2] = "U"
    else:
        card[2] = "D"
    return card

# 同一スーツ、1つ下の数値のカードを見つけて、下に連結する
def find(lane,lanes):
    b = False
    for ls in lanes:
        if ls != lane:
            for l in ls:
                if not len(lane)==0:
                    if(lane[len(lane)-1][0]==l[0] and \
                       lane[len(lane)-1][1]-1==l[1] and \
                       l[2]=='U'):
                        b = True
                        ix = ls.index(l)
                        for c in range(ix,len(ls)):
                            lane.append(ls.pop(ix))
    return b

# 空のレーンに、キング(に連なるカードたち)を移す
def king_move(lanes):
    b = False
    for ls in lanes:
        if len(ls)==0:
            for ls_ot in lanes:
                if len(ls_ot)>0 and len(ls)==0:
                    for l in ls_ot:
                        if l[1] == 13 and len(ls)==0:
                            ix = ls_ot.index(l)
                            if ix >0 and len(ls)==0:
                                b = True
                                for c in range(ix,len(ls_ot)):
                                    ls.append(ls_ot.pop(ix))
                                break
    return b

# トップに来た裏カードを、表にする
def top_faceup(lanes):
    b = False
    for ls in lanes:
        if not len(ls)==0:
            if(ls[len(ls)-1][2] =='D'):
                b = True
                updown(ls[len(ls)-1])
    return b

# エース(以降最小の)のカードがトップに来たら、外に出す 
def out_put(lanes):
    b = False
    for ls in lanes:
        if not len(ls)==0:
            for s in range(0,4):
                if(out_place[s][len(out_place[s])-1][0] == ls[len(ls)-1][0] and \
                   out_place[s][len(out_place[s])-1][1] == ls[len(ls)-1][1]-1 ):
                    out_place[s].append(ls.pop())
                    b = True
                    break
    return b


# メインループの始まり
import random

cn1=0 #試行回数
cn2=0 #成功数

# メイン
for k in range(0,10000):

    if k % 100 == 0:
        print(k)

    # 準備 ht:ハート、sp:スペード、di:ダイヤ、cb:クラブ
    out_place = [[['ht',0,'U']],[['sp',0,'U']],[['di',0,'U']],[['cb',0,'U']]]
    nums = [1,2,3,4,5,6,7,8,9,10,11,12,13]
    suits = ["ht","sp","di","cb"]
    cards = list()

    # 52枚の準備
    for s in suits:
        for n in nums:
            cards.append([s,n,"D"])
    random.shuffle(cards)

    # 7つのレーン
    lane = [list(),list(),list(),list(),list(),list(),list()]

    # カードの初期配置 ここから↓
    # 1枚表 6枚裏
    lane[0].append(updown(cards.pop()))
    for i in range(1,7):
        lane[i].append(cards.pop())
    # 1枚表 ●枚裏
    for j in range(1,7):
        lane[j].append(updown(cards.pop()))
        for i in range(j+1,7):
            lane[i].append(cards.pop())
    # 4枚ずつ表
    for j in range(1,5):
        for i in range(1,7):
            lane[i].append(updown(cards.pop()))
    # カードの初期配置 ここまで↑

    #なにか動く限り、ループ
    b1 = True
    while b1:
        b1 = False
        b1 = b1 or top_faceup(lane)
        b1 = b1 or out_put(lane)
        b1 = b1 or king_move(lane)
        for i in range(0,7):
            b1 = b1 or find(lane[i],lane)

    if sum(len(op) for op in out_place)-4 == 13*4:
        cn2=cn2+1
    cn1=cn1+1

print("全試行数:",cn1, " 成功数:",cn2, " 成功率:", "{0:.2f}%".format(cn2/cn1*100))



結果↓

10000回実施して、182回。 約2%弱。

全試行数: 100000  成功数: 4143  成功率: 4.14%

成功率4%ほど。 ※注:処理を一部修正後(ソース内"#なにか動く限り、ループ")

2
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2