Spacer królowej po spirali

13

W dalekim królestwie królowa szachów codziennie spaceruje po spiralnej ścieżce, ponumerowanej od 1 do n, nie dbając o samą spiralę, ale po prostu wykonując ruchy królowej, tak jak na szachownicy. Królowa jest ukochana przez swoich poddanych i odnotowują każdy kwadrat, który odwiedza na swojej drodze. Biorąc pod uwagę, że królowa może rozpocząć swój spacer na dowolnym kwadracie, a kończy go na dowolnym kwadracie, jaki jest najkrótszy spacer królowej?

Wyzwanie

Biorąc pod uwagę spiralę liczb całkowitych na prostokątnej siatce, napisz funkcję, która zwraca jedną z najkrótszych możliwych ścieżek (liczoną przez liczbę przejechanych komórek) między dwiema liczbami na tej spiralnej siatce, używając ruchów szachowej królowej.

Na przykład od 16do 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

Niektóre możliwe ścieżki obejmują 16, 4, 2, 10, 25i 16, 5, 1, 9, 25.

Zasady

  • Dane wejściowe będą stanowić dowolne dwie dodatnie liczby całkowite.
  • Dane wyjściowe będą ścieżką liczb całkowitych (w tym obu punktów końcowych) w poprzek spirali przy użyciu tylko ruchów ortogonalnych i ukośnych.
  • Długość ścieżki jest liczona przez liczbę przejechanych komórek.
  • Twoja odpowiedź może być programem lub funkcją.
  • To jest kod golfowy, więc wygrywa najmniejsza liczba bajtów.

Jak zawsze, jeśli problem jest niejasny, daj mi znać. Powodzenia i dobrej gry w golfa!

Przypadki testowe

>>> 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
źródło
Związane .
Leaky Nun
5
Możesz wspomnieć, że szukasz najkrótszej ścieżki według liczby przebytych komórek (na przykład w przeciwieństwie do odległości euklidesowej).
Martin Ender
1
Czy nie miałoby to większego sensu jako „spacer króla”?
Jo King
1
@JoKing Ach, skoro już o tym wspominasz, powinien to być królewski spacer. Jednak zmiana tytułu może być trochę za późna.
Sherlock9

Odpowiedzi:

5

APL (Dyalog Unicode) , 59 57 bajtów SBCS

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

Wypróbuj online!

-2 bajty dzięki @ngn.

Anonimowa funkcja, która akceptuje dwa punkty końcowe jako lewy i prawy argument.

Niegolfowane i jak to działa

Królowa najpierw porusza się po przekątnej, więc wystarczy wstępnie obliczyć współrzędne każdej liczby do max(start,end).

Algorytm generujący współrzędne jest inspirowany kilkoma odpowiedziami na powiązane wyzwanie , ale nieco różni się od żadnej z istniejących odpowiedzi:

  • Biorąc pod uwagę niezbędną granicę 10
  • Wygeneruj zakres 1 r=1 2 3 4 5 6 7 8 9 10
  • Weź pułap połowy każdej liczby n=1 1 2 2 3 3 4 4 5 5
  • Replikuj każdy element rwedług 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
  • Weź łączną sumę mocy wyimaginowanej jednostki, zaczynając od 0. (ta część jest wspólna dla różnych rozwiązań Pythona dla połączonego wyzwania)

Następnie, gdy wektor współrzędnych vjest gotowy, możemy łatwo przekonwertować między indeksem spiralnym a współrzędnymi za pomocą v[i]i v⍳coord(znalezienie pierwszego indeksu 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
źródło
(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
ngn
(⍺⌷v)->v[⍺]
ngn
3

Mathematica 615 530 bajtów

To konstruuje siatkę liczb, przekształca ją w wykres, a następnie znajduje najkrótszą ścieżkę między dwoma wprowadzonymi liczbami.


UnGolfed

numberSpiralpochodzi z Mathworld Prime Spiral . Tworzy spiralę Ulam n od n (bez podświetlania liczb pierwszych).

findPathkonwertuje siatkę liczb na wykres. Krawędzie są prawidłowymi ruchami królowej na siatce liczb.


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

Przykłady

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

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

krata


Najkrótsza ścieżka od 80 do 1 zawiera 5, a nie 6 wierzchołków.

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

{80, 48, 24, 8, 1}

osiemdziesiąt jeden siatka


Grał w golfa

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
źródło
2

Scala (830 bajtów)

Tworzy spiralę w kwadratowej macierzy 2D za pomocą czterech wzajemnie rekurencyjnych funkcji. Kolejne wyszukiwanie rekurencyjne w celu zbudowania listy ścieżek.

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

Nie golfił

  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
źródło
2

Rubinowy, 262 218 216 bajtów

To jest port mojej odpowiedzi w Pythonie . Sugestie dotyczące gry w golfa mile widziane.

Edit: 45 bajty dzięki Jordana i ich sugestie d=[0]*n=m*m;*e=c=0;*t=a, .rect, 0<=>xi x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]. Kolejny bajt od (x+y*1i)do (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}

Nie golfowany:

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
źródło
Powinieneś usunąć q=z odpowiedzi, ponieważ nie liczysz jej bajtów. c=0;e=[c];t=[a]można skrócić do *e=c=0;*t=a. Można wymienić z=e[a]-e[b];x,y=z.real,z.imagz x,y=(e[a]-e[b]).recti x+=x<0?1:x>0?-1:0z x+=0<=>x(samo dla y). Myślę, że to sprowadza się do 229 bajtów.
Jordan
Po przejściu na tablicę jednowymiarową możesz zapisać 6 dodatkowych bajtów. Wymień inicjalizacji dz d=[0]*m*m, a następnie zastąpić d[c.real][c.imag]z d[c.real*m+c.imag]i d[e[b].real+x][e[b].imag+y]z d[(e[b].real+x)*m+e[b].imag+y].
Jordan
2-bajtowa poprawa w stosunku do mojego poprzedniego komentarza: t<<d[(e[b].real+x)*m+e[b].imag+y]można ją skrócić u,v=e[b].rect;t<<d[(u+x)*m+v+y].
Jordan
Dwa kolejne bajty, zmieniając d=[0]*m*mna d=[0]*n=m*mi (m*m).timesna n.times. To 219.
Jordan
Możesz zapisać dwa dodatkowe bajty, zmieniając x,y=(e[a]-e[b]).rectna x,y=(e[a]-g=e[b]).rect, usuwając u,v=e[b].recti zmieniając t<<d[(u+x)*m+v+y]na t<<d[(g.real+x)*g.imag+v+y](w zasadzie cofam mój komentarz od drugiego do ostatniego).
Jordan
1

Python 3, 316 bajtów

Ta odpowiedź analizuje współrzędne ai bna spirali (używając liczb zespolonych) i dodaje najpierw ruchy ukośne, a następnie ruchy ortogonalne.

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

Nie golfowany:

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
źródło