ゆるめ

ゆるめなのは公開範囲です。

452バイトテトリス

先日 7行テトリスのことを話題にしている人を見かけて、懐かしくなって巡ってきました。

7行テトリス482バイトテトリス6行テトリス464B tetris、と辿ったところで行き止まりになって、新しいものを見つけられなかったので、自分で書くことにしました。

デモページで動作の確認ができます。コードは以下の通りです。

ES201X を取り入れつついじったら、452バイト (Shift_JIS、LF で保存時) になりました。

<pre id=D><script>onkeydown=e=>K=e.which-38,Z=X=B=[],(Y=f=>{C=[A=12]
K&B.some((p,n)=>Z[h+(K+6?p+K:C[n]=p*A-(p/9|0)*145)])?0:K+6?h+=K:t?B=C:0;B.map(
q=>X[f|=Z[A+h+q],h+q]=1);if(f||1-B)for(Z=X,X=[l=228],B=[~[10,23,-3,-14,A][t=++t%
7],0,1,t-6?-A:2];l--;h=5)for(l%A?l-=l%A*!Z[l]:(P+=f++,K=l+=A);--K>A;)Z[K]=Z[K-A]
for(K=i=0,h+=A,S=P;i<240;)S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?~-i%A?'■':`
■`:'_';D.innerHTML=S;Z[5]||setTimeout(Y,i-P)})(h=K=t=P=0)</script>

80字越したら改行を入れるルールがあるみたいなので、それに準じました。

<pre id=D><script>onkeydown=e=>K=e.which-38,Z=X=B=[],(Y=f=>{C=[A=12]
K&B.some((p,n)=>Z[h+(K+6?p+K:C[n]=p*A-(p/9|0)*145)])?0:K+6?h+=K:t?B=C:0
B.map(q=>X[f|=Z[A+h+q],h+q]=1)
if(f||1-B)for(Z=X,X=[l=228],B=[~[10,23,-3,-14,A][t=++t%7],
0,1,t-6?-A:2];l--;h=5)for(l%A?l-=l%A*!Z[l]:(P+=f++,K=l+=A);--K>A;)Z[K]=Z[K-A]
for(K=i=0,h+=A,S=P;i<240;)S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?~-i%A?'■':`
■`:'_';D.innerHTML=S;Z[5]||setTimeout(Y,i-P)})(h=K=t=P=0)</script>

…と思っていたのですが、元々は 79文字 * 7行という制約だったみたいです。見逃していた記事があって、そこから判明しました。そちらに準じた場合は 451バイトになります。

改行も活用するため、セミコロンが外せそうな部分は積極的に外しています。

以下はテキストエディタの機能で JavaScript の部分のみそれっぽく整形したものです。

手を入れた部分のみコメントしています。他の方の書いた部分は他の方の解説をご覧になってください。

// "event" って変数が firefox になかったから JavaScript 内にしまった
onkeydown = e => K = e.which - 38,
// B を最初から配列扱いするため初期化時の判定方法を変更、副作用で [] 内での宣言が NG に
// "" とか 0 とかになる変数なら宣言できるけど今のとこ空配列
Z = X = B = [],
// いつも思うけどアロー関数ほんとぐっと縮まるね
// この f は初回以外は undefined だけど宣言済み変数として便利に使える
(Y = f => {
	// 上で追い出された A の宣言ここで
	// Array.prototype にくっついてるメソッド使うから Y で代用はできなかった
	C = [A = 12];
	// some() で接触フラグ作り、元のアルゴリズムには手を入れてない
	// 接触してた時はすぐ引き上げるから C が未完成になるけど問題ない
	K & B.some(
		// (p, n) の n 外に出して ++ とかしてみたけど、宣言と初期化で手間取って長くなった
		// n が外に出せれば (,) の三文字が削れてつよい
		(p, n) => Z[h + (K + 6 ? p + K : C[n] = p * A - (p / 9 | 0) * 145)]
	) ? 0 : K + 6 ? h += K : t ? B = C : 0;
	// f = undefined でもいいように |= にした
	// q => (式,式) だと () いるから [] 内にお邪魔させた
	B.map(q => X[f |= Z[A + h + q], h + q] = 1);

	// B を最初から配列にしたから判定長くなった
	// 1 - [] ⇒ 1 - "" ⇒ 1 - 0 で 1、1 - [1,1] ⇒ 1 - "1,1" ⇒ 1 - NaN で NaN
	if (f || 1 - B)
		for (Z = X, X = [l = 228], B = [~[10, 23, -3, -14, A][t = ++t % 7], 0, 1, t - 6 ? -A : 2]; l--; h = 5)
			// 設置判定時必ず 1 になってるから k の代わりに f 使うことにした
			// あと c 宣言する暇なかったから K 使い回した
			for (l % A ? l -= l % A * !Z[l] : (P += f++, K = l += A); --K > A; )
				Z[K] = Z[K - A];

	// K と i ここでリセット
	for (K = i = 0, h += A, S = P; i < 240; )
		// <pre> だから \n に、改行コード一文字にしてテンプレートリテラル使うとさらに一文字減
		S += X[i] | (X[i] = Z[i] |= ++i % A < 2 | i > 228) ? ~-i % A ? '■' : `
■` : '_';

	// innerText は何故か firefox でキー反応が悪くなるから無理だった
	// <body onload=""> も何故かキー反応が鈍ったから採用できなかった、採用できたら 3バイト縮む
	D.innerHTML = S;
	Z[5] || setTimeout(Y, i - P)

})(h = K = t = P = 0)

新しめの書き方を利用したアルゴリズムなんかでまだまだ縮まる余地が存分にあるので、つよい方々の登場が待たれます。


あと、せっかくなのでブックマークレットにしておきました。なんだかんだでいっつもせっかくしてる感じがします。
T⃞T⃞R⃞S⃞ - Hatena::Let


あとゴルフつながりで、先日 Hatena::Let で Fork して遊んだものも載せておきます。スターがたくさんなのは、たくさん更新してその度に更新箇所にスターをいただいたからで、ブツそのものは通常通りです。
Zalgolf ('unuse strict') - Hatena::Let