七行プログラミングとは
かつて、使える文字が「7行×79文字」という制限の元でコーディングの技術を競う、七行プログラミングと呼ばれるショートコーディング技術が流行ったそうです。
その流行の中で生まれたのが、以下に紹介する七行で動くテトリスです。
七行テトリスについて
七行テトリスはネット上で何種類かの亜種が見つかりますが、主だったものを紹介します。
- 498バイト版 (参考:たった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>
- 改良された487バイト版(参考:482バイトテトリス)
<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;h+=A;if(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,i-P)}Y(h=K=t=P=0)
</script>
これらのコードをテキストファイルに張り付け、「tetoris.html」といった適当な名前のhtmlファイルにすると、下の画像のようにCUIベースのテトリスを遊ぶことができます。
操作は矢印キーで移動、スペースキーで回転です(亜種の中にはEnterキーで回転するバージョンもあります)。
七行テトリスの短縮化
これらのコードについてですが、作成されたのはいずれも十年以上前という、古いコードになっています。
本記事はこれらのコードに対し、令和の今のJavaScriptならさらに文字数を削減できないかを試してみた内容になっています。
注意
- ロジック部分はそのままです(というか筆者の頭では理解しきれませんでした)
- あくまでJSの記法をいじって文字数をどうにかしよう、という方針です
七行テトリスからの変更点
その1: event.keyCodeをevent.whichに
キーボードから押下されたキーの取得方法である、event.keyCodeは現在Deprecatedになっており、現在のJSなら代わりにevent.keyやevent.codeを使うべきでしょう。
(参考:JavaScriptのキーボードイベント、キー判定にどれつかう?)
しかし、これらevent.keyやevent.codeは押下されたキーの「文字」を取得するものであり、数値である「キーコード値」を取得するものではありません。
七行テトリスのキーコードの処理は洗練されています。event.keyならevent.keyCodeより文字数を4文字減らせますが、キーコードを扱うためには結局それ以上の文字数がかかりそうです。
ここではevent.keyCodeの代わりに、Deprecatedですが同じくキーコードが取得できる、event.whichを使います。
### 修正前
onKeyDown=K=event.keyCode-38
### 修正後
onKeyDown=K=event.which-38
これで2文字減らせました。
その2: アロー関数を使う
今回最も大きな変更点になります。
function()の代わりに、ES2015から導入されたアロー関数を使うことで、文字数を大きく減らせます
### 修正前
function Y(){for...
### 修正後
Y=()=>{...
当然、const Y=
のように変数宣言はせず、グローバル変数として宣言することで文字数を節約します。
また、アロー関数にすることでブロックの末尾に;
を加えなければ動かなくなったので追加します。
### 修正前
...}Y(h=K=t=P=0)
### 修正後
...};Y(h=K=t=P=0)
これで12文字→6+1文字と5文字減らせました
その3: brタグをpタグに(※今回は実施せず)
現在のブラウザでは、<p>
タグは別に閉じなくても正常に動作します。
そこで、コード内でブロックを描画している箇所で、<br>
タグのかわりに<p>
タグを使うことにより、文字数を1文字減らせます。
### 修正前
"■<br>"
### 修正後
"■<p>"
しかしこれをやってしまうと、テトリスとして動作はするものの、画面全体が大きく縦に間延びしてしまうため、今回は見送りました
結果(479バイト)
上記2点の改良を加えたテトリスが以下の通り。6行に収めることができました。
文字数は476(全角文字を含む)、バイト数は479バイトとなります。
<body id=D onKeyDown=K=event.which-38><script>Z=X=[B=A=12];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;h+=A;if(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?"■":
"■<p>":"_");D.innerHTML=S+P;Z[5]||setTimeout(Y,i-P)};Y(h=K=t=P=0)</script>
その他修正箇所
ロジック部分を除けば、他にはonKeyDown
,innerHTML
,setTimeout
,<script>~</script>
などの文言が目につきますが、これ以上JSの記法を書き換えてコードを短縮化することは難しいのではないかと思います。
-
setTimeout
の代わりにrequestAnimationFrame
が使えるかもしれませんが、文字数が増えるだけです -
<script>
タグはもちろん必要ですし、閉じタグ</script>
は無ければ動作しません
そのため、これ以上短縮化するにはロジック部分の改良が必要になるかと思います。が、それは他の方に譲りたいと思います。
参考文献
参考:たった7行でテトリスを実装「七行プログラミング」とは
参考:482バイトテトリス
参考:JavaScriptのキーボードイベント、キー判定にどれつかう?