マガジン

偶奇で解けるパズルを作る:石の数の偶数・奇数だけで勝敗が決まる遊び

遊びをつくる

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

一列をそろえたスライドパズルで、残りの絵柄を動かす順番を考える手元。
記事のテーマをもとに制作したAI生成の写真風イメージ。

机の上に石が7個あり、二人が交互に1個以上の「奇数個」を取ります。最後の石を取った人の勝ちです。この遊びでは、先手が必ず勝てます。7個ならまず1個取って6個を残し、以後は相手が取った数に関係なく、自分の番で全部取れる形に戻せるからです。石の数が偶数なら、立場は逆になります。 勝敗が石の数の偶数・奇数(パリティ)だけで決まるので、仕組みが分かれば誰でも勝てます。パズルとして作るなら、気づく前は不思議で、気づいた後は「なるほど」と言える状態にしたいところです。この記事では、その手前の問いを実験として扱います。どんなルールなら偶奇で勝敗が決まるのか。決まるルールのうち、どの見せ方なら気づくまでに手応えが残るのか。確かめる手順を、コードと記録表の形で用意しました。結果は書いていません。読者の手元で出すものです。

この記事の目次
  1. 1. 偶奇で決まる理由を、先に手で確かめる
  2. 2. 実験で確かめる二つの問い
  3. 3. 手順1:勝敗表をコードで出す
  4. 4. 手順2:気づくまでの回数を記録する
  5. 5. 結果の読み方と、起こりやすい誤り
  6. 次の行動

1. 偶奇で決まる理由を、先に手で確かめる

土台のルールは次のとおりです。山に石がN個あり、二人が交互に1個以上の奇数個(1、3、5……)を取ります。最後の石を取った人が勝ちです。

勝敗が偶奇で決まる理由は、次の三つで説明できます。

  1. 取る数が必ず奇数なので、一手ごとに残りの偶奇が入れ替わります。
  2. 残りが奇数の番なら、全部取れます。全部は奇数個なので、その場で勝ちです。
  3. 残りが偶数の番なら、どう取っても相手に奇数個を渡します。相手は全部取れるので、負けです。

つまり「自分の番で残りが奇数なら勝ち、偶数なら負け」です。先手が勝つのは、最初の個数が奇数のときです。

山を複数にしても理屈は変わりません。ただし、取る数は一つの山から奇数個です。全部の山の合計が偶数の番なら、どの山から取っても合計は奇数になります。合計が奇数なら、奇数個の山が必ずあるので、そこから1個取って合計を偶数に戻せます。山の分け方は見た目の飾りで、合計の偶奇だけが効きます。この「飾り」が、後半の実験の変数になります。

2. 実験で確かめる二つの問い

  • 問い1:取り方のルールを変えたとき、勝敗はどこまで偶奇で決まるか。
  • 問い2:偶奇で決まるルールを、見せ方の違い(山が1つか3つか)で、気づくまでの回数をどう変えられるか。

準備するものは次のとおりです。

  • ブラウザ(問い1のコード用)
  • 石の代わりになるもの(コインやクリップなど。画面上で作ってもかまいません)
  • 記録用の紙か表計算
  • 問い2のための、できれば5人以上の協力者

3. 手順1:勝敗表をコードで出す

勝敗を全探索で調べるコードです。次を check.html として保存し、ブラウザで開きます。外部ライブラリは不要です。

html
<pre id="out"></pre>
<script>
// win[n] : 石がn個で自分の番のとき、勝てるか
function solve(allowed, misere, max) {
  const win = [misere]; // 0個:通常は負け、最後に取ると負けなら勝ち
  for (let n = 1; n <= max; n++) {
    win[n] = false;
    for (let k = 1; k <= n; k++) {
      if (allowed(k) && !win[n - k]) { win[n] = true; break; }
    }
  }
  return win;
}
const rules = {
  "奇数個ずつ": k => k % 2 === 1,
  "1個か2個":   k => k <= 2,
  "1個か3個":   k => k === 1 || k === 3,
};
let text = "";
for (const misere of [false, true]) {
  for (const name in rules) {
    const w = solve(rules[name], misere, 16);
    text += (misere ? "最後に取ると負け " : "最後に取ると勝ち ") + name + "\n";
    text += w.map((v, n) => n + (v ? "○" : "×")).join(" ") + "\n\n";
  }
}
document.getElementById("out").textContent = text;
</script>

○は「自分の番で勝てる」、×は「自分の番では負ける」を表します。実行する前に、6通り(3つの取り方と、勝ちか負けかの2種)それぞれについて、○×の並びを紙に予想してください。予想と実行結果のずれが、ルールの理解のずれです。

読み方の基準は一つです。n=0から並べて、○と×が交互に現れるなら、偶奇で決まるルールです。2個ごと、3個ごとなど別の周期になるなら、偶奇ではなく別の割り算の余りで決まっています。

次に、自分の考えたルールを rules に1行足して試します。「奇数個、ただし最大5個まで」や「1個か、ちょうど4個」など、いくつか増やしてみてください。なお、このコードは山が1つの場合だけを扱います。山が複数あるときに合計の偶奇だけで済むと確かめられているのは、前節で考えた「奇数個を1つの山から取る」ルールだけです。他のルールで山を増やすなら、合計では決まらない可能性があります。

4. 手順2:気づくまでの回数を記録する

問い2は、人に遊んでもらって調べます。

条件の分け方

協力者を二つの組に分けます。A組は山が1つ、B組は山が3つ(合計は同じ数)で遊びます。同じ人に両方を遊ばせると、先に覚えたことが後に影響するので、組を分けてください。

石の初期個数は、事前に1回目から10回目まで決めて紙に書きます。奇数と偶数を混ぜ、全員に同じ順で出します。B組の山の分け方も事前に決めておきます。先手と後手は交互に入れ替えます。

一人あたりの流れ

  1. ルールだけを説明し、勝つコツは教えません。
  2. 一人10ゲームを遊びます。相手は、手順1の結果表どおりに指す人(または簡単なプログラム)にします。
  3. 毎ゲームの後、「次に勝つための方法を一言で」と聞き、答えをそのまま書き留めます。
  4. 10ゲームの後、遊んでいない配置を3つ見せ、「自分の番なら勝てるか」を答えてもらいます。

記録の単位

1ゲームを1行とします。

参加者 / 組 / ゲーム番号 / 初期個数(山の分け方) / 先手か後手か / 勝敗 / 手数 / 一言の答え

「気づいた」の判定は、手順の4で3つの配置すべてに正しく答えられたこと、かつその説明が偶奇に触れていることとします。そのうえで、どのゲーム以降の「一言」が偶奇に触れ始めたかを「気づいたゲーム番号」として参加者ごとに書きます。

5. 結果の読み方と、起こりやすい誤り

読み方

組ごとに「気づいたゲーム番号」を並べ、中央値と散らばりを見ます。5人程度では、差があっても傾向を示すにとどまります。断定には使えません。

次のように判断します。

  • 気づいた番号がA組より明らかに後ろに寄るなら、山の分割には偶奇を隠す効果がありそうです。
  • 差がなければ、分割は飾りにすぎず、別の工夫が必要です。たとえば、石を色で分ける、並べ方を変えるなど、合計を数えにくくする見せ方です。
  • 全員が早い回で気づくなら、簡単すぎます。誰も10ゲーム以内に気づかないなら、隠れすぎです。ここでの「早い」「遅い」の線は、実験の前に自分で決めておきます。後から決めると、結果に合わせてしまいます。

起こりやすい誤り

  • ○×の取り違え:「最後に取ると勝ち」と「負け」で、0個の扱いが逆になります。コードの misere を確認します。
  • 初期個数の偏り:偶数ばかりだと、先手が負け続けて「運が悪いだけ」に見えます。必ず混ぜます。
  • 相手役の弱さ:相手がランダムに指すと、気づかなくても勝てるため、観察がぼやけます。結果表どおりに指す相手を使います。
  • 説明のヒント漏れ:「残りに注目して」と言うと、実験が崩れます。ルール説明は一文ずつ決めておきます。
  • 後づけの解釈:予想を書かずに実行すると、どんな結果でも納得できてしまいます。

偶奇は、他のゲームにも顔を出します。たとえば、オセロの終盤では空きマスの偶奇が手番に関わるという考え方が一般に知られています。「潮目のオセロ」のひとり対局で、終盤の空きマスを数えながら遊ぶと、自分の目で観察できます。スライドパズルは、配置の偶奇で解けるかどうかが決まることが一般に知られています。「かたちのあいだ」の配置がどう作られているかは、作品を開いて確かめてください。

次の行動

まず check.html を保存し、6通りの予想を紙に書いてから実行してみてください。ルールを一つ足して勝敗表を作り直すと、偶奇で解けるルールと解けないルールの境目が分かってきます。そのうえで、ひとつ決めたルールを二人用の画面に仕立て、直下に index.html を置いて投稿すれば、遊んでもらう準備ができます。投稿の「遊び方・最大参加人数」は作者の申告で、共通の対戦機能を有効にするものではありません。同じ画面で二人が交代するつくりにするのが現実的です。