プログラミング素人のはてなブログ

技術屋の末端。プログラミングも電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#、python3、ラズパイ始めました。

pythonで石取りゲーム

f:id:s51517765:20180802224836p:plain
石取りゲームとは、2人のプレーヤーが交互に決まった上限までの石を取っていって、最後の一個を取ったら勝ち(負け)というゲームです。

例えば、8個から始めて、一度に3個まで、最後の一個をと取ったほうが勝ちとすると、

先手3個
〇〇〇\〇〇〇〇〇
残り5個
後手2個
〇〇〇\〇〇\〇〇〇
残り3個
先手3個
〇〇〇\〇〇\〇〇〇\
残り0個

で、先手の勝ちです。

最後の一個を取ったら「勝ち」なのか「負け」なのかは、ローカルルールとかあるかもしれませんが、「負け」のほうが一般的なようです。
ここでは敢えて逆に最後の一個を取ったら「勝ち」として進めます。

この石取りゲームには必勝法があることは有名です。
この必勝法は一度にとれる数によって異なります。
一度にとれる数が3個であれば、のこりが4個になるように取れば必ず勝ちます。
(4個にさせられた相手が、1~3個のどれを選んでもその次の自分の手番ですべて取れます。)
残りが4個にするためには、その前の自分の手番で残りが8個になるようにします。
(8個にさせられた相手が、1~3個のどれを選んでもその次の自分の手番で4個にできます。)
残りが8個にするためには…(同様)

これを一般化すると、残りが4、8、12、16…となるようにします。
自分の手番で残りがn個であったら、n-4m個取ります。(nは自然数で、mはn-4m>0となる最大の自然数
これは、4で割った「余り」を表します。
これをプログラミング的に表すと、

toru=nokori%4

一度にとれる数をmaxとして、一般化すると、

toru=nokori%(max+1)

となります。

これをComputerとの対戦ゲームとしてプログラミングしました。

# -*- coding: utf-8 -*-

def main(nokori,teban):
    while nokori>0:
        if teban ==True:
            print("あなたの番")
            toru=120 #適当な初期値をいれて次のwhileをtrueにしている
            while(toru>nokori or toru>max): #プレイヤーの入力は、残りの石より多くてはダメ、一度にとれる最大よりも多くてはダメ
                toru = int(input())
            nokori-=toru
            teban=False #手番を反転
        else:
            print("COMの手")
            if nokori<=max:
                toru=nokori
            else:
                toru=nokori%(max+1)
                if toru==0:
                    toru=max
            print(str(toru)+"個とりました")
            nokori-=toru
            teban=True #手番を反転
        jugde(nokori,teban) #それぞれの手番ごとに局面を判定します

def jugde(nokori,teban):
    print("残り"+str(nokori)+"個")
    if nokori==0: #残りが0なら決着
        if teban==True:
            print("あなたの負け!")
        else:
            print("あなたの勝ち")

if __name__ == '__main__':
    max=3 #一度に取れる最大数、ただし2以上でないとゲームにならない
    nokori=12
    teban=False #Trueだと自分先手、Falseだと自分後手
    print("一度にとれるのは"+str(max)+"個まで。")
    print("最後の1個を取ったら勝ち!")
    print("残り" + str(nokori) + "個")
    main(nokori,teban)

必勝法を知っていると、先手は絶対負けません。
maxとnokoriを自由に変化させるとバリエーションができます。