石取りゲームとは、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を自由に変化させるとバリエーションができます。