マガジン

テトリスの7種類のブロックは、なぜその形なのか

遊びを見つける

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

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

落ちものパズルのブロックは、どれも4つの正方形をつないだ形です。ここで素朴な疑問が出てきます。4マスのつなぎ方は、本当に7通りしかないのでしょうか。ほかにも形があるのに、使われていないだけなのでしょうか。 この問いは、紙とペンで答えが出ます。ただし答えは「数え方」で変わります。回転して重なる形を同じとみなすか、裏返して重なる形まで同じとみなすかで、数は変わるからです。この記事では、4マスの形を自分の手で全部並べ、基準ごとに数え直す手順を示します。最後に、7という数がどの基準で出てくるかを読み解きます。 なお、なぜ4マスにしたのかという開発側の意図は、ここでは扱いません。見るのは、4マスの形が数の上でどう並ぶかだけです。

この記事の目次
  1. 数える前に決める「同じ形」の三つの基準
  2. 3マスから育てて4マスを並べる手順
  3. コードで確かめる
  4. 結果の読み方:7はどの基準の数か
  5. 起こりやすい誤り
  6. 次の行動

数える前に決める「同じ形」の三つの基準

四角を辺でつないだ図形を、一般にポリオミノと呼びます。4マスのものがテトロミノです。数える前に、どの形どうしを「同じ」とみなすかを決めておきます。基準は三つあります。

  • 固定、同じとみなす操作:平行移動だけ、呼び方の例:向きが違えば別の形
  • 回転のみ、同じとみなす操作:平行移動と回転、呼び方の例:裏返さないと重ならない形は別
  • 回転と裏返し、同じとみなす操作:平行移動・回転・裏返し、呼び方の例:鏡に映して重なる形も同じ

「つなぐ」は辺で接することを指します。角だけで触れている二つのマスは、つながっているとは数えません。ここを曖昧にすると、数が合わなくなります。

3マスから育てて4マスを並べる手順

いきなり4マスを描くと、重複や抜けが出ます。3マスの形に1マス足していく方法なら、漏れなく数えられます。

準備するのは方眼紙(またはノートの方眼)と鉛筆、消しゴムです。

  1. 3マスの形を全部描きます。一列に並んだ直線形と、角を一つ曲げたL字形の2種類です。
  2. 直線形の周囲で、辺が接する空きマスを一つずつ探します。端の延長、端の横、中央の横といった位置があります。それぞれに1マス足した形を描きます。
  3. L字形でも同じことをします。足せる位置を一つ残らず試し、描きます。
  4. 描いた形を一枚ずつ切り抜くか、付箋に写します。
  5. 切り抜きを机に並べ、「回転だけで重なるもの」を見つけて重ねます。重なるものは、向きだけが違う同じ形です。
  6. 回転では重ならなくても、裏返すと重なる組を探します。鏡像の関係にある形です。

記録は、次の表を紙に作って行います。単位は「形一つにつき一行」です。

  • 列1は、形の呼び名です。自分で付けた名前で構いません。
  • 列2は、見つかった向きの数です。回転だけで何通りの向きがあるかを書きます。
  • 列3は、裏返した形と重なるかどうかです。重なるなら「あり」、重ならないなら「なし」と書きます。

手作業は2回行うと確実です。1回目と2回目で形の総数が一致しなければ、足し忘れか重複があります。

コードで確かめる

手作業の結果は、短いプログラムで検算できます。下のコードをファイル(例: tetro.html)に保存してブラウザで開くと、1〜6マスの形を三つの基準で数えて表示します。外部のライブラリは使っていません。

html
<pre id="out"></pre>
<script>
const key = c => c.map(p => p.join(",")).sort().join(";");
const norm = c => {
  const mx = Math.min(...c.map(p => p[0]));
  const my = Math.min(...c.map(p => p[1]));
  return c.map(([x, y]) => [x - mx, y - my]);
};
const rot = c => norm(c.map(([x, y]) => [-y, x]));
const flip = c => norm(c.map(([x, y]) => [-x, y]));
function grow(shapes) {
  const next = new Map();
  for (const s of shapes.values()) {
    const have = new Set(s.map(p => p.join(",")));
    for (const [x, y] of s) {
      for (const [dx, dy] of [[1,0],[-1,0],[0,1],[0,-1]]) {
        const q = [x + dx, y + dy];
        if (have.has(q.join(","))) continue;
        const t = norm([...s, q]);
        next.set(key(t), t);
      }
    }
  }
  return next;
}
function classes(shapes, withFlip) {
  const seen = new Set();
  for (const s of shapes.values()) {
    let forms = [s], cur = s;
    for (let i = 0; i < 3; i++) { cur = rot(cur); forms.push(cur); }
    if (withFlip) forms = forms.concat(forms.map(flip));
    seen.add(forms.map(key).sort()[0]);
  }
  return seen.size;
}
let shapes = new Map([[key([[0,0]]), [[0,0]]]]);
let text = "";
for (let n = 1; n <= 6; n++) {
  if (n > 1) shapes = grow(shapes);
  text += `${n}マス: 固定 ${shapes.size} / 回転のみ ${classes(shapes, false)} / 回転と裏返し ${classes(shapes, true)}\n`;
}
document.getElementById("out").textContent = text;
</script>

仕組みは手作業と同じです。1マスから始めて、辺で接する空きマスに1マスずつ足し、平行移動で重なる形をまとめます。そのうえで、回転した形、裏返した形を同じ組に入れて数えます。

3マスの行で「固定 6 / 回転のみ 2 / 回転と裏返し 2」と出れば、動作は正しいと判断できます。直線形とL字形の2種類を向きまで数えると6通りになるため、手作業の結果ともつながります。

結果の読み方:7はどの基準の数か

4マスの行を見てください。数学的によく知られた数え方では、固定が19、回転のみが7、回転と裏返しが5になります。手元の結果がこれと違う場合は、先に「起こりやすい誤り」の節を確認してください。

読み方は次のとおりです。

  • 回転のみで数えると7になります。ゲームのブロックは盤上で回転させられますが、裏返す操作はありません。この操作と同じ基準で数えると、7種類になります。
  • 回転と裏返しまで同じとみなすと5になります。S字とZ字、J字とL字が、それぞれ鏡像の組として一つにまとまるためです。
  • 固定で数えると19です。内訳は、直線形2、正方形1、T字4、S字2、Z字2、J字4、L字4です。足し算すると19になるので、向きの数を数えた表と照らし合わせてください。

つまり、手元の表の列3が「なし」になる形が二組あります。S字とZ字、J字とL字です。この二組は、回転をどれだけ重ねても重ならず、鏡像どうしでだけ重なります。だから、回転しかできない前提では別々の部品として数え、5ではなく7になります。

ここで言えるのは、数の上での対応です。「4マスの形を、回転だけで同じとみなして並べ尽くすと、ちょうど7種類になる」という事実と、一般に知られる7種類の構成は一致します。作り手がその数え方を意図したかどうかは、この手順からは分かりません。

マス数を変えた行も見ておくと、数の変わり方がつかめます。3マスは回転のみで2種類で、並べるには少なめです。5マスは回転のみで18種類、回転と裏返しで12種類になり、種類が増えます。4マスは、全部の形を目で覚えられる範囲に収まっています。この「覚えられる量」という見方は、数から読み取れる範囲の感想として受け取ってください。

起こりやすい誤り

数が合わないときは、次の点を疑います。

  • 角だけで接する形を数えている。斜めに触れるだけの二つのマスは、つながっていません。
  • 向きが違うだけの形を二つ数えている。切り抜きを回して重ねて確かめます。
  • 鏡像を同じ形として落としている。回転のみの基準では、S字とZ字は別の形です。基準を決めてから数えます。
  • 3マスの形を描き漏らしている。直線形とL字形の2種類で全部です。ここが抜けると、4マスで漏れが出ます。
  • コードの貼り付けで、記号が全角になっている。[ や ; が全角になると動きません。

次の行動

方眼紙に3マスの2種類を描き、1マス足して4マスの形を全部切り出してみてください。次に、回転で重なる組と、裏返さないと重ならない組を分けて、19・7・5のどの数まで自分の表で再現できるかを確かめます。

そのうえでコードを動かし、5マスの行も読んでみてください。基準を一つ変えるだけで、数がどれだけ変わるかが見えてきます。