Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

隣接するマスへの差分の配列をワンライナーで生成する

初めに言っておくと、数式が覚えられないくらい複雑なので実用性はありません。これが簡単な数式だったらまだ使えたのですがね…普通に[[0,1],[1,0],[0,-1],[-1,0]]のように地道に書いたほうが早いです。

用途としては、forループ内で配列を使わないで生成ができるくらいです。

隣接マスまでの差分とは?

(x,y)にいたとして、(x-1,y)(x+1,y+1)のような座標のことです。8近傍は斜めを含み、4近傍は含みません。

ソースコード

console.log([...Array(9)].map((_, i) => [(i/3|0)-1,i%3-1])); // 8近傍(現在のマスを含む)
console.log([...Array(4)].map((_, i) => [(i-2)*(i%2),(i-1)*(1-i%2)])); // 4近傍(現在のマスは含まない)
console.log([...Array(5)].map((_, i) => [(i-2)*(i%2),(i-2)/2|0])); // 4近傍(現在のマスを含む)

以下のような配列が得られます。

[[-1,-1],[-1,0],[-1,1],[0,-1],[0,0],[0,1],[1,-1],[1,0],[1,1]]
[[0,-1],[-1,0],[0,1],[1,0]]
[[0,-1],[-1,0],[0,0],[1,0],[0,1]]

forと組み合わせて使う

for(let i = 0; i < 9; i++)
    const [dx, dy] = [(i/3|0)-1,i%3-1]; // 8近傍(現在のマスを含む)

for(let i = 0; i < 4; i++)
    const [dx, dy] = [(i-2)*(i%2),(i-1)*(1-i%2)]; // 4近傍(現在のマスは含まない)

for(let i = 0; i < 5; i++)
    const [dx, dy] = [(i-2)*(i%2),(i-2)/2|0]; // 4近傍(現在のマスを含む)

実用的なソース

console.log([[-1,-1],[-1,0],[-1,1],[0,-1],[0,0],[0,1],[1,-1],[1,0],[1,1]]);
console.log([[0,-1],[-1,0],[0,1],[1,0]]);
console.log([[0,-1],[-1,0],[0,0],[1,0],[0,1]]);
for(let i = 0; i < 9; i++)
    const [dx, dy] = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,0],[0,1],[1,-1],[1,0],[1,1]][i]; // 8近傍(現在のマスを含む)

for(let i = 0; i < 4; i++)
    const [dx, dy] = [[0,-1],[-1,0],[0,1],[1,0]][i]; // 4近傍(現在のマスは含まない)

for(let i = 0; i < 5; i++)
    const [dx, dy] = [[0,-1],[-1,0],[0,0],[1,0],[0,1]][i]; // 4近傍(現在のマスを含む)

解説

8近傍はみたままなので解説をしません。トリッキーなことをしている残り2つを解説します。

4近傍で得たいもの

4近傍では以下のような配列を得たいです。

[[0,-1],
[-1,0],
[0,1],
[1,0]]

コレを見ると、偶数、奇数のところが0になっていることがわかります。というかそうなるように並べたんですが。

ということは[index%2,1-index%2]としてやればつぎのような配列が得られます。

[[0,1],
[1,0],
[0,1],
[1,0]]

あとはindexが2未満のとき-1、indexが2以上のとき1をかけてやれば完成ですね。ただ、こうなるよう数式をいじるのは意外とめんどくさいので以下で代用しました。

  • iが1のとき-1、iが3のとき1を得られるi-2
  • iが0のとき-1、iが2のとき1を得られるi-1

現在のマスを含むパターン

現在のマスを含むほうは得る順番を若干変えることで数式をカンタンにしています。

[[0,-1],
[-1,0],
[0,0],
[1,0],
[0,1]]

真ん中が[0,1]から[0,0]になっています。こうすると、y座標の差分がカンタンに求めることができるようになります。