マガジン

天秤で偽物を見つけるゲーム:最少回数の推理

遊びをつくる

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

さまざまな小さなゲームの世界が並んだ棚を描いたイラスト。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

見た目が同じ9枚の硬貨のうち、1枚だけが重い偽物だとします。使えるのは、左右の皿を比べる天秤だけです。この条件で、偽物を必ず見つけるには何回はかればよいでしょうか。 多くの人は、まず4枚ずつ載せる場面を思い浮かべます。つり合えば残りの1枚が偽物、傾けば重い側の4枚から探し直しです。ここで「3回は要りそうだ」と感じます。実は2回で足ります。この「あと1回減らせる」という手応えが、天秤パズルをゲームにする核です。比較の回数を競うルールなら、画面上で、プレイヤーの分け方がそのまま点数に変わります。 この記事は、この古典問題をブラウザゲームにして、遊ぶ人が最少回数に届くかどうかを自分で確かめるための実験設計書です。結果は書きません。コードと記録の取り方を用意するので、手元で集めて判断してください。

この記事の目次
  1. 数え方の下地:1回の天秤は3通りの答えを返す
  2. 実験の問いと準備するもの
  3. 手順と記録の取り方
  4. 結果の読み方
  5. 起こりやすい誤り
  6. 次の行動

数え方の下地:1回の天秤は3通りの答えを返す

はかった結果は「左が重い」「右が重い」「つり合い」の3通りです。k回はかれば、結果の並びは最大で3のk乗通りになります。偽物の候補がそれより多ければ、どう工夫しても見分けられません。

偽物が「重い」と分かっている場合、見分けられる硬貨の最大枚数は次のとおりです。

  • 1回、見分けられる最大枚数:3枚
  • 2回、見分けられる最大枚数:9枚
  • 3回、見分けられる最大枚数:27枚

9枚を2回で見つけるには、最初に3枚対3枚で比べ、机に3枚を残します。結果にかかわらず、候補は3枚に絞られます。残り1回で、1枚対1枚にして1枚を机に残せば決まります。

この考え方から、設計の判断基準になる規則が出ます。残りk回なら、はかった後に残る候補の塊は、どの結果でも3の(k−1)乗枚以下でなければなりません。2回で9枚なら、左・右・机のどれも3枚以下です。この規則を、実験で人の手とすり合わせます。

偽物が重いか軽いかが分からない場合は、12枚を3回で見分けられることが古典として知られています。ただし、それを遊べるようにするには別のコードが必要です。この記事は「重い偽物が1枚」の版に絞ります。

実験の問いと準備するもの

実験で確かめる問いは次の3つです。

  1. 枚数Nが同じとき、プレイヤーは理論上の最少回数に届くか。
  2. 届かない人は、最初の分け方のどこでつまずくか。
  3. Nを変えると、最少回数に届く割合はどう変わるか。

準備するものは、次の4つです。

  • 下のHTMLを保存したファイル(1枚で動き、外部通信は不要です)
  • 遊んでもらう人。ルールを知らない人と知っている人を、分けて数えます。
  • 記録用の表(下の「手順と記録」参照)
  • 時間を測る道具(任意)

コードは、硬貨をクリックして「机・左・右」を切り替え、「はかる」で結果を履歴に積みます。偽物と思う硬貨の「偽物?」を押すと答えになり、記録が画面に出ます。枚数は先頭のNで変えます。

html
<!doctype html>
<meta charset="utf-8">
<title>天秤の推理</title>
<div id="coins"></div>
<p><button id="w">はかる</button> <button id="n">新しい問題</button></p>
<p id="log"></p>
<ol id="h"></ol>
<script>
const N = 9; // 硬貨の枚数。ここを変えて試します
const rec = [];
let fake, count, side, done;
const $ = id => document.getElementById(id);
function start() {
  fake = Math.floor(Math.random() * N);
  count = 0; done = false;
  side = Array(N).fill(0); // 0=机 1=左 2=右
  $('h').innerHTML = '';
  $('log').textContent = N + '枚のうち1枚が重い偽物です。';
  draw();
}
function draw() {
  $('coins').innerHTML = '';
  side.forEach((s, i) => {
    const m = document.createElement('button');
    m.textContent = (i + 1) + [':机', ':左', ':右'][s];
    m.onclick = () => { if (!done) { side[i] = (side[i] + 1) % 3; draw(); } };
    const a = document.createElement('button');
    a.textContent = '偽物?';
    a.onclick = () => answer(i);
    $('coins').append(m, a, document.createElement('br'));
  });
}
$('w').onclick = () => {
  if (done) return;
  const L = side.filter(s => s === 1).length;
  const R = side.filter(s => s === 2).length;
  if (L === 0 || L !== R) { $('log').textContent = '左右の枚数をそろえてください(数えません)。'; return; }
  count++;
  const r = side[fake] === 1 ? '左が重い' : side[fake] === 2 ? '右が重い' : 'つり合い';
  const li = document.createElement('li');
  li.textContent = '左' + L + '枚 対 右' + R + '枚 → ' + r;
  $('h').append(li);
};
function answer(i) {
  if (done) return;
  done = true;
  rec.push({ n: N, weighings: count, ok: i === fake });
  $('log').textContent = (i === fake ? '正解' : '不正解') + '。はかった回数は' + count + '回。記録:' + JSON.stringify(rec);
}
$('n').onclick = start;
start();
</script>

手順と記録の取り方

最少回数を先に決めておく

Nごとの理論上の最少回数は、表の枚数から決まります。

  • N=3は1回です。
  • N=4から9は2回です。
  • N=10から27は3回です。

注意点として、N=8でも最少は2回です。3枚・3枚・2枚と分ければ足ります。実験の前に、この対応を記録表の列に書き込んでおきます。

進め方

  1. 練習としてN=3を1回だけ遊んでもらいます。操作に慣れてもらうのが目的で、記録には入れません。
  2. 本番のNを、人ごとに順番を入れ替えて渡します。たとえば、ある人は9→8→27、別の人は27→9→8のようにします。順番が固定だと、「前の問題で学んだ分」が結果に混ざります。
  3. 同じNを1人につき3回ずつ遊んでもらいます。1回だけでは偶然との区別がつきません。
  4. 遊んでいる間はヒントを出さず、「最少回数がある」ことも伝えません。伝えると、最初の分け方に影響します。
  5. 遊び終えるたびに、画面の記録と、最初の1回の分け方を書き留めます。

1回ごとに記録する項目

  • 参加者、記録する内容:名前ではなく番号(ルール既知かどうかも記入)
  • N、記録する内容:硬貨の枚数
  • 回数、記録する内容:画面に出る「はかった回数」
  • 最少との差、記録する内容:回数から理論上の最少を引いた値
  • 最初の分け方、記録する内容:左・右・机の枚数(例:3・3・3)
  • 正誤、記録する内容:画面の正解/不正解
  • 時間、記録する内容:任意。1回あたり、開始から答えまで

画面の記録はページを閉じると消えます。1人ごとに表へ転記してください。

結果の読み方

結果が出たら、まず「最少との差」を見ます。差が0の割合を、Nごとに出します。

次に、最初の分け方で分類します。見るのは、左・右・机のどれかが、残りの回数で処理できる上限を超えていないかです。

  • N=9なら、3・3・3の人は規則を満たしています。4・4・1の人は、傾いたときに4枚が残り、2回目では1回に収まりません。
  • N=8でも、4・4・0の人は、傾いたときに4枚が残るので、全体で3回になります。3・3・2なら2回で収まります。
  • N=27なら、9・9・9が規則を満たす分け方です。

読み方の例を挙げます。

  • 差が0の人の多くが規則を満たす分け方をしているなら、最少回数に届けるかどうかは、最初の1手でほぼ決まります。ゲームの山場は最初の分け方に置けます。
  • 規則を満たす分け方でも差が0にならない人がいるなら、2回目以降の分け方でつまずいています。履歴の見せ方や、候補が残っている硬貨の目印を足す価値があります。
  • ルール既知の人としない人で差が大きいなら、この問題は「知っているか」で決まる面が強いと読めます。初見の人向けに、枚数を3→9→27と段階的に増やす導線が必要です。
  • どのNでも差が0の人がほとんどいなければ、難しすぎます。硬貨の候補を絞り込んだ状態を示す、一手ヒントを足すことを考えます。

N=3でほぼ全員が最少なのは、たぶん当然です。見るべきなのは、Nを上げたときに差が0の割合が下がり始める位置です。そこが、このゲームの難易度の曲がり角になります。

起こりやすい誤り

  • 偶然の正解を最少回数と混ぜる。 コードは、はかる前でも答えを押せます。N=9で0回のまま当てた人は、運の正解です。表では、回数が最少を下回る記録は別枠にして集計から外してください。
  • 回数が少なすぎる。 1人1回だけでは、偶然と実力を分けられません。人数が少ないときは、人数を増やすより、同じ人の回数を増やすほうが読みやすくなります。
  • 順番の偏り。 Nの順番を固定すると、学習の効果がNの違いに見えます。入れ替えを忘れないでください。
  • 数えない失敗の混入。 左右の枚数が違うと、コードは回数を数えません。ただし、この操作が多い人は、規則を理解していないかもしれません。回数とは別にメモしておくと、説明画面の改善材料になります。
  • 偽物の位置の偏り。 偽物はランダムですが、少ない回数では偏って見えることがあります。位置が原因に見えたときは、回数を増やして確かめてください。
  • 対象外の版を混ぜる。 「重いか軽いか分からない」版は、このコードでは動きません。結果の分け方も変わるので、別の実験にしてください。

次の行動

まず上のコードをファイルに保存し、N=9で自分で1回遊んでみてください。そのうえで、2〜3人にNの順番を入れ替えて渡し、記録表に「最少との差」と「最初の分け方」を書き留めます。この単独のHTMLは、index.htmlとしてアソバースの投稿画面に入れられます。公開前の表示確認で、操作が伝わるかを見られます。