Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

イメージ

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

n4o847
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした