ご存知、じゃんけんで階段登るゲームありますよね。
階段を登るときにじゃんけんをし、勝ったらその手に応じた歩数だけ階段を登っていき、先に登り切った方が勝ちになるというあれ。
単純なルールながら、パーとチョキは6歩、グーだけ3歩という露骨な不平等により、絶妙な駆け引きを生んでいます。
グーを「グリコのおまけ」とするバージョンもあり、その場合グーは7歩となって差は減ってしまうのですが、これは改悪と言わざるを得ないでしょう。
ちなみにWikipediaではグリコという名前で載っています(今知った)。
そして、そのWikipediaに、衝撃の一文が。
>相手がグー・チョキ・パーをいかなる割合で出してきても引き分けるには、グー・チョキ・パーを2:2:1の割合で出すと良い。
しかも要出典タグもついておらず、見事に断言されています。えっ、マジで?
最強のパターンを追究するつもりで書き始めたのですが、反証を示すべき命題が見つかったので非常に助かりました・・・。
では検証してみましょう。以下ソースコードです。
二人のプレイヤーが予め決められた割合に従ってランダムで手を選択し、定められた回数だけじゃんけんした後の歩数を表示します。
この場合、プレイヤー1はWikipediaの教えに従い2:2:1、プレイヤー2は1:1:1で手を出します。
#include#include #include #define TRY_MAX 100000 //試行回数 enum EnumHand{ H_G, H_C, H_P, H_MAX }; struct StrRate{ int g; int c; int p; }; //それぞれの手で勝ったときに進める歩数 const int steps[H_MAX] = { 3, 6, 6 }; //それぞれの手を出す割合 const StrRate r[2] = { { 2, 2, 1 },{ 1, 1, 1 } }; int GetHand(const StrRate* rate); int main(){ int step[2] = {0, 0}; for(int i = 0; i < TRY_MAX; ++i){ int hand[2]; for(int t = 0; t < 2; ++t){ hand[t] = GetHand(&r[t]); } for(int t = 0; t < 2; ++t){ if(abs(hand[t] + 3 - hand[(t + 1) % 2]) % 3 == 2){ step[t] += steps[hand[t]]; } } } printf("1:%d歩 2:%d歩\n", step[0], step[1]); return 0; } int GetHand(const StrRate* rate){ int h = rand() % (rate->g + rate->c + rate->p); if(h < rate->g){ return H_G; } else if(h < rate->g + rate->c){ return H_C; } else if(h < rate->g + + rate->c + rate->p){ return H_P; } return -1; }
結果。160101歩と160152歩。ほぼ互角になりました。
次はチョキの確率を上げてみましょう。勝った場合に6歩進めるのに負けても相手は3歩しか進めないすぐれものです。
プレイヤー2の手の割合を1:10:1にすると、130443歩と130398歩。やはりほぼ互角。
開き直って最弱のグーしか出さないようにすると、120876歩と119811歩。互角。
Wikipedia先生へ。疑ってごめんなさい。
細かい理論が知りたい方は「じゃんけんグリコ」の数学を見るとよいと思います。