7行テトリスをMonicaを使って分解してみる
<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>
ネタ枠な投稿テストなので読んでもあまり面白くないと思います
前提知識
onkeydown | |
---|---|
キー | コード |
SPACE | 32 |
← | 37 |
↑ | 38 |
→ | 39 |
↓ | 40 |
Hi! Monica
適度な改行を入れて読みやすくしてください。
<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>
</body>
【参考】フローチャート
各変数の値の変化に着目して、スクリプトの流れを説明してください
Monica
以下に、各変数の値の変化に着目してスクリプトの流れを説明します。
初期化
Z, X, B, Aのすべてが12で初期化されます。これにより、ZとXは配列であり、最初の要素が12になります。
Z = X = [B = A = 12];
関数 Y() の呼び出し
h, K, t, Pがすべて0で初期化され、Y()関数が呼び出されます。
Y(h = K = t = P = 0);
最初のループ
初期化: C, q, c, iが4に設定されます。
fの計算: fはi-- * Kで計算されます。最初にiは4で、Kは0なので、fは0になります。iは3に減少します。
条件式: cはZ[h + (K + 6 ? p + K : C[i])]の結果に基づいて減少します。最初はhは0、Kは0なので、C[i]の計算が行われます。
pの更新: pはB[i]で更新されます。最初はB[3](初期化時にBは12)となります。
このループは、iが0になるまで続きます。
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];
}
次のループ
初期化: cの値に基づいて、hやBが更新されます。
i, Kの更新: iとKはq--の結果で更新されます。
fの加算: fはZ[A + p]の値が加算されます。
kの設定: X[p]に1が代入され、pが更新されます。
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;
}
条件チェックと新しい配列の初期化
fまたはBが真であれば、ZをXで更新し、新しい配列をXに設定します。
内部ループでは、lが0になるまで処理が行われ、条件に基づいてZの内容が更新されます。
if (f | B) {
for (Z = X, X = [l = 228], B = [[...]];
l--;) {
for (l % A ? l -= l % A * !Z[l] : (P += k++, c = l += A);
--c > A;) {
Z[c] = Z[c - A];
}
}
}
最終的な出力
出力文字列の生成: SにX[i]やZ[i]の値に基づいて文字列を追加します。
D.innerHTMLの更新: 最終的な文字列SとPをD要素に設定します。
再帰呼び出し
Z[5]が0であれば、Y()を再度呼び出します。
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);
まとめ
このスクリプトは、変数の値を動的に更新しながら、条件に基づいて様々な処理を行います。特にiの値の変化に注目すると、ループの各段階での変数の状態がどのように変わるかがわかります。最終的には、生成された文字列がHTMLに表示され、必要に応じて再帰的に関数が呼び出されます。
何気に嵌った所
- フローチャートの作図
フローチャートの作図でエラーを吐くのを修正できないので、
各ノードのテキストをダブルクォーテーションで囲むように指示をして修正したよ
- 「K+6?」の解釈
event.keyCodeは、押されたキーのASCIIコードを返します。これを基に、次のようにKが計算されます
Key | K |
---|---|
SPACE (32) | K = 32 - 38 = -6 |
← (37) | K = 37 - 38 = -1 |
↑ (38) | K = 38 - 38 = 0 |
→ (39) | K = 39 - 38 = 1 |
↓ (40) | K = 40 - 38 = 2 |
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;
}
「K + 6が真の場合、h += Kが実行され、hがKの値だけ増加します。ただし、SPACE(K = -6)の場合は何も実行されません。」
この回答に至るまでに、K = event.keyCode - 38の計算の説明とASCIIコードの説明をする必要がありました