マガジン

二人用ゲームを三人で遊ぶ:手番の順番が生む新しい駆け引き

遊びを見つける

執筆にClaudeを使用しています。

一つだけ空いた場所へ、丸い駒を置こうとする初めての一手。
記事のテーマをもとに制作したAI生成の写真風イメージ。

二人で石取りゲームを遊んでいるところに、横から三人目が「入れて」と言う場面を考えてみます。ルールは何も変えず、席が一つ増えるだけです。二人のときは「自分の手と相手の手」しかなかった盤面に、「自分の次の人」と「その次の人」という区別が生まれます。 この記事で確かめるのは、題名どおり次の問いです。二人用のゲームを三人で遊ぶと、手番の順番はどんな偏りと駆け引きを生むのか。 答えは記事の中には書いてありません。数十行のJavaScriptで席順ごとの負け率を数える試作と、紙と石を使った人間三人の観察の、二段構えで読者が自分で出す設計になっています。 先に注意しておくと、結果を予想して読み進めるより、予想を紙に書いてから試作を動かすほうが差がはっきり見えます。

この記事の目次
  1. 三人目が入ると、何が変わりうるのか
  2. 題材は「最後の石を取ると負け」の石取り
  3. 試作で席順の偏りを数える
  4. 記録の取り方と結果の読み方
  5. 人間三人で遊んで、駆け引きを観察する
  6. 起こりやすい誤り
  7. 作品づくりへつなげる場合の注意
  8. 次の行動

三人目が入ると、何が変わりうるのか

二人用ゲームの手番は交互です。自分の次の手番は必ず相手で、前の手番も必ず相手です。三人になると、この対称性が崩れます。

考えられる変化を、仮説として三つ挙げます。いずれも本当にそうなるかは未確認で、試作と観察で確かめる対象です。

  • 席の有利不利が変わる:二人用では「先手有利」「後手有利」の二択でした。三人では先手、二番手、三番手の三通りになり、偏りの形も変わりえます。
  • 同じ必勝法が通じなくなる:二人用で成り立つ「相手の動きを打ち消す手」は、手番が間に一人挟まると打ち消せなくなるかもしれません。
  • 誰を狙うかという選択が生まれる:二人用では敵が一人しかいません。三人では、自分の手が「次の人」と「その次の人」のどちらに有利になるかを選べます。

三つ目は盤面の数字ではなく人間の判断の話なので、試作では見えません。人間三人で遊ぶ段階で観察します。

題材は「最後の石を取ると負け」の石取り

題材には石取りゲーム(ニム)の一種を使います。ルールが短く、コードにしやすく、二人用では必勝法が知られているからです。人数を増やしたとき、その必勝法がどうなるかを比べる基準になります。

ルールは次のとおりです。

  1. 場に石をN個置きます(最初は21個にします)。
  2. 手番の人は、石を1個、2個、3個のどれかだけ取ります。残りが3個未満なら、残り全部までです。
  3. 最後の石を取った人が負けです。
  4. 席は1、2、3の順に回ります。席1が最初に取ります。

二人用のこのルールでは、残りが「4の倍数+1」(1、5、9、13、17、21…)の局面で手番を迎えた人が不利になることが、数学的に知られています。相手が毎回「自分と相手の合計が4になるように」取り返せるからです。そのため石21個の二人対局では、双方が最善を尽くすと、席1(先に取る人)が負けます。

この性質は「二人で、取り返しが4個ずつ合う」ことに依存しています。三人になると手番が三つで一巡するので、「合計4」の取り返しがそのままは使えません。ここが実験の焦点です。

三人用では「負けは一人だけ」と決めます。最後の石を取った一人が負けで、残る二人は勝ちです。この勝敗の決め方は、実験の設計上の選択です。「勝者を一人に絞る」ルールにすると、別の駆け引きが加わります。

試作で席順の偏りを数える

人間が遊ぶ前に、ブラウザの中で数万局を回して席ごとの負け率を出します。外部ライブラリもサーバーも不要です。次のコードを nim.html という名前で保存し、ブラウザで開くだけで動きます。

html
<pre id="out"></pre>
<script>
const rnd = n => 1 + Math.floor(Math.random() * Math.min(3, n));
const mod4 = n => { const t = (n - 1) % 4; return t === 0 ? 1 : t; };
const S = { random: rnd, mod4: mod4 };
function play(stones, seats) {
  let turn = 0;
  for (;;) {
    stones -= S[seats[turn]](stones);
    if (stones === 0) return turn;
    turn = (turn + 1) % seats.length;
  }
}
function run(stones, seats, games) {
  const loss = seats.map(() => 0);
  for (let i = 0; i < games; i++) loss[play(stones, seats)]++;
  return loss.map(x => (100 * x / games).toFixed(1) + "%").join(" / ");
}
const cases = [
  [21, ["random","random"]],
  [21, ["random","random","random"]],
  [21, ["mod4","random","random"]],
  [21, ["mod4","mod4","random"]],
];
let text = "";
for (const [n, seats] of cases)
  text += `石${n} ${seats.join(",")} 負け率(席1/席2/..): ${run(n, seats, 20000)}\n`;
document.getElementById("out").textContent = text;
</script>

二種類の打ち手を用意しています。

  • random:取れる範囲(1〜3個)から等確率で選びます。
  • mod4:二人用の必勝法です。残りから1を引いて4で割った余りの数だけ取り、余りが0なら1個取ります。二人用で最善を尽くす打ち手の代わりです。

出力の各行は、席1、席2、席3の順に「その席が最後の石を取って負けた割合」を並べたものです。

動かす前に予想を書く

実行する前に、次の四行それぞれについて、負け率が最も高い席と最も低い席を紙に書いておきます。

  1. random 二人
  2. random 三人
  3. mod4 が席1で、残り二人が random
  4. mod4 が席1と席2で、席3が random

予想を書いてから出力と比べると、「思っていた偏りと違った場所」が自分で見つかります。

変えて試す項目

cases の中身を書き換えると、問いを広げられます。

  • 石の数を変えます(20、22、23、25など)。二人用の必勝法は石の数で席の有利が入れ替わるので、三人では石の数ごとに偏りの形が変わるかを見ます。
  • mod4 を置く席を変えます(席2だけ、席3だけ)。
  • 席の並びを ["random","mod4","random"] のように入れ替えます。

記録の取り方と結果の読み方

何を、どの単位で、何回記録するか

  1. 条件(石の数、席ごとの打ち手)を一行に一つ書きます。
  2. 各行について、席ごとの負け率を記録します。
  3. 同じ条件で最低3回実行し、3回分を並べます。乱数を使うので、実行のたびに少しずつ値が変わります。
  4. 1回の局数は20,000局のままで構いません。値の揺れが気になるときは 20000 を 200000 に増やします。

局数の目安として、負け率が3分の1前後のとき、20,000局での偶然の揺れは±0.3〜0.7ポイント程度に収まるのが、一般的な統計の考え方です。席の間の差がこれより小さいときは、偏りがあるとは言えません。 実行を繰り返して、毎回同じ向きに差が出るかを見ると、判断しやすくなります。

結果の読み方(こうなればこう判断する)

  • random 三人で席の差が揺れの範囲内、考えられる解釈:乱数だけでは席の偏りが出ない、次にすること:石の数を変えて再確認する
  • random 三人でも毎回同じ席が高い、考えられる解釈:手番の順番そのものに偏りがある、次にすること:石の数ごとに偏りの席が変わるか調べる
  • mod4 を置くと、その席の負け率が大きく動く、考えられる解釈:打ち手の質が席の偏りを上回る、次にすること:mod4 を別の席に置いて同じ動きか確かめる
  • mod4 を置いても席1の負け率がほぼ変わらない、考えられる解釈:二人用の必勝法が三人では通じにくい、次にすること:石の数を変え、通じる条件があるか探す
  • mod4 の人が増えると、その人たちの負け率が逆に上がる、考えられる解釈:同じ手を打つ者同士が互いに影響している、次にすること:席の並びを入れ替えて確かめる

表の「解釈」はあくまで候補です。数字が出た時点で原因が確定するわけではなく、別の席・別の石数で同じ傾向が再現するかを見て、はじめて言えることが決まります。

人間三人で遊んで、駆け引きを観察する

試作で見えるのは、打ち手が決まっているときの偏りです。「誰を狙うか」という判断は、人間が遊ばないと見えません。

準備するもの

  • 石の代わりになる小物(コイン、ボタン、消しゴムのかけらなど)21個
  • 記録用の紙とペン
  • 三人(保護者と子どもの組み合わせでも構いません)

手順

  1. 席1、2、3を決めます。三局で席を一つずつずらし、全員が各席を一度ずつ経験します。 席の偏りと、人の腕前の差を切り分けるためです。
  2. 一局ごとに、取った個数を手番順に書き留めます。
  3. 負けた人を記録します。
  4. 席を回して、もう一局遊びます。これを三局(席が一巡)、できれば六局(二巡)繰り返します。
  5. 各局の途中で、相談してよいか決めます。最初の三局は相談なし、次の三局は相談ありにして、違いを比べます。

記録シートの例

  • 1、席1:人A、席2:人B、席3:人C、取った個数(手番順):、負けた席:、相談:なし
  • 2、席1:人C、席2:人A、席3:人B、取った個数(手番順):、負けた席:、相談:なし
  • 3、席1:人B、席2:人C、席3:人A、取った個数(手番順):、負けた席:、相談:なし

「取った個数」の列を埋めておくと、後で「あの局面で2個ではなく3個取っていたら」と振り返れます。

注目する場面

  • 自分が負けそうになったとき、残る二人のどちらかに有利になる取り方を選んでいないか。三人ゲームでは、自分が勝てなくなった人が、他の二人のどちらが勝つかを左右できる立場に立つことがあります。この立場は「キングメーカー」と呼ばれます。
  • 相談を許したとき、「二人で一人に負けを押しつける」動きが出るか。出る場合、どの局面から出始めるか。
  • 三人目の存在が見えにくくなる瞬間。二人用の感覚で「相手と自分」だけを考えていると、自分の次の人の存在を忘れる場面があるかもしれません。

こうした観察は、勝敗の数より「どんな取り方が出たか」「誰が何を言ったか」の記録のほうが後で役に立ちます。

起こりやすい誤り

  • 一局の結果で席の有利を決めてしまう:偏りは数十局以上の傾向で見るものです。人間の対局は数が少ないので、「席の偏りは試作、駆け引きは人間」と役割を分けます。
  • 「負け率」と「勝ち率」を取り違える:このゲームは最後に取った人が負けです。コードの出力は負け率なので、数字が高い席ほど不利です。
  • 石の数を一つに固定したまま結論を出す:二人用でも、石の数が一つずれるだけで有利な席が入れ替わります。三人でも同じことが起きうるので、複数の石数で確かめます。
  • 勝敗の定義を途中で変える:「負けは一人」から「最初に石を取り切った人が勝ち」に変えると、まったく別のゲームになります。途中で変えず、変えるなら別の実験として分けます。
  • 腕前の差を席の差と読み違える:同じ人が毎回同じ席に座ると、人の差と席の差が混ざります。席を回す手順はこのためです。
  • 乱数の揺れを傾向と読む:実行のたびに少し変わる数字を、一回だけ見て決めつけません。

作品づくりへつなげる場合の注意

アソバースのオンライン対戦は「潮目のオセロ」と「灯りのチェス」に限られ、リンクで友達を一人招待する二人対戦の仕組みです。投稿作品向けの共通対戦APIは未提供で、フレンドやチャットの機能もありません。三人用の石取りを作品として公開するなら、一つの画面を順番に使う形が現実的です。

この記事の試作は、HTMLファイル一つで外部通信なしに動く構成です。投稿できる形(直下の index.html を入口にしたHTML、またはZIP)にもそのまま近いので、席順の偏りを見る道具から遊べる作品へ育てることもできます。

次の行動

まず cases の四行について予想を紙に書き、nim.html を開いて三回ずつ実行します。差が揺れの範囲を超える行があれば、石の数を変えて再現するかを確かめます。そのうえで、家族や友達と三人で、席を回しながら六局遊び、記録シートの「取った個数」から「誰を狙った手か」を読み返してみてください。