ここにジュリアの答えがあります:私のアプローチは、原点の周りの同心円の正方形(「らせん」)に点を割り当て、(0,0)
各正方形は辺の長さを持ちm = 2n + 1
、キーとして位置番号(原点の1から始まる)を持つ順序付けられた辞書を生成することです値として対応する座標。
らせんごとの最大位置は で(n,-n)
あるため、残りのポイントは、このポイントから逆方向に作業するだけで見つけることができます。つまり、ユニットの右下隅からm-1
ユニットの垂直 3 セグメントを繰り返しm-1
ます。
このプロセスは、この逆のカウントプロセスではなくスパイラルがどのように進行するかに対応して、以下に逆の順序で書かれています。つまり、ra
[右昇順]セグメントは3(m+1)
、la
[左昇順]2(m+1)
は.
import DataStructures: OrderedDict, merge
function spiral(loc::Int)
s = sqrt(loc-1) |> floor |> Int
if s % 2 == 0
s -= 1
end
s = (s+1)/2 |> Int
return s
end
function perimeter(n::Int)
n > 0 || return OrderedDict([1,[0,0]])
m = 2n + 1 # width/height of the spiral [square] indexed by n
# loc_max = m^2
# loc_min = (2n-1)^2 + 1
ra = [[m^2-(y+3m-3), [n,n-y]] for y in (m-2):-1:0]
la = [[m^2-(y+2m-2), [y-n,n]] for y in (m-2):-1:0]
ld = [[m^2-(y+m-1), [-n,y-n]] for y in (m-2):-1:0]
rd = [[m^2-y, [n-y,-n]] for y in (m-2):-1:0]
return OrderedDict(vcat(ra,la,ld,rd))
end
function walk(n)
cds = OrderedDict(1 => [0,0])
n > 0 || return cds
for i in 1:n
cds = merge(cds, perimeter(i))
end
return cds
end
m = 3
したがって、最初の例では、方程式にプラグインして n を見つけるn = (5-1)/2 = 2
と、位置の順序付けられたディクショナリが座標に与えられます。これは、ディクショナリのフィールドwalk(2)
にアクセスすることで座標の配列に変換できます。vals
walk(2)
DataStructures.OrderedDict{Any,Any} with 25 entries:
1 => [0,0]
2 => [1,0]
3 => [1,1]
4 => [0,1]
⋮ => ⋮
[(co[1],co[2]) for co in walk(2).vals]
25-element Array{Tuple{Int64,Int64},1}:
(0,0)
(1,0)
⋮
(1,-2)
(2,-2)
一部の関数 [eg norm
] では、座標を ではなく配列のままにしておくことが望ましい場合がありますTuple{Int,Int}
が、ここでは、リスト内包表記を使用して、必要に応じて座標をタプル (<code>(x,y)) に変更します。
非正方行列を「サポートする」ためのコンテキストは指定されていません (このソリューションはまだグリッド外の値を計算することに注意しx
てくださいy
) 。からの値に対するこの行列。x=5
y=3
intersect
walk
grid = [[x,y] for x in -2:2, y in -1:1]
5×3 Array{Array{Int64,1},2}:
[-2,-1] [-2,0] [-2,1]
⋮ ⋮ ⋮
[2,-1] [2,0] [2,1]
[(co[1],co[2]) for co in intersect(walk(2).vals, grid)]
15-element Array{Tuple{Int64,Int64},1}:
(0,0)
(1,0)
⋮
(-2,0)
(-2,-1)