El paseo de una reina a través de una espiral.

13

En un reino lejano, una reina del ajedrez da un paseo diario a través de un camino en espiral, numerado del 1 al n, sin preocuparse por seguir la espiral en sí, sino simplemente haciendo los movimientos de la reina como lo haría en un tablero de ajedrez. La reina es amada por sus súbditos, y toman nota de cada cuadro que visita en su camino. Dado que la reina puede comenzar su caminata en cualquier casilla y terminarla en cualquier casilla, ¿cuál es la caminata más corta que puede dar la reina?

El reto

Dada una espiral de enteros en una cuadrícula rectangular, escriba una función que devuelva uno de los caminos más cortos posibles (contados por el número de celdas recorridas) entre dos números en esta cuadrícula espiral usando los movimientos de una reina de ajedrez.

Por ejemplo, de 16a 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

Algunos caminos posibles incluyen 16, 4, 2, 10, 25y 16, 5, 1, 9, 25.

Reglas

  • La entrada será dos enteros positivos.
  • La salida será una ruta de enteros (incluidos ambos puntos finales) a través de la espiral utilizando solo movimientos ortogonales y diagonales.
  • La longitud de una ruta se cuenta por el número de celdas recorridas.
  • Su respuesta puede ser un programa o una función.
  • Este es el código de golf, por lo que gana el menor número de bytes.

Como siempre, si el problema no está claro, hágamelo saber. ¡Buena suerte y buen golf!

Casos de prueba

>>> 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
fuente
Relacionados .
Leaky Nun
55
Es posible que desee mencionar que está buscando el camino más corto por número de celdas recorridas (en oposición a la distancia euclidiana, por ejemplo).
Martin Ender
1
¿No tendría esto más sentido como un "paseo del rey"?
Jo King
1
@JoKing Ah, ahora que lo mencionas, debería ser la caminata de un rey. Sin embargo, podría ser un poco tarde para cambiar el título.
Sherlock9

Respuestas:

5

APL (Dyalog Unicode) , 59 57 bytes SBCS

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

Pruébalo en línea!

-2 bytes gracias a @ngn.

Función anónima que acepta dos puntos finales como argumentos izquierdo y derecho.

Ungolfed y cómo funciona

La reina se mueve diagonalmente primero, por lo que es suficiente calcular previamente las coordenadas de cada número hasta max(start,end).

El algoritmo de generación de coordenadas se inspira en varias respuestas sobre el desafío relacionado , pero es ligeramente diferente de cualquiera de las respuestas existentes:

  • Dado el límite necesario de 10
  • Generar el rango basado en 1 r=1 2 3 4 5 6 7 8 9 10
  • Toma el techo de la mitad de cada número n=1 1 2 2 3 3 4 4 5 5
  • Replicar cada elemento de 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
  • Tome la suma acumulativa de potencia de la unidad imaginaria, con un punto de partida de 0. (esta parte es común a varias soluciones de Python para el desafío vinculado)

Luego, una vez que el vector de coordenadas vestá listo, podemos convertir fácilmente entre el índice espiral y las coordenadas usando v[i]y v⍳coord(encontrar el primer índice de 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)
}
Bubbler
fuente
(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
NGN
(⍺⌷v)->v[⍺]
NGN
3

Mathematica 615530 bytes

Esto construye una cuadrícula de números, la convierte en un gráfico y luego encuentra una ruta más corta entre los dos números que se ingresaron.


Sin golf

numberSpirales de Mathworld Prime Spiral . Crea una espiral de n por n Ulam (sin resaltar los números primos).

findPathconvierte la cuadrícula de números en un gráfico. Los bordes son movimientos de reina válidos en la cuadrícula de números.


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

Ejemplos

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

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

cuadrícula


El camino más corto de 80 a 1 contiene 5, no 6, vértices.

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

{80, 48, 24, 8, 1}

ochenta y una cuadrícula


Golfed

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
fuente
2

Scala (830 bytes)

Construye la espiral en una matriz cuadrada en 2D usando cuatro funciones recursivas mutuamente. Otra búsqueda recursiva para construir la lista de rutas.

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

Sin golf

  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
fuente
2

Rubí, 262 218 216 bytes

Este es un puerto de mi respuesta de Python . Sugerencias de golf bienvenidas.

Editar: 45 bytes gracias a Jordan y sus sugerencias de d=[0]*n=m*m;*e=c=0;*t=a, .rect, 0<=>xy x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]. Otro byte de (x+y*1i)a (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}

Sin golf:

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
fuente
Debe eliminar el q=de su respuesta ya que no cuenta sus bytes. c=0;e=[c];t=[a]se puede acortar a *e=c=0;*t=a. Puede reemplazar z=e[a]-e[b];x,y=z.real,z.imagcon x,y=(e[a]-e[b]).recty x+=x<0?1:x>0?-1:0con x+=0<=>x(lo mismo para y). Creo que eso lo reduce a 229 bytes.
Jordania
Si cambia a una matriz unidimensional, puede guardar 6 bytes más. Reemplace la inicialización de dcon d=[0]*m*m, luego reemplace d[c.real][c.imag]con d[c.real*m+c.imag]y d[e[b].real+x][e[b].imag+y]con d[(e[b].real+x)*m+e[b].imag+y].
Jordania
Una mejora de 2 bytes sobre mi comentario anterior: t<<d[(e[b].real+x)*m+e[b].imag+y]se puede acortar a u,v=e[b].rect;t<<d[(u+x)*m+v+y].
Jordania
Dos bytes más cambiando d=[0]*m*ma d=[0]*n=m*my (m*m).timespara n.times. Eso es 219.
Jordania
Puede guardar dos bytes adicionales cambiando x,y=(e[a]-e[b]).recta x,y=(e[a]-g=e[b]).rect, borrando u,v=e[b].recty cambiando t<<d[(u+x)*m+v+y]a t<<d[(g.real+x)*g.imag+v+y](básicamente revertir mi penúltimo comentario).
Jordania
1

Python 3, 316 bytes

Esta respuesta mira las coordenadas de ay ben la espiral (usando números complejos) y agrega los movimientos diagonales primero, luego los movimientos ortogonales.

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

Sin golf:

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
fuente