女王の螺旋を歩く


13

遠く離れた王国では、チェスの女王は1からまでの番号が付けられたらせん状の小道を毎日歩いておりn、スパイラル自体に追従するのではなく、単にチェス盤でするように女王の動きをします。女王は彼女の被験者に愛され、彼らは彼女が彼女の道を訪問するすべての広場を書き留めます。女王が任意の正方形で散歩を開始し、任意の正方形でそれを終了できるとすると、女王が歩くことができる最短の女王の散歩は何ですか?

チャレンジ

長方形のグリッドに整数のスパイラルが与えられた場合、チェスのクイーンの動きを使用して、このスパイラルグリッド上の2つの数値間の最短経路(移動したセルの数で数えられる)の1つを返す関数を記述します。

たとえば、from 16から25

25 10 11 12 13
24  9  2  3 14
23  8  1  4 15
22  7  6  5 16
21 20 19 18 17

可能なパスには、16, 4, 2, 10, 25およびが含まれ16, 5, 1, 9, 25ます。

ルール

  • 入力は任意の2つの正の整数になります。
  • 出力は、直交移動と斜め移動のみを使用して、らせんを横切る整数のパス(両方の端点を含む)になります。
  • パスの長さは、移動したセルの数によってカウントされます。
  • あなたの答えはプログラムか関数かもしれません。
  • これはコードゴルフなので、最小バイト数が優先されます。

いつものように、問題が不明な場合はお知らせください。幸運と良いゴルフを!

テストケース

>>> queen_spiral(4, 5)
4, 5
>>> queen_spiral(13, 20)
13, 3, 1, 7, 20
>>> queen_spiral(14, 14)
14
>>> queen_spiral(10, 3)
10, 11, 3
>>> queen_spiral(16, 25)
16, 4, 2, 10, 25
>>> queen_spiral(80, 1)
80, 48, 24, 8, 1


5
(たとえば、ユークリッド距離とは対照的に)移動したセルの数で最短経路を探していることを言及する必要があるかもしれません。
Martin Ender

1
これは「王様の散歩」としてもっと意味があると思いませんか?
ジョーキング

1
@JoKingああ、あなたがそれを言ったので、それは王の散歩になるはずです。ただし、タイトルの変更には少し遅れる場合があります。
Sherlock9

回答:


5

APL(Dyalog Unicode)59 57バイトSBCS

{v⍳+\v[⍺],↓⍉↑(|⍴¨×)⊃⍵⍺-.⊃⊂v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵}

オンラインでお試しください!

-ngnのおかげで-2バイト。

2つのエンドポイントを左と右の引数として受け入れる無名関数。

ゴルフをしていないとそれがどのように機能するか

クイーンは最初に対角線上に移動するため、までの各数値の座標を事前に計算するだけで十分max(start,end)です。

座標生成アルゴリズムは、関連する課題に関するいくつかの回答から発想を得ていますが、既存の回答とは少し異なります。

  • 必要な10の限界を考える
  • 1ベースの範囲を生成する r=1 2 3 4 5 6 7 8 9 10
  • それぞれの数の半分の天井を取りなさい n=1 1 2 2 3 3 4 4 5 5
  • rbyの各アイテムを複製しnます。1 2 3 3 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 9 10 10 10 10 10
  • 開始点を0として、虚数単位の累乗の累乗をとります(この部分は、リンクされた課題に対するさまざまなPythonソリューションに共通です)。

座標のベクトルが一旦、v準備ができている、我々は簡単に使用スパイラルインデックスと座標との間で変換することができv[i]及びv⍳coord(の最初のインデックス見つけるcoordにはv)。

 Define a function; ⍺=start, ⍵=end
f←{
   Construct a vector of spiral coordinates v
  v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵
                             ⍺⌈⍵   max of start, end
                                  range of 1 to that number
                   {⍵/⍨⌈⍵÷2}   for each number n of above, copy itself ceil(n/2) times
               0j1*   raise imaginary unit to the power of above
           +\0,       prepend 0 and cumulative sum
                      (gives vector of coordinates as complex numbers)
    9 11∘○¨   convert each complex number into (real, imag) pair
  v          assign it to v

   Extract start and end coordinates
  a w←(⍺⊃v)(⍵⊃v)

   Compute the path the Queen will take
  v⍳+\(a),↓⍉↑(|⍴¨×)w-a
                    w-a   coordinate difference (end-start)
              (|⍴¨×)      generate abs(x) copies of signum(x) for both x- and y-coords
                          e.g. 4 -> (1 1 1 1), ¯3 -> 1 ¯1 ¯1)
           ↓⍉↑   promote to matrix (with 0 padding), transpose and split again
                 (gives list of steps the Queen will take)
    +\(a),      prepend the starting point and cumulative sum
                 (gives the path as coordinates)
  v   index into the spiral vector (gives the spiral numbers at those coordinates)
}

(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
ngn

(⍺⌷v)->v[⍺]
ngn

3

Mathematica 615 530バイト

これは、数値グリッドを作成し、それをグラフに変換してから、入力された2つの数値間の最短経路を見つけます。


アンゴルフ

numberSpiralMathworld Prime Spiralからです。n行n列のUlamスパイラルを作成します (素数を強調表示しません)。

findPath数値グリッドをグラフに変換します。エッジは、数値グリッド上で有効なクイーンの動きです。


numberSpiral[n_Integer?OddQ]:= 
  Module[{a,i=(n+1)/2,j=(n+1)/2,cnt=1,dir=0,len,parity,vec={{1,0},{0,-1},{-1,0},{0,1}}},a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=cnt++;{i,j}+=vec[[dir+1]],{k,len}];dir=Mod[dir+1,4],{parity,0,1}],{len,n-1}];a];  

findPath[v1_, v2_] := 
  Module[{f, z, k},
    (*f  creates edges between each number and its neighboring squares *)
    f[sp_,n_]:=n<->#&/@(sp[[Sequence@@#]]&/@(Position[sp,n][[1]]/.{r_,c_}:>Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1}, {r+1,c-1}},{x_,y_}/; 0<x<k&&0<y<k]));k=If[EvenQ[
     z=\[LeftCeiling]Sqrt[Sort[{v1, v2}][[-1]]]\[RightCeiling]],z+1,z];
    FindShortestPath[Graph[Sort/@Flatten[f[ns=numberSpiral[k],#]&/@Range[k^2]] //Union],v1,v2]]

findPath[4,5]
findPath[13,22]
findPath[16,25]
numberSpiral[5]//Grid

{4,5}

{13、3、1、7、22}

{16、4、1、9、25}

グリッド


80から1への最短パスには、6つではなく5つの頂点が含まれます。

findPath[80,1]
numberSpiral[9]//Grid

{80、48、24、8、1}

81グリッド


ゴルフ

u=Module;
w@n_:=u[{a,i=(n+1)/2,j=(n+1)/2,c=1,d=0,l,p,v={{1,0},{0,-1},{-1,0},{0,1}}},
a=Table[j+n(i-1),{i,n},{j,n}];
Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]],{k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];a];
h[v1_,v2_]:=u[{f,z},
s_~f~n_:=n<->#&/@(s[[Sequence@@#]]&/@(Position[s,n][[1]]/.{r_,c_}:> 
Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1},{r+1,c-1}},{x_,y_}/;0<x<k&&0<y<k]));
k=If[EvenQ[z=\[LeftCeiling]Sqrt[Sort[{v1,v2}][[-1]]]\[RightCeiling]],z+1,z];
FindShortestPath[g=Graph[Sort/@Flatten[f[ns=w@k,#]&/@Union@Range[k^2]]],v1,v2]]

2

Scala(830バイト)

4つの相互に再帰的な関数を使用して、正方形の2D配列でスパイラルを構築します。パスリストを作成するための別の再帰検索。

def P(s:Int,e:Int):List[Int]={
import scala.math._
type G=Array[Array[Int]]
type I=Int
type T=(I,I)
def S(z:I)={def U(g:G,x:I,y:I,c:I,r:I):Unit={for(i<-0 to r.min(y)){g(y-i)(x)=c+i}
if(r<=y)R(g,x,y-r,c+r,r)}
def R(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x+i)=c+i}
D(g,x+r,y,c+r,r+1)}
def D(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y+i)(x)=c+i}
L(g,x,y+r,c+r,r)}
def L(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x-i)=c+i}
U(g,x-r,y,c+r,r+1)}
val g=Array.ofDim[I](z,z)
U(g,z/2,z/2,1,1)
g}
def C(n:I,g:G):T={var(x,y)=(0,0)
for(i<-g.indices){val j=g(i).indexOf(n)
if(j>=0){x=j
y=i}}
(x,y)}
def N(n:Int)=if(n==0)0 else if(n<0)-1 else 1
def Q(a:T,b:T):List[T]={val u=N(b._1-a._1)
val v=N(b._2-a._2)
if(u==0&&v==0)b::Nil else a::Q((a._1+u,a._2+v),b)}
val z=ceil(sqrt(max(s,e))).toInt|1
val p=S(z)
Q(C(s,p),C(e,p)).map{case(x,y)=>p(y)(x)}}

未ゴルフ

  import scala.math._
  type Grid=Array[Array[Int]]
  def spiral(size: Int) = {
    def up(grid:Grid, x: Int, y: Int, c: Int, r: Int): Unit = {
      for (i <- 0 to r.min(y)) {
        grid(y-i)(x) = c + i
      }
      if (r <= y)
        right(grid,x,y-r,c+r,r)
    }
    def right(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x+i) = c + i
      }
      down(grid,x+r,y,c+r,r+1)
    }
    def down(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y+i)(x) = c + i
      }
      left(grid,x,y+r,c+r,r)
    }
    def left(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x-i) = c + i
      }
      up(grid,x-r,y,c+r,r+1)
    }
    val grid = Array.ofDim[Int](size,size)
    up(grid,size/2,size/2,1,1)
    grid
  }
  def findPath(start: Int, end: Int): List[Int] = {
    def findCoords(n: Int, grid: Grid): (Int, Int) = {
      var (x,y)=(0,0)
      for (i <- grid.indices) {
        val j = grid(i).indexOf(n)
        if (j >= 0) {
          x = j
          y = i
        }
      }
      (x,y)
    }
    def sign(n: Int) = if (n == 0) 0 else if (n < 0) -1 else 1
    def path(stc: (Int, Int), enc: (Int, Int)) : List[(Int, Int)] = {
      val dx = sign(enc._1 - stc._1)
      val dy = sign(enc._2 - stc._2)
      if (dx == 0 && dy == 0) {
        enc :: Nil
      } else {
        stc :: path((stc._1 + dx, stc._2 + dy), enc)
      }
    }
    val size = ceil(sqrt(max(start, end))).toInt | 1
    val spir = spiral(size)
    path(findCoords(start, spir),findCoords(end, spir)).
      map { case (x, y) => spir(y)(x) }
  }

2

ルビー、262 218 216バイト

これは私のPythonの答えのポートです。ゴルフの提案を歓迎します。

編集: 45は、ヨルダンとの彼らの提案のおかげでバイトd=[0]*n=m*m;*e=c=0;*t=a.rect0<=>xx,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]。別のバイト(x+y*1i)(x+y.i)

->a,b{m=([a,b].max**0.5).to_i+1;d=[0]*n=m*m;*e=c=0;*t=a
n.times{|k|d[c.real*m+c.imag]=k+1;e<<c;c+=1i**((4*k+1)**0.5-1).to_i}
x,y=(e[a]-g=e[b]).rect
(x+=0<=>x;y+=0<=>y;t<<d[(g.real+x)*m+g.imag+y])while(x+y.i).abs>0
t}

非ゴルフ:

def q(a,b)
  m = ([a,b].max**0.5).to_i+1
  n = m*m
  d = [0]*n
  c = 0
  *e = c   # same as e=[0]
  *t = a   # same as t=[a]

  (1..n).each do |k|
    d[c.real * m + c.imag] = k+1
    e << c
    c += 1i**((4*k+1)**0.5-1).to_i
  end

  x, y = (e[a] - g=e[b]).rect

  while (x+y.i).abs > 0 do
    if x<0
      x += 1
    elsif x>0
      x += -1
    end

    if y<0
      y += 1
    elsif y>0
      y -= 1
    end

    t << d[(g.real+x)*m+g.imag+y]
  end

  return t
end

q=バイトをカウントしていないので、回答からを削除する必要があります。c=0;e=[c];t=[a]に短縮できます*e=c=0;*t=a。交換できますz=e[a]-e[b];x,y=z.real,z.imagx,y=(e[a]-e[b]).rectx+=x<0?1:x>0?-1:0でられx+=0<=>x(と同じy)。私はそれを229バイトに減らすと思います。
ジョーダン

1次元配列に切り替えると、さらに6バイトを節約できます。の初期化dd=[0]*m*m、その後、交換するd[c.real][c.imag]d[c.real*m+c.imag]してd[e[b].real+x][e[b].imag+y]d[(e[b].real+x)*m+e[b].imag+y]
ジョーダン

以前のコメントより2バイト改善:t<<d[(e[b].real+x)*m+e[b].imag+y]に短縮できますu,v=e[b].rect;t<<d[(u+x)*m+v+y]
ジョーダン

およびに変更d=[0]*m*mすることにより、さらに2バイト。それは219です。– d=[0]*n=m*m(m*m).timesn.times
ジョーダン

あなたは、変更することにより、二つの追加のバイトを保存することができますx,y=(e[a]-e[b]).rectx,y=(e[a]-g=e[b]).rect、削除、u,v=e[b].rectおよび変更t<<d[(u+x)*m+v+y]t<<d[(g.real+x)*g.imag+v+y](基本的には私の最後から2番目のコメントを元に戻します)。
ジョーダン

1

Python 3、316バイト

この答えは、の座標を見てab(複素数を使用して)スパイラルにして最初の対角線移動し、その後、直交移動を追加します。

def q(a,b):
 m=int(max(a,b)**.5)+1;d=[];c=0;e=[c];t=[a]
 for i in range(m):d+=[[0]*m]
 for k in range(m*m):d[int(c.real)][int(c.imag)]=k+1;e+=[c];c+=1j**int((4*k+1)**.5-1)
 z=e[a]-e[b];x,y=int(z.real),int(z.imag)
 while abs(x+y*1j):x+=(x<0)^-(x>0);y+=(y<0)^-(y>0);t+=[d[int(e[b].real)+x][int(e[b].imag)+y]]
 return t

非ゴルフ:

def queen_spiral(a,b):
    square_size = int(max(a,b)**.5)+1
    complex_to_spiral = []
    complex = 0
    spiral_to_complex = [c] # add 0 first, so that it's 1-indexed later
    result = [a]

    for i in range(square_size):
        complex_to_spiral.append([0]*square_size) # the rows of the spiral

    for k in range(square_size**2):
        row = int(complex.real)
        column = int(complex.imag)
        complex_to_spiral[row][column] = k+1 # 1-indexing

        spiral_to_complex.append(complex)

        quarter_turns = int((4*k+1)**.5-1)
        complex += 1j**quarter_turns

    z = spiral_to_complex[a] - spiral_to_complex[b]
    v = spiral_to_complex[b]
    x, y = int(z.real), int(z.imag)
    r, s = int(v.real), int(v.imag)

    while abs(x+y*1j):
        if x < 0:
            x += 1
        elif x > 0:
            x += -1
        # else x == 0, do nothing
        if y < 0:
            y += 1
        elif y > 0:
            y += -1

        vertex = complex_to_spiral[r+x][s+y]
        result.append(vertex)
    return result
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.