Una passeggiata della regina attraverso una spirale


13

In un regno lontano, una regina degli scacchi fa una passeggiata quotidiana attraverso un percorso a spirale, numerato da 1 a n, non preoccupandosi di seguire la spirale stessa, ma semplicemente facendo le mosse della regina come farebbe su una scacchiera. La regina è amata dai suoi sudditi e prendono nota di ogni piazza che visita sul suo cammino. Dato che la regina può iniziare la sua passeggiata in qualsiasi piazza e finirla in qualsiasi piazza, qual è la passeggiata della regina più breve che può fare?

La sfida

Data una spirale di numeri interi su una griglia rettangolare, scrivi una funzione che restituisca uno dei percorsi più brevi possibili (contati dal numero di celle percorse) tra due numeri su questa griglia a spirale usando le mosse di una regina degli scacchi.

Ad esempio, da 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

Alcuni possibili percorsi includono 16, 4, 2, 10, 25e 16, 5, 1, 9, 25.

Regole

  • L'input sarà due numeri interi positivi.
  • L'output sarà un percorso di numeri interi (inclusi entrambi gli endpoint) attraverso la spirale usando solo mosse ortogonali e diagonali.
  • La lunghezza di un percorso viene contata dal numero di celle percorse.
  • La tua risposta potrebbe essere un programma o una funzione.
  • Questo è il codice golf, quindi vince il minor numero di byte.

Come sempre, se il problema non è chiaro, per favore fatemi sapere. Buona fortuna e buon golf!

Casi test

>>> 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
Potresti menzionare che stai cercando il percorso più breve per numero di celle percorse (al contrario della distanza euclidea, diciamo).
Martin Ender

1
Non avrebbe più senso una "passeggiata del re"?
Jo King,

1
@JoKing Ah, ora che me lo dici, dovrebbe essere una passeggiata da re. Tuttavia, potrebbe essere un po 'tardi per cambiare il titolo.
Sherlock9,

Risposte:


5

APL (Dyalog Unicode) , 59 57 byte SBCS

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

Provalo online!

-2 byte grazie a @ngn.

Funzione anonima che accetta due endpoint come argomenti sinistro e destro.

Ungolfed e come funziona

La regina si sposta per prima in diagonale, quindi è sufficiente pre-calcolare le coordinate di ciascun numero fino a max(start,end).

L'algoritmo di generazione delle coordinate si ispira a diverse risposte sulla sfida correlata , ma è leggermente diverso da qualsiasi delle risposte esistenti:

  • Dato il limite necessario di 10
  • Genera l'intervallo basato su 1 r=1 2 3 4 5 6 7 8 9 10
  • Prendi il soffitto della metà di ogni numero n=1 1 2 2 3 3 4 4 5 5
  • Replicare ogni elemento di 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
  • Prendi la somma cumulativa del potere dell'unità immaginaria, con un punto iniziale di 0. (questa parte è comune a varie soluzioni Python alla sfida collegata)

Quindi, una volta che il vettore di coordinate vè pronto, possiamo facilmente convertire tra l'indice a spirale e le coordinate usando v[i]e v⍳coord(trovando il primo indice di 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

Ciò costruisce una griglia numerica, la converte in un grafico e quindi trova un percorso più breve tra i due numeri immessi.


UnGolfed

numberSpiralè di Mathworld Prime Spiral . Crea una spirale Ulam (senza evidenziare i numeri primi).

findPathconverte la griglia numerica in un grafico. I bordi sono mosse regina valide sulla griglia numerica.


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

Esempi

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

{4,5}

{} 13,3,1,7,22

{} 16,4,1,9,25

griglia


Il percorso più breve da 80 a 1 contiene 5, non 6 vertici.

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

{80, 48, 24, 8, 1}

ottantuno griglia


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

2

Scala (830 byte)

Costruisce la spirale in un array 2D quadrato utilizzando quattro funzioni reciprocamente ricorsive. Un'altra ricerca ricorsiva per creare l'elenco dei percorsi.

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

2

Rubino, 262 218 216 byte

Questa è una porta della mia risposta Python . Suggerimenti di golf benvenuti.

Edit: 45 byte grazie alla Jordan ed i loro suggerimenti di d=[0]*n=m*m;*e=c=0;*t=a, .rect, 0<=>xe x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]. Un altro byte da (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}

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

Dovresti rimuovere il q=dalla tua risposta poiché non stai contando i suoi byte. c=0;e=[c];t=[a]può essere abbreviato in *e=c=0;*t=a. È possibile sostituire z=e[a]-e[b];x,y=z.real,z.imagcon x,y=(e[a]-e[b]).recte x+=x<0?1:x>0?-1:0con x+=0<=>x(lo stesso per y). Penso che arriva a 229 byte.
Giordania,

Se si passa a un array monodimensionale è possibile salvare altri 6 byte. Sostituire l'inizializzazione di dcon d=[0]*m*m, quindi sostituire d[c.real][c.imag]con d[c.real*m+c.imag]e d[e[b].real+x][e[b].imag+y]con d[(e[b].real+x)*m+e[b].imag+y].
Giordania,

Un miglioramento di 2 byte rispetto al mio commento precedente: t<<d[(e[b].real+x)*m+e[b].imag+y]può essere abbreviato in u,v=e[b].rect;t<<d[(u+x)*m+v+y].
Giordania,

Altri due byte cambiando d=[0]*m*min d=[0]*n=m*me (m*m).timesin n.times. Sono il 219.
Giordania,

È possibile salvare due byte aggiuntivi cambiando x,y=(e[a]-e[b]).rectin x,y=(e[a]-g=e[b]).rect, eliminando u,v=e[b].recte cambiando t<<d[(u+x)*m+v+y]in t<<d[(g.real+x)*g.imag+v+y](sostanzialmente ripristinando il mio penultimo commento).
Giordania,

1

Python 3, 316 byte

Questa risposta esamina le coordinate di ae bsulla spirale (usando numeri complessi) e aggiunge prima i movimenti diagonali, quindi i movimenti ortogonali.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.