Eine Königin geht über eine Spirale

13

In einem fernen Königreich macht eine Schachkönigin täglich einen Spaziergang über einen von 1 bis 1 nummerierten nSpiralpfad, ohne sich darum zu kümmern, der Spirale selbst zu folgen, sondern einfach die Bewegungen der Königin wie auf einem Schachbrett auszuführen. Die Königin wird von ihren Untertanen geliebt, und sie notieren sich jedes Feld, das sie auf ihrem Weg besucht. Was ist der kürzeste Spaziergang der Königin, den sie machen kann, wenn die Königin ihren Spaziergang auf einem beliebigen Feld beginnen und auf einem beliebigen Feld beenden kann?

Die Herausforderung

Schreiben Sie bei einer gegebenen Spirale von ganzen Zahlen in einem rechteckigen Gitter eine Funktion, die einen der kürzesten möglichen Pfade (gezählt nach der Anzahl der zurückgelegten Zellen) zwischen zwei Zahlen in diesem Spiralgitter mit den Zügen einer Schachkönigin zurückgibt .

Zum Beispiel von 16bis 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

Einige mögliche Pfade umfassen 16, 4, 2, 10, 25und 16, 5, 1, 9, 25.

Regeln

  • Die Eingabe besteht aus zwei beliebigen positiven ganzen Zahlen.
  • Die Ausgabe ist ein Pfad von ganzen Zahlen (einschließlich beider Endpunkte) über die Spirale, wobei nur orthogonale und diagonale Bewegungen verwendet werden.
  • Die Länge eines Pfades wird durch die Anzahl der zurückgelegten Zellen gezählt.
  • Ihre Antwort kann ein Programm oder eine Funktion sein.
  • Dies ist Code Golf, also gewinnt die kleinste Anzahl von Bytes.

Wie immer, wenn das Problem unklar ist, lassen Sie es mich bitte wissen. Viel Glück und gutes Golfen!

Testfälle

>>> 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
Sherlock9
quelle
Verwandte .
Undichte Nonne
5
Vielleicht möchten Sie erwähnen, dass Sie nach dem kürzesten Weg nach Anzahl der zurückgelegten Zellen suchen (im Gegensatz beispielsweise zur euklidischen Entfernung).
Martin Ender
1
Wäre das nicht sinnvoller als ein "Königsspaziergang"?
Jo King
1
@JoKing Ah, jetzt wo du es sagst, sollte es ein Königsweg sein. Es könnte jedoch etwas spät sein, den Titel zu ändern.
Sherlock9

Antworten:

5

APL (Dyalog Unicode) , 59 57 Byte SBCS

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

Probieren Sie es online aus!

-2 Bytes dank @ngn.

Anonyme Funktion, die zwei Endpunkte als linkes und rechtes Argument akzeptiert.

Ungolfed & wie es funktioniert

Die Königin bewegt sich zuerst diagonal, so dass es ausreicht, die Koordinaten jeder Zahl bis zu vorab zu berechnen max(start,end).

Der Koordinatengenerierungsalgorithmus ist von mehreren Antworten auf die damit verbundene Herausforderung inspiriert , unterscheidet sich jedoch geringfügig von den vorhandenen Antworten:

  • Angesichts der notwendigen Grenze von 10
  • Generieren Sie den 1-basierten Bereich r=1 2 3 4 5 6 7 8 9 10
  • Nehmen Sie die Decke der Hälfte jeder Zahl n=1 1 2 2 3 3 4 4 5 5
  • Replizieren Sie jeden Artikel von 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
  • Nehmen Sie die kumulative Summe der Potenzen der imaginären Einheit mit dem Startpunkt 0. (Dieser Teil ist verschiedenen Python-Lösungen für die verknüpfte Herausforderung gemeinsam.)

Sobald der Koordinatenvektor vfertig ist, können wir mit v[i]und v⍳coord(Finden des ersten Index von coordin v) leicht zwischen dem Spiralindex und den Koordinaten konvertieren .

 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)
}
Bubbler
quelle
(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
ngn
(⍺⌷v)->v[⍺]
ngn
3

Mathematica 615 530 Bytes

Dadurch wird ein Zahlenraster erstellt, in ein Diagramm konvertiert und dann ein kürzester Pfad zwischen den beiden eingegebenen Zahlen gefunden.


UnGolfed

numberSpiralist von Mathworld Prime Spiral . Es wird eine n mal n Ulam-Spirale erzeugt (ohne die Primzahlen hervorzuheben).

findPathkonvertiert das Zahlenraster in ein Diagramm. Kanten sind gültige Königinbewegungen im Zahlenraster.


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

Beispiele

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

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

Gitter


Der kürzeste Weg von 80 nach 1 enthält 5, nicht 6 Eckpunkte.

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

{80, 48, 24, 8, 1}

einundachtzig Gitter


Golf gespielt

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]]
DavidC
quelle
2

Scala (830 Bytes)

Erstellt die Spirale in einem quadratischen 2D-Array mit vier gegenseitig rekursiven Funktionen. Eine weitere rekursive Suche zum Erstellen der Pfadliste.

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

Ungolfed

  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) }
  }
Tim Robbins
quelle
2

Ruby, 262 218 216 Bytes

Dies ist eine Portierung meiner Python-Antwort . Golfvorschläge willkommen.

Edit: 45 Bytes dank Jordan und ihre Vorschläge d=[0]*n=m*m;*e=c=0;*t=a, .rect, 0<=>xund x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]. Ein weiteres Byte von (x+y*1i)bis (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}

Ungolfed:

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
Sherlock9
quelle
Sie sollten das q=aus Ihrer Antwort entfernen , da Sie die Bytes nicht zählen. c=0;e=[c];t=[a]kann auf verkürzt werden *e=c=0;*t=a. Sie können z=e[a]-e[b];x,y=z.real,z.imagmit x,y=(e[a]-e[b]).rectund x+=x<0?1:x>0?-1:0mit ersetzen x+=0<=>x(gleich für y). Ich denke, das bringt es auf 229 Bytes.
Jordanien
Wenn Sie zu einem eindimensionalen Array wechseln, können Sie 6 weitere Bytes speichern. Ersetzen Sie die Initialisierung von dmit d=[0]*m*mund ersetzen Sie sie d[c.real][c.imag]durch d[c.real*m+c.imag]und d[e[b].real+x][e[b].imag+y]mit d[(e[b].real+x)*m+e[b].imag+y].
Jordanien
Eine 2-Byte-Verbesserung gegenüber meinem vorherigen Kommentar: t<<d[(e[b].real+x)*m+e[b].imag+y]kann auf verkürzt werden u,v=e[b].rect;t<<d[(u+x)*m+v+y].
Jordanien
Zwei weitere Bytes durch Ändern d=[0]*m*mvon d=[0]*n=m*mund (m*m).timeszu n.times. Das ist 219.
Jordan
Sie können durch Änderung von zwei zusätzlichen Bytes speichern x,y=(e[a]-e[b]).rectzu x,y=(e[a]-g=e[b]).rect, Löschen u,v=e[b].rectund Ändern t<<d[(u+x)*m+v+y]zu t<<d[(g.real+x)*g.imag+v+y](im Grunde zurückkehren meine zweite bis letzten Kommentar).
Jordanien
1

Python 3, 316 Bytes

Diese Antwort betrachtet die Koordinaten von aund bauf der Spirale (unter Verwendung komplexer Zahlen) und addiert zuerst die diagonalen Bewegungen und dann die orthogonalen Bewegungen.

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

Ungolfed:

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
Sherlock9
quelle