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

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、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を自由に変化させるとバリエーションができます。