6行に収まりました。470文字です。
ただ、これを自分の手柄として書くつもりはありません。先に到達していた人がいます。2021年、Qiita に「六行テトリス」という記事が出ていて、476文字・479バイトで6行に収まったコードが載っています。私がそれを知ったのは、この連載を書き始めてからでした。
そのあたりの経緯は第2部に書きます。この記事は、そこへ至るまでの20年ぶんです。7行×79文字という制限がどこから来て、誰がテトリスを押し込んで、誰がそれを削っていったのか。
7行×79文字
七行プログラミングは、7行かつ1行79文字以内でプログラムを書く遊びです。合計553文字。この中でどれだけ動くものを作れるかを競います。
79という数字は、Unix 端末の横幅が80文字だったことから来ています。80文字目で折り返すので、実質1行に収まるのは79文字。ターミナルの画面に収まるサイズで書く、という制限です。
2001年から2004年ごろ、2ちゃんねるのプログラム技術板でスレッドが立ち、次々と作品が投稿されました。マンデルブロ集合、ライフゲーム、簡易エディタ、ミニゲーム。その中で最も知られているのが、7行のテトリスです。
498バイトのテトリス
コードを先に置きます。これが7行テトリスです。.html で保存すればブラウザで動きます。
| 1 2 3 4 5 6 7 | <body id=D onKeyDown=K=event.keyCode-38><script>Z=X=[B=A=12];function Y(){for(C =[q=c=i=4];f=i--*K;c-=!Z[h+(K+6?p+K:C[i]=p*A-(p/9|0)*145)])p=B[i];for(c?0:K+6?h +=K:t?B=C:0;i=K=q--;f+=Z[A+p])k=X[p=h+B[q]]=1;if(e=!e)if(h+=A,f|B)for(Z=X,X=[l= 228],B=[[-7,-20,6,h=17,-9,3,3][t=++t%7]-4,0,1,t-6?-A:2];l--;)for(l%A?l-=l%A*!Z[ l]:(P+=k++,c=l+=A);--c>A;)Z[c]=Z[c-A];for(S="";i<240;S+=X[i]|(X[i]=Z[i]|=++i%A< 2|i>228)?i%A?"■":"■<br>":"_");D.innerHTML=S+P;Z[5]||setTimeout(Y,99-P)}Y(h=e =K=t=P=0)</script> |
498バイト版。作者は nanagyou 氏。Qiita「たった7行でテトリスを実装『七行プログラミング』とは」より引用しました。

この498バイトに、次のものが全部入っています。7種類のテトリミノ、左右移動、回転、高速落下、壁と床とブロックの衝突判定、ライン消去、スコア表示、そして速度が上がっていくゲームオーバー判定。市販のテトリスと遜色ない機能が、498バイトに収まっています。

変数名は1文字。Z がフィールド、X が描画用バッファ、B が現在のブロック、A がフィールドの幅、h が落下中の位置。空白も改行も、ひとつも無駄がありません。
作者が分かるまでの5年
このコードは2ちゃんねるのスレッドに投稿されたもので、作者名が付いていませんでした。
2007年11月1日、Ozy 氏が自身のブログでこのコードを取り上げます。「明らかに縮みそうな箇所がありますね」という書き出しで、5行目の if(l%A)l-=l%A*!Z[l];else for(P+=k++,j=l+=A;--j>A;) を指して、ショートコーダーは else なんて書かない、と削り始めました。
その3日後、11月4日の記事で作者が判明します。nanagyou 氏。ショートコーディングの本にも名前が載っている方で、すでに自分のサイトで、もっと短い版を公開していました。Ozy 氏はその記事で、変数 e がウェイトをかけているだけなので省けそうだ、と書いています。
この往復で、498バイトが487バイト、482バイトへと削られていきました。投稿から5年経ってから、作者と第三者が公開の場でコードを削り合っている。掲示板文化の産物が、ブログ時代に持ち越されて磨かれた形です。
nanagyou 氏のサイトは GeoCities にあったので、いまは閉鎖されています。残っているのは、引用した先のコードと、それを解説した記事だけです。
7行の内訳
7行に何が詰まっているかを、機能ごとに見ておきます。第2部で削る対象になる部分です。
フィールドは幅12の1次元配列で持っています。10列のプレイ領域の左右に壁を1列ずつ足した12。2次元配列にせず1次元で持つことで、衝突判定が配列の値をひとつ見るだけで済みます。底は i>228 で判定していて、228 は 12×19。
テトリミノは、7種類ぶんの形状データを1つの配列に押し込んでいます。[-7,-20,6,h=17,-9,3,3] という7要素の配列から、t=++t%7 で順番に取り出す。回転は座標の算術変換ひとつで、p*A-(p/9|0)*145 という式が90度回転を担っています。
描画は文字列連結です。ブロックが ■、空きマスが _、行末で <br>。全角文字を使うことで、CSS を1文字も書かずに正方形のマス目が並びます。フォントの都合を利用して、レイアウトの記述を丸ごと省いている。
スコアは P+=k++ で、消した行数に応じてボーナスが付きます。落下速度は setTimeout(Y,99-P) で、スコアが上がるほど間隔が縮む。Z[5]|| がゲームオーバー判定で、フィールド上端にブロックが積まれるとタイマーが止まります。
読める人が読むと、まだ縮む
Ozy 氏の記事を読んで印象に残ったのは、削り方そのものより、削れる箇所が見えている人には見えているという事実のほうでした。
私がこのコードを最初に見たときは、何が書いてあるのかも追えませんでした。c-=!Z[h+(K+6?p+K:C[i]=p*A-(p/9|0)*145)] という式の中で、代入と三項演算子と単項マイナスが同時に走っている。読む順番すら分からない。
それを見て「else は要らない」と即座に指摘できる人がいる。同じコードを見ているのに、見えているものが違います。
2021年には、別の方がもう一段縮めています。Qiita の「六行テトリス」という記事で、アロー関数と event.which を使って476文字。7行の壁を越えて6行に入っています。私が同じ壁に挑んだのは、その5年後です。
次回
第2部では、私が作った470文字版のコードを全部出します。2021年の476文字版と並べて、どこが同じでどこが違うのかを見ます。
先に書いておくと、私の版のほうが6文字短いのですが、機能を削っているぶん短いだけです。向こうはゲームオーバー判定も速度の加速も残したまま476文字に収めています。数字だけ見ると勝っているように見えて、中身は負けている。そのあたりも含めて書きます。
もしこのコードを実際に動かしてみたいなら、.html で保存するだけです。上のコードをそのままコピーして、拡張子を .html にして開いてください。20年前のコードが、いまのブラウザでそのまま動きます。
参考
- たった7行でテトリスを実装「七行プログラミング」とは ── 498バイト版のコードと解説
- わずか565バイトテトリスのプログラミング解説(Ozy 氏) ── 短縮の着手
- 482バイトテトリス(Ozy 氏) ── 作者の特定と、もう一段の短縮
- 六行テトリス(Sotobato_Nihu 氏) ── 2021年、476文字で6行に収めた記録



コメント