LoginSignup
1
1

More than 5 years have passed since last update.

1ツイートに収まる15パズル.html

Last updated at Posted at 2018-04-06

イメージ

image.png

注意

  • Chrome でのみ動作確認
  • 矢印キーで操作
  • 文字が小さいので、拡大はセルフサービス

v2

<pre id=p><script>a=`①②③④
⑤⑥⑦⑧
⑨⑩⑪⑫
⑬⑭⑮ 
`.split``
q=18
M=d=>!a[Q=q-(d&1?d*5-9:d)+1]||Q%5>3||d&-4||(a[q]=a[Q],a[q=Q]=` `)
A=a+``
S=_=>p.innerHTML=a.join``+(a==A)
for(i=334;i--;)M(Math.random()*4|0)
for(i=6;i--;)M(i&1)
S(onkeydown=e=>S(M(e.keyCode-37)))</script>
  • 操作性のため onkeyup -> onkeydown
  • 座標を1つにまとめた
  • 初期位置を右下にする余裕ができた

v1

<pre id=p><script>
a=`①②③④
⑤⑥⑦⑧
⑨⑩⑪⑫
⑬⑭⑮ 
`.split``
r=c=3
M=d=>(d|(R=r,C=c,d&1?R-=d-2:(C-=d-1)))&-4||(a[r*5+c]=a[R*5+C],a[(r=R)*5+(c=C)]=" ")
A=a+""
S=_=>p.innerHTML=a.join``+(a==A)
for(i=334;i--;)M(Math.random()*4|0)
S(onkeyup=e=>S(M(e.keyCode-37)))
</script>

<pre id=p>

閉じタグがなくても動きます。idhoge を設定することで、その要素を window.hoge で参照できます。クオーテーションは不要です。<pre> にしたのは、改行をそのまま出力するためです。


a=`①②③④
⑤⑥⑦⑧
⑨⑩⑪⑫
⑬⑭⑮ 
`.split``

r 行目 c 列目の要素に、a[r*5+c] でアクセス出来るようにします。
.split`` は「タグ付きテンプレートリテラル」と呼ばれるもので、JavaScript のコードゴルフでは splitjoin と組み合わされることで威力を発揮します。


r=c=3

空白部分の座標です。


M=d=>(d|(R=r,C=c,d&1?R-=d-2:(C-=d-1)))&-4||(a[r*5+c]=a[R*5+C],a[(r=R)*5+(c=C)]=" ")

これはわかりづらいので、優先順位などを考慮して見やすくすると

M = d => {
  R = r;
  C = c;
  _RC = (d & 1) ? (
    R -= d - 2
  ) : (
    C -= d - 1
  );
  (d | _RC) & -4 || (
    a[r*5+c]=a[R*5+C],
    a[(r=R)*5+(c=C)]=" "
  );
};

M は移動のための関数です。
まず (r, c)(R, C) として保持します。
移動方向 d0 1 2 3 のいずれかであると仮定して、それぞれ ← ↑ → ↓ を割り当てます。「d が奇数なら行番号を d - 2 減らし、偶数なら列番号を d - 1 減らす」という操作は、実際に追ってみると正しいことがわかります。
ここで、「d0 1 2 3 のいずれでもない場合」「R または C (変化した方が _RC に入る)が 0 1 2 3 のいずれでもなくなった場合」が考えられます(d については後述)。
これを (d | _RC) & -4 で、「d_RC の下位2ビット以外にビットが立っているかどうか」という判定をします。
hoge || fugaif (!hoge) { fuga } のようなものです。つまり、「d_RC の下位2ビット以外にビットが立っていなければ」⇔「d_RC が両方とも 0 1 2 3 に収まっていれば」、次を実行します。
この条件次第で、(r, c)(遷移前)と (R, C)(遷移後)の入れ替え操作が行われます。


A=a+""
S=_=>p.innerHTML=a.join``+(a==A)

a を文字列化したものを A に保存しておきます。
S は表示のための関数です。== はゆるい比較演算子なので、a == Aa は文字列に型変換され、初期状態と一致しているかが判定されます。


for(i=334;i--;)M(Math.random()*4|0)

Math.random()*4|00 1 2 3 のいずれかをランダムに返します。これで好きな回数だけ空白をかき混ぜます。


S(onkeyup=e=>S(M(e.keyCode-37)))

window.onkeyup 時に、キーコードを読み取って M し、S します。
← ↑ → ↓37 38 39 40 が割り当てられているため、37 を引いて M に渡せば、前述のようにバリデーションしてくれるというわけです。
最後に初期状態を S して終わりです。

最後に

Twitter の文字数制限が変更されて、いい感じにプログラムが収まる程度になったので、みなさんもいろいろ挑戦してみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1