Seorang ratu berjalan melintasi spiral


13

Di kerajaan yang jauh, seorang ratu catur berjalan-jalan setiap hari melintasi jalan spiral, dinomori dari 1 hingga n, tidak peduli untuk mengikuti spiral itu sendiri, tetapi hanya membuat gerakan ratu seperti yang ia lakukan di papan catur. Sang ratu dicintai oleh rakyatnya, dan mereka membuat catatan setiap kotak yang dia kunjungi di jalannya. Mengingat bahwa sang ratu dapat memulai perjalanannya di alun-alun mana saja dan mengakhirinya di alun-alun mana saja, apa jalan ratu terpendek yang bisa dia ambil?

Tantangan

Diberikan spiral bilangan bulat pada kotak persegi panjang, tulis fungsi yang mengembalikan salah satu jalur terpendek yang mungkin (dihitung berdasarkan jumlah sel yang ditempuh) antara dua angka pada grid spiral ini menggunakan gerakan ratu catur.

Misalnya, dari 16ke 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

Beberapa jalur yang mungkin termasuk 16, 4, 2, 10, 25dan 16, 5, 1, 9, 25.

Aturan

  • Input akan berupa dua bilangan bulat positif.
  • Outputnya akan berupa jalur bilangan bulat (termasuk kedua titik akhir) melintasi spiral hanya menggunakan gerakan ortogonal dan diagonal.
  • Panjang jalan dihitung oleh jumlah sel yang ditempuh.
  • Jawaban Anda mungkin sebuah program atau fungsi.
  • Ini adalah kode golf, sehingga jumlah byte terkecil menang.

Seperti biasa, jika masalahnya tidak jelas, beri tahu saya. Semoga berhasil dan bermain golf dengan baik!

Uji kasus

>>> 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
Anda mungkin ingin menyebutkan bahwa Anda mencari jalur terpendek berdasarkan jumlah sel yang ditempuh (berbeda dengan jarak Euclidian, katakanlah).
Martin Ender

1
Bukankah ini lebih masuk akal sebagai "jalan raja"?
Jo King

1
@JoKing Ah, sekarang Anda menyebutkannya, itu harus berjalan kaki seorang raja. Namun mungkin agak terlambat untuk mengubah judul.
Sherlock9

Jawaban:


5

APL (Dyalog Unicode) , 59 57 byte SBCS

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

Cobalah online!

-2 byte terima kasih kepada @ngn.

Fungsi anonim yang menerima dua titik akhir sebagai argumen kiri dan kanan.

Tidak dikelompokkan & cara kerjanya

Sang ratu bergerak secara diagonal terlebih dahulu, sehingga cukup untuk melakukan pra-perhitungan koordinat setiap angka hingga max(start,end).

Algoritma penghasil koordinat terinspirasi dari beberapa jawaban pada tantangan terkait , tetapi sedikit berbeda dari salah satu jawaban yang ada:

  • Diberi batasan 10
  • Hasilkan kisaran 1-based r=1 2 3 4 5 6 7 8 9 10
  • Ambil plafon setengah dari setiap angka n=1 1 2 2 3 3 4 4 5 5
  • Gandakan setiap item roleh 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
  • Ambil jumlah kumulatif kekuatan unit imajiner, dengan titik awal 0. (bagian ini umum untuk berbagai solusi Python untuk tantangan terkait)

Kemudian, setelah vektor koordinat vsiap, kita dapat dengan mudah mengkonversi antara indeks spiral dan koordinat menggunakan v[i]dan v⍳coord(menemukan indeks pertama coordin 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 byte

Ini membangun kisi angka, mengubahnya menjadi grafik, dan kemudian menemukan jalur terpendek antara dua angka yang dimasukkan.


Tidak disatukan

numberSpiraladalah dari Mathworld Prime Spiral . Ini menciptakan n oleh n Ulam Spiral (tanpa menyoroti bilangan prima).

findPathmengubah grid angka menjadi grafik. Tepi adalah gerakan ratu yang valid pada kisi angka.


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]]

Contohnya

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

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

kisi


Jalur terpendek dari 80 ke 1 berisi 5, bukan 6, simpul.

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

{80, 48, 24, 8, 1}

delapan puluh satu kotak


Golf

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 bytes)

Membangun spiral dalam array 2D persegi menggunakan empat fungsi rekursif yang saling menguntungkan. Pencarian rekursif lain untuk membangun daftar jalur.

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)}}

Tidak disatukan

  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

Ruby, 262 218 216 byte

Ini adalah port jawaban Python saya . Saran bermain golf diterima.

Edit: 45 byte berkat Yordania dan saran mereka d=[0]*n=m*m;*e=c=0;*t=a, .rect, 0<=>xdan x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]. Byte lain dari (x+y*1i)ke (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}

Tidak Disatukan:

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

Anda harus menghapus q=dari jawaban Anda karena Anda tidak menghitung byte-nya. c=0;e=[c];t=[a]dapat disingkat menjadi *e=c=0;*t=a. Anda dapat mengganti z=e[a]-e[b];x,y=z.real,z.imagdengan x,y=(e[a]-e[b]).rectdan x+=x<0?1:x>0?-1:0dengan x+=0<=>x(sama untuk y). Saya pikir itu akan turun ke 229 byte.
Jordan

Jika Anda beralih ke larik 1 dimensi, Anda dapat menyimpan 6 byte lebih banyak. Ganti inisialisasi ddengan d=[0]*m*m, lalu ganti d[c.real][c.imag]dengan d[c.real*m+c.imag]dan d[e[b].real+x][e[b].imag+y]dengan d[(e[b].real+x)*m+e[b].imag+y].
Jordan

Peningkatan 2 byte dari komentar saya sebelumnya: t<<d[(e[b].real+x)*m+e[b].imag+y]dapat disingkat menjadi u,v=e[b].rect;t<<d[(u+x)*m+v+y].
Jordan

Dua byte lagi dengan mengubah d=[0]*m*mke d=[0]*n=m*mdan (m*m).timeske n.times. Itu 219.
Jordan

Anda dapat menyimpan dua byte tambahan dengan mengubah x,y=(e[a]-e[b]).rectke x,y=(e[a]-g=e[b]).rect, menghapus u,v=e[b].rectdan mengubah t<<d[(u+x)*m+v+y]ke t<<d[(g.real+x)*g.imag+v+y](pada dasarnya mengembalikan saya kedua-untuk-terakhir komentar).
Jordan

1

Python 3, 316 byte

Jawaban ini melihat koordinat dari adan bpada spiral (menggunakan bilangan kompleks) dan menambahkan gerakan diagonal terlebih dahulu, kemudian bergerak ortogonal.

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

Tidak Disatukan:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.